Commit 00ea0697 authored by Jason Kuo's avatar Jason Kuo Committed by Alexandre Julliard

wininet: Partially implement InternetSetFilePointer.

The function is implemented by setting the newly added contentPos that keep track of current read position in the content, when InternetReadFile related function is called, data will be read from req_file->file_handle before continuing reading from http stream. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26570
parent cf553129
......@@ -1293,6 +1293,7 @@ static const object_vtbl_t FTPFILEVtbl = {
NULL,
FTPFILE_QueryOption,
INET_SetOption,
NULL,
FTPFILE_ReadFile,
FTPFILE_WriteFile,
FTPFILE_QueryDataAvailable,
......@@ -2397,6 +2398,7 @@ static const object_vtbl_t FTPSESSIONVtbl = {
NULL,
NULL,
NULL,
NULL,
NULL
};
......@@ -3525,6 +3527,7 @@ static const object_vtbl_t FTPFINDNEXTVtbl = {
NULL,
NULL,
NULL,
NULL,
FTPFINDNEXT_FindNextFileW
};
......
......@@ -329,6 +329,7 @@ static void reset_data_stream(http_request_t *req)
destroy_data_stream(req->data_stream);
req->data_stream = &req->netconn_stream.data_stream;
req->read_pos = req->read_size = req->netconn_stream.content_read = 0;
req->content_pos = 0;
req->read_gzip = FALSE;
}
......@@ -2499,6 +2500,8 @@ static void create_cache_entry(http_request_t *req)
create_req_file(file_name, &req->req_file);
req->req_file->url = url;
req->content_pos = 0;
req->cache_size = 0;
req->hCacheFile = CreateFileW(file_name, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
......@@ -2512,7 +2515,9 @@ static void create_cache_entry(http_request_t *req)
DWORD written;
b = WriteFile(req->hCacheFile, req->read_buf+req->read_pos, req->read_size, &written, NULL);
if(!b)
if(b)
req->cache_size += written;
else
FIXME("WriteFile failed: %lu\n", GetLastError());
if(req->data_stream->vtbl->end_of_data(req->data_stream, req))
......@@ -2621,7 +2626,9 @@ static DWORD read_http_stream(http_request_t *req, BYTE *buf, DWORD size, DWORD
DWORD written;
bres = WriteFile(req->hCacheFile, buf, *read, &written, NULL);
if(!bres)
if(bres)
req->cache_size += written;
else
FIXME("WriteFile failed: %lu\n", GetLastError());
}
......@@ -3033,6 +3040,35 @@ static void HTTP_ReceiveRequestData(http_request_t *req)
send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, 0);
}
static DWORD read_req_file(http_request_t *req, BYTE *buffer, DWORD size, DWORD *read, BOOL allow_blocking)
{
DWORD ret_read = 0, res;
LARGE_INTEGER off;
BYTE buf[1024];
while (req->content_pos > req->cache_size) {
res = read_http_stream(req, (BYTE*)buf, min(sizeof(buf), req->content_pos - req->cache_size),
&ret_read, allow_blocking);
if (res != ERROR_SUCCESS)
return res;
if (!ret_read) {
*read = 0;
return ERROR_SUCCESS;
}
}
if (req->content_pos < req->cache_size) {
off.QuadPart = req->content_pos;
if (!SetFilePointerEx(req->req_file->file_handle, off, NULL, FILE_BEGIN))
return GetLastError();
if (!ReadFile(req->req_file->file_handle, buffer, size, &ret_read, NULL))
return GetLastError();
}
*read = ret_read;
return ERROR_SUCCESS;
}
/* read data from the http connection (the read section must be held) */
static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL allow_blocking)
{
......@@ -3046,13 +3082,16 @@ static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *
memcpy(buffer, req->read_buf+req->read_pos, ret_read);
req->read_size -= ret_read;
req->read_pos += ret_read;
req->content_pos += ret_read;
allow_blocking = FALSE;
}
if(ret_read < size) {
res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, &current_read, allow_blocking);
if(res == ERROR_SUCCESS)
if(res == ERROR_SUCCESS) {
ret_read += current_read;
req->content_pos += current_read;
}
else if(res == WSAEWOULDBLOCK && ret_read)
res = ERROR_SUCCESS;
}
......@@ -3106,6 +3145,17 @@ static void async_read_file_proc(task_header_t *hdr)
TRACE("req %p buf %p size %lu read_pos %lu ret_read %p\n", req, task->buf, task->size, task->read_pos, task->ret_read);
if(req->req_file && req->req_file->file_handle) {
DWORD ret, ret_read;
BYTE buf[1024];
while (req->content_pos > req->cache_size) {
ret = read_http_stream(req, (BYTE*)buf, min(sizeof(buf), req->content_pos - req->cache_size),
&ret_read, TRUE);
if(ret != ERROR_SUCCESS || !ret_read)
break;
}
}
if(task->buf) {
DWORD read_bytes;
while (read < task->size) {
......@@ -3155,6 +3205,47 @@ static DWORD async_read(http_request_t *req, void *buf, DWORD size, DWORD read_p
return ERROR_IO_PENDING;
}
static DWORD HTTPREQ_SetFilePointer(object_header_t *hdr, LONG lDistanceToMove, DWORD dwMoveContext)
{
http_request_t *req = (http_request_t*)hdr;
DWORD res = INVALID_SET_FILE_POINTER, err = ERROR_SUCCESS;
if(req->hdr.dwFlags & (INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_CACHE_WRITE)) {
SetLastError(ERROR_INTERNET_INVALID_OPERATION);
return INVALID_SET_FILE_POINTER;
}
EnterCriticalSection(&req->read_section);
switch (dwMoveContext) {
case FILE_BEGIN:
res = lDistanceToMove;
break;
case FILE_CURRENT:
if(req->content_pos && lDistanceToMove < 0) {
err = ERROR_NEGATIVE_SEEK;
break;
}
res = req->content_pos + lDistanceToMove;
break;
case FILE_END:
FIXME("dwMoveContext FILE_END not implemented\n");
/* fallthrough */
default:
err = ERROR_INTERNET_INVALID_OPERATION;
break;
}
if(err == ERROR_SUCCESS) {
req->content_pos = res;
req->read_pos = req->read_size = 0;
}
LeaveCriticalSection(&req->read_section);
SetLastError(err);
return res;
}
static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_read,
DWORD flags, DWORD_PTR context)
{
......@@ -3182,9 +3273,18 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD
memcpy(buf, req->read_buf + req->read_pos, read);
req->read_size -= read;
req->read_pos += read;
req->content_pos += read;
}
if(read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) {
if(read < size && req->req_file && req->req_file->file_handle) {
res = read_req_file(req, (BYTE*)buf + read, size - read, &cread, allow_blocking);
if(res == ERROR_SUCCESS) {
read += cread;
req->content_pos += cread;
}
}
if(res == ERROR_SUCCESS && read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) {
LeaveCriticalSection(&req->read_section);
INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0);
EnterCriticalSection( &req->read_section );
......@@ -3265,6 +3365,8 @@ static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available,
hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR;
avail = req->read_size;
if(req->cache_size > req->content_pos)
avail = max(avail, req->cache_size - req->content_pos);
if(!avail && !end_of_read_data(req)) {
LeaveCriticalSection(&req->read_section);
......@@ -3318,6 +3420,7 @@ static const object_vtbl_t HTTPREQVtbl = {
HTTPREQ_CloseConnection,
HTTPREQ_QueryOption,
HTTPREQ_SetOption,
HTTPREQ_SetFilePointer,
HTTPREQ_ReadFile,
HTTPREQ_WriteFile,
HTTPREQ_QueryDataAvailable,
......@@ -5807,6 +5910,7 @@ static const object_vtbl_t HTTPSESSIONVtbl = {
NULL,
NULL,
NULL,
NULL,
NULL
};
......
......@@ -957,6 +957,7 @@ static const object_vtbl_t APPINFOVtbl = {
APPINFO_SetOption,
NULL,
NULL,
NULL,
NULL
};
......@@ -2155,14 +2156,36 @@ INTERNET_STATUS_CALLBACK WINAPI InternetSetStatusCallbackW(
/***********************************************************************
* InternetSetFilePointer (WININET.@)
*
* Sets read position for an open internet file.
*
* RETURNS
* Current position of the file on success
* INVALID_SET_FILE_POINTER on failure
*/
DWORD WINAPI InternetSetFilePointer(HINTERNET hFile, LONG lDistanceToMove,
PVOID pReserved, DWORD dwMoveContext, DWORD_PTR dwContext)
{
FIXME("(%p %ld %p %ld %Ix): stub\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
object_header_t *hdr;
DWORD res;
TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext);
hdr = get_handle_object(hFile);
if(!hdr) {
SetLastError(ERROR_INVALID_HANDLE);
return INVALID_SET_FILE_POINTER;
}
SetLastError(ERROR_INTERNET_INVALID_OPERATION);
return INVALID_SET_FILE_POINTER;
if(hdr->vtbl->SetFilePointer) {
res = hdr->vtbl->SetFilePointer(hdr, lDistanceToMove, dwMoveContext);
}else {
SetLastError(ERROR_INVALID_HANDLE);
res = INVALID_SET_FILE_POINTER;
}
WININET_Release(hdr);
return res;
}
/***********************************************************************
......
......@@ -225,6 +225,7 @@ typedef struct {
void (*CloseConnection)(object_header_t*);
DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL);
DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD);
DWORD (*SetFilePointer)(object_header_t*,LONG,DWORD);
DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*,DWORD,DWORD_PTR);
DWORD (*WriteFile)(object_header_t*,const void*,DWORD,DWORD*);
DWORD (*QueryDataAvailable)(object_header_t*,DWORD*,DWORD,DWORD_PTR);
......@@ -332,6 +333,7 @@ typedef struct
FILETIME last_modified;
HANDLE hCacheFile;
ULONGLONG cache_size; /* size of cached data */
req_file_t *req_file;
FILETIME expires;
struct HttpAuthInfo *authInfo;
......@@ -339,6 +341,7 @@ typedef struct
CRITICAL_SECTION read_section; /* section to protect the following fields */
ULONGLONG contentLength; /* total number of bytes to be read */
ULONGLONG content_pos; /* content read position */
BOOL read_gzip; /* are we reading in gzip mode? */
DWORD read_pos; /* current read position in read_buf */
DWORD read_size; /* valid data size in read_buf */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment