From: Jason Kuo j20001970@gmail.com
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 --- dlls/wininet/ftp.c | 3 ++ dlls/wininet/http.c | 93 ++++++++++++++++++++++++++++++++++++++++- dlls/wininet/internet.c | 29 +++++++++++-- dlls/wininet/internet.h | 2 + 4 files changed, 123 insertions(+), 4 deletions(-)
diff --git a/dlls/wininet/ftp.c b/dlls/wininet/ftp.c index cf6555c63e2..f3f586cd6e1 100644 --- a/dlls/wininet/ftp.c +++ b/dlls/wininet/ftp.c @@ -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 };
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index 18f61f108fc..3a21da42afa 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -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->contentPos = 0; req->read_gzip = FALSE; }
@@ -2499,6 +2500,7 @@ static void create_cache_entry(http_request_t *req)
create_req_file(file_name, &req->req_file); req->req_file->url = url; + req->contentPos = 0;
req->hCacheFile = CreateFileW(file_name, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); @@ -2549,6 +2551,7 @@ static void remove_data( http_request_t *req, int count ) { if (!(req->read_size -= count)) req->read_pos = 0; else req->read_pos += count; + req->contentPos += count; }
static DWORD read_line( http_request_t *req, LPSTR buffer, DWORD *len ) @@ -3033,6 +3036,37 @@ 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 file_size, ret_read, res; + BYTE buf[1024]; + + file_size = GetFileSize(req->req_file->file_handle, NULL); + if(file_size == INVALID_FILE_SIZE) + return GetLastError(); + + if(!allow_blocking && req->contentPos > file_size) + return WSAEWOULDBLOCK; + + while (req->contentPos > file_size) { + res = read_http_stream(req, (BYTE*)buf, min(1024, req->contentPos-file_size), &ret_read, TRUE); + if(res != ERROR_SUCCESS || !ret_read) + break; + file_size = GetFileSize(req->req_file->file_handle, NULL); + } + + res = SetFilePointer(req->req_file->file_handle, req->contentPos, NULL, FILE_BEGIN); + if(res == INVALID_SET_FILE_POINTER) + return GetLastError(); + if(ReadFile(req->req_file->file_handle, buffer, size, &ret_read, NULL)) { + *read = ret_read; + req->contentPos += ret_read; + return ERROR_SUCCESS; + } + else + return GetLastError(); +} + /* 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 +3080,22 @@ 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->contentPos += ret_read; allow_blocking = FALSE; }
+ if(ret_read < size && req->req_file && req->req_file->file_handle) { + res = read_req_file(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, allow_blocking); + if(res == ERROR_SUCCESS) + ret_read += current_read; + } + if(ret_read < size) { res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, allow_blocking); - if(res == ERROR_SUCCESS) + if(res == ERROR_SUCCESS) { ret_read += current_read; + req->contentPos += current_read; + } else if(res == WSAEWOULDBLOCK && ret_read) res = ERROR_SUCCESS; } @@ -3155,6 +3198,45 @@ 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 err = ERROR_INTERNET_INVALID_OPERATION, res = INVALID_SET_FILE_POINTER; + + if(req->hdr.dwFlags & (INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_CACHE_WRITE)) + goto lend; + + switch (dwMoveContext) { + case FILE_BEGIN: + res = lDistanceToMove; + break; + case FILE_CURRENT: + if(req->contentPos && lDistanceToMove < 0) { + err = ERROR_NEGATIVE_SEEK; + goto lend; + } + res = req->contentPos + lDistanceToMove; + break; + case FILE_END: + FIXME("dwMoveContext FILE_END not implemented\n"); + goto lend; + default: + goto lend; + } + + EnterCriticalSection(&req->read_section); + req->contentPos = res; + req->read_pos = req->read_size = 0; + LeaveCriticalSection(&req->read_section); + + err = NO_ERROR; + +lend: + if(res == INVALID_SET_FILE_POINTER) + 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,6 +3264,13 @@ 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->contentPos += read; + } + + 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; }
if(read < size && (!read || !(flags & IRF_NO_WAIT)) && !end_of_read_data(req)) { @@ -3318,6 +3407,7 @@ static const object_vtbl_t HTTPREQVtbl = { HTTPREQ_CloseConnection, HTTPREQ_QueryOption, HTTPREQ_SetOption, + HTTPREQ_SetFilePointer, HTTPREQ_ReadFile, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, @@ -5807,6 +5897,7 @@ static const object_vtbl_t HTTPSESSIONVtbl = { NULL, NULL, NULL, + NULL, NULL };
diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 26d262b9665..57be3922d63 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -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); + DWORD err = ERROR_INVALID_HANDLE, res = INVALID_SET_FILE_POINTER; + object_header_t *hdr; + + TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext); + + hdr = get_handle_object(hFile); + if(!hdr) + goto lend; + + if(hdr->vtbl->SetFilePointer) { + res = hdr->vtbl->SetFilePointer(hdr, lDistanceToMove, dwMoveContext); + if(res == INVALID_SET_FILE_POINTER) + err = GetLastError(); + }
- SetLastError(ERROR_INTERNET_INVALID_OPERATION); - return INVALID_SET_FILE_POINTER; + WININET_Release(hdr); + +lend: + if(res == INVALID_SET_FILE_POINTER) + SetLastError(err); + return res; }
/*********************************************************************** diff --git a/dlls/wininet/internet.h b/dlls/wininet/internet.h index 6756488d5a5..a1ad1e0153e 100644 --- a/dlls/wininet/internet.h +++ b/dlls/wininet/internet.h @@ -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); @@ -339,6 +340,7 @@ typedef struct
CRITICAL_SECTION read_section; /* section to protect the following fields */ ULONGLONG contentLength; /* total number of bytes to be read */ + ULONGLONG contentPos; 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 */