From: Jason Kuo j20001970@gmail.com
The function is implemented by setting cache file pointer to fill read_buf. Consequently, when HTTPREQ_ReadFile is called, it will try reading data from cache after read_buf is depleted, before continuing reading from http stream.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=26570 --- dlls/wininet/http.c | 16 +++++++++++ dlls/wininet/internet.c | 60 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 73 insertions(+), 3 deletions(-)
diff --git a/dlls/wininet/http.c b/dlls/wininet/http.c index c9d1c463982..a0e44b50639 100644 --- a/dlls/wininet/http.c +++ b/dlls/wininet/http.c @@ -3184,6 +3184,22 @@ static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD req->read_pos += read; }
+ if(read < size && req->hCacheFile) { + DWORD cache_pos, err; + while(read < size) { + cache_pos = SetFilePointer(req->hCacheFile, 0, NULL, FILE_CURRENT); + err = cache_pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + if(err != NO_ERROR) + ERR("SetFilePointer return with error %ld\n", err); + if(cache_pos <= GetFileSize(req->hCacheFile, NULL)) + break; + res = ReadFile(req->hCacheFile, (char*)buf+read, size-read, &cread, NULL); + read += cread; + if(res != ERROR_SUCCESS || !cread) + break; + } + } + if(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); diff --git a/dlls/wininet/internet.c b/dlls/wininet/internet.c index 292fd44dd8e..baa0cd5313d 100644 --- a/dlls/wininet/internet.c +++ b/dlls/wininet/internet.c @@ -2154,14 +2154,68 @@ 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 cache_pos, read, cread; + DWORD err = ERROR_INTERNET_INVALID_OPERATION, res = INVALID_SET_FILE_POINTER; + http_request_t *request; + + TRACE("(%p %ld %p %ld %Ix)\n", hFile, lDistanceToMove, pReserved, dwMoveContext, dwContext); + + request = (http_request_t*)get_handle_object(hFile); + + if(request->hdr.dwFlags & (INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_CACHE_WRITE)) + goto lend; + + switch (dwMoveContext) { + case FILE_BEGIN: + cache_pos = lDistanceToMove; + break; + case FILE_CURRENT: + FIXME("dwMoveContext %ld not implemented\n", dwMoveContext); + err = ERROR_NEGATIVE_SEEK; + goto lend; + case FILE_END: + default: + FIXME("Unhandled dwMoveContext %ld\n", dwMoveContext); + goto lend; + }
- SetLastError(ERROR_INTERNET_INVALID_OPERATION); - return INVALID_SET_FILE_POINTER; + if(GetFileSize(request->hCacheFile, NULL) < cache_pos) { + BYTE buf[1024]; + while(GetFileSize(request->hCacheFile, NULL) < cache_pos) { + res = InternetReadFile(hFile, buf, 1024, &cread); + if(res != ERROR_SUCCESS || !cread) + break; + } + } + + res = cache_pos = SetFilePointer(request->hCacheFile, lDistanceToMove, NULL, dwMoveContext); + err = cache_pos == INVALID_SET_FILE_POINTER ? GetLastError() : NO_ERROR; + if(err != NO_ERROR) + goto lend; + EnterCriticalSection(&request->read_section); + read = min(READ_BUFFER_SIZE, GetFileSize(request->hCacheFile, NULL)-cache_pos); + if(ReadFile(request->hCacheFile, request->read_buf, read, &cread, NULL)) { + request->read_size = cread; + request->read_pos = 0; + } + LeaveCriticalSection(&request->read_section); + +lend: + if(res == INVALID_SET_FILE_POINTER) + SetLastError(err); + TRACE("returning %ld\n", res); + if(request) + WININET_Release( &request->hdr ); + return res; }
/***********************************************************************