Author: akhaldi Date: Sun Jun 4 01:48:55 2017 New Revision: 74866
URL: http://svn.reactos.org/svn/reactos?rev=74866&view=rev Log: [WININET] Sync with Wine Staging 2.9. CORE-13362
05c23c9 wininet: Use isspaceW() instead of isspace() for WCHARs. f9d1b16 wininet: Return failure when handling http redirect without hostname. 4ca5f42 wininet: Allow to set INTERNET_OPTION_HTTP_DECODING on sessions and connections. 7d8cf31 wininet: Don't use returned read size if read failed in gzip_read. 2952c63 wininet: Get rid of no longer needed get_avail_data from data stream implementations. 295291b wininet: Always use non-blocking reads in HTTP_ReceiveRequestData. fd0ac40 wininet: Get rid of no longer needed blocking_mode_t. 18f9d03 wininet: Get rid of no longer needed BLOCKING_WAITALL. 7eaadab wininet: Merge InternetReadFile and InternetReadFileEx implementations. a546e8a wininet: Reimplemented InternetQueryDataAvailable on top of async_read. 0880874 wininet: Rewrite InternetReadFileEx for http protocol to make use of non-blocking reads. 98bcd00 wininet: Rewrite asynchronous read to try to fill whole buffer and not buffer additional data unless requested. c140a70 wininet: Propagate WSAEWOULDBLOCK from read_http_stream. f42a2cc wininet: Pass blocking mode to HTTPREQ_Read. 67b5677 wininet: Propagate WSAEWOULDBLOCK result from content decoding reads. 36f6387 wininet: Forward InternetGetConnectedState to Ex function. 7b42dc4 wininet: Improved netconn_drain_content. 6caecb6 wininet: Handle query parameters for HTTPS urls in InternetOpenUrlW. e9be490 wininet: Fix some more spec file entries.
Modified: trunk/reactos/dll/win32/wininet/ftp.c trunk/reactos/dll/win32/wininet/http.c trunk/reactos/dll/win32/wininet/internet.c trunk/reactos/dll/win32/wininet/internet.h trunk/reactos/dll/win32/wininet/netconnection.c trunk/reactos/dll/win32/wininet/wininet.spec trunk/reactos/media/doc/README.WINE
Modified: trunk/reactos/dll/win32/wininet/ftp.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/wininet/ftp.c?rev... ============================================================================== --- trunk/reactos/dll/win32/wininet/ftp.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/wininet/ftp.c [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -1161,7 +1161,8 @@ return INET_QueryOption(hdr, option, buffer, size, unicode); }
-static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) +static DWORD FTPFILE_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read, + DWORD flags, DWORD_PTR context) { ftp_file_t *file = (ftp_file_t*)hdr; int res; @@ -1183,12 +1184,6 @@ WARN("WriteFile failed: %u\n", GetLastError()); } return error; -} - -static DWORD FTPFILE_ReadFileEx(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_size, - DWORD flags, DWORD_PTR context) -{ - return FTPFILE_ReadFile(hdr, buf, size, ret_size); }
static DWORD FTPFILE_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) @@ -1277,7 +1272,6 @@ FTPFILE_QueryOption, INET_SetOption, FTPFILE_ReadFile, - FTPFILE_ReadFileEx, FTPFILE_WriteFile, FTPFILE_QueryDataAvailable, NULL, @@ -2378,7 +2372,6 @@ FTPSESSION_CloseConnection, FTPSESSION_QueryOption, INET_SetOption, - NULL, NULL, NULL, NULL, @@ -3517,7 +3510,6 @@ NULL, FTPFINDNEXT_QueryOption, INET_SetOption, - NULL, NULL, NULL, NULL,
Modified: trunk/reactos/dll/win32/wininet/http.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/wininet/http.c?re... ============================================================================== --- trunk/reactos/dll/win32/wininet/http.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/wininet/http.c [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -364,16 +364,9 @@ return ret; }
-typedef enum { - BLOCKING_ALLOW, - BLOCKING_DISALLOW, - BLOCKING_WAITALL -} blocking_mode_t; - struct data_stream_vtbl_t { - DWORD (*get_avail_data)(data_stream_t*,http_request_t*); BOOL (*end_of_data)(data_stream_t*,http_request_t*); - DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,blocking_mode_t); + DWORD (*read)(data_stream_t*,http_request_t*,BYTE*,DWORD,DWORD*,BOOL); BOOL (*drain_content)(data_stream_t*,http_request_t*); void (*destroy)(data_stream_t*); }; @@ -430,12 +423,6 @@ BOOL end_of_data; } gzip_stream_t;
-static DWORD gzip_get_avail_data(data_stream_t *stream, http_request_t *req) -{ - /* Allow reading only from read buffer */ - return 0; -} - static BOOL gzip_end_of_data(data_stream_t *stream, http_request_t *req) { gzip_stream_t *gzip_stream = (gzip_stream_t*)stream; @@ -444,7 +431,7 @@ }
static DWORD gzip_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size, - DWORD *read, blocking_mode_t blocking_mode) + DWORD *read, BOOL allow_blocking) { gzip_stream_t *gzip_stream = (gzip_stream_t*)stream; z_stream *zstream = &gzip_stream->zstream; @@ -452,7 +439,7 @@ int zres; DWORD res = ERROR_SUCCESS;
- TRACE("(%d %d)\n", size, blocking_mode); + TRACE("(%d %x)\n", size, allow_blocking);
while(size && !gzip_stream->end_of_data) { if(!gzip_stream->buf_size) { @@ -462,16 +449,14 @@ gzip_stream->buf_pos = 0; } res = gzip_stream->parent_stream->vtbl->read(gzip_stream->parent_stream, req, gzip_stream->buf+gzip_stream->buf_size, - sizeof(gzip_stream->buf)-gzip_stream->buf_size, ¤t_read, blocking_mode); - gzip_stream->buf_size += current_read; + sizeof(gzip_stream->buf)-gzip_stream->buf_size, ¤t_read, allow_blocking); if(res != ERROR_SUCCESS) break;
+ gzip_stream->buf_size += current_read; if(!current_read) { - if(blocking_mode != BLOCKING_DISALLOW) { - WARN("unexpected end of data\n"); - gzip_stream->end_of_data = TRUE; - } + WARN("unexpected end of data\n"); + gzip_stream->end_of_data = TRUE; break; } } @@ -497,11 +482,13 @@ break; }
- if(ret_read && blocking_mode == BLOCKING_ALLOW) - blocking_mode = BLOCKING_DISALLOW; + if(ret_read) + allow_blocking = FALSE; }
TRACE("read %u bytes\n", ret_read); + if(ret_read) + res = ERROR_SUCCESS; *read = ret_read; return res; } @@ -524,7 +511,6 @@ }
static const data_stream_vtbl_t gzip_stream_vtbl = { - gzip_get_avail_data, gzip_end_of_data, gzip_read, gzip_drain_content, @@ -2348,11 +2334,6 @@ if (!(req->session->appInfo->proxyPassword = heap_strdupW(buffer))) return ERROR_OUTOFMEMORY; return ERROR_SUCCESS;
- case INTERNET_OPTION_HTTP_DECODING: - if(size != sizeof(BOOL)) - return ERROR_INVALID_PARAMETER; - req->decoding = *(BOOL*)buffer; - return ERROR_SUCCESS; }
return INET_SetOption(hdr, option, buffer, size); @@ -2565,11 +2546,13 @@ return !req->read_size && req->data_stream->vtbl->end_of_data(req->data_stream, req); }
-static DWORD read_http_stream(http_request_t *req, BYTE *buf, DWORD size, DWORD *read, blocking_mode_t blocking_mode) +static DWORD read_http_stream(http_request_t *req, BYTE *buf, DWORD size, DWORD *read, BOOL allow_blocking) { DWORD res;
- res = req->data_stream->vtbl->read(req->data_stream, req, buf, size, read, blocking_mode); + res = req->data_stream->vtbl->read(req->data_stream, req, buf, size, read, allow_blocking); + if(res != ERROR_SUCCESS) + *read = 0; assert(*read <= size);
if(req->hCacheFile) { @@ -2582,7 +2565,7 @@ FIXME("WriteFile failed: %u\n", GetLastError()); }
- if(req->data_stream->vtbl->end_of_data(req->data_stream, req)) + if((res == ERROR_SUCCESS && !*read) || req->data_stream->vtbl->end_of_data(req->data_stream, req)) commit_cache_entry(req); }
@@ -2590,7 +2573,7 @@ }
/* fetch some more data into the read buffer (the read section must be held) */ -static DWORD refill_read_buffer(http_request_t *req, blocking_mode_t blocking_mode, DWORD *read_bytes) +static DWORD refill_read_buffer(http_request_t *req, BOOL allow_blocking, DWORD *read_bytes) { DWORD res, read=0;
@@ -2604,7 +2587,10 @@ }
res = read_http_stream(req, req->read_buf+req->read_size, sizeof(req->read_buf) - req->read_size, - &read, blocking_mode); + &read, allow_blocking); + if(res != ERROR_SUCCESS) + return res; + req->read_size += read;
TRACE("read %u bytes, read_size %u\n", read, req->read_size); @@ -2613,33 +2599,6 @@ return res; }
-/* return the size of data available to be read immediately (the read section must be held) */ -static DWORD get_avail_data( http_request_t *req ) -{ - DWORD avail = req->read_size; - - /* - * Different Windows versions have different limits of returned data, but all - * of them return no more than centrain amount. We use READ_BUFFER_SIZE as a limit. - */ - if(avail < READ_BUFFER_SIZE) - avail += req->data_stream->vtbl->get_avail_data(req->data_stream, req); - - return min(avail, READ_BUFFER_SIZE); -} - -static DWORD netconn_get_avail_data(data_stream_t *stream, http_request_t *req) -{ - netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; - DWORD avail = 0; - - if(is_valid_netconn(req->netconn)) - NETCON_query_data_available(req->netconn, &avail); - return netconn_stream->content_length == ~0u - ? avail - : min(avail, netconn_stream->content_length-netconn_stream->content_read); -} - static BOOL netconn_end_of_data(data_stream_t *stream, http_request_t *req) { netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; @@ -2647,31 +2606,24 @@ }
static DWORD netconn_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size, - DWORD *read, blocking_mode_t blocking_mode) + DWORD *read, BOOL allow_blocking) { netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; DWORD res = ERROR_SUCCESS; - int len = 0, ret = 0; + int ret = 0;
size = min(size, netconn_stream->content_length-netconn_stream->content_read);
if(size && is_valid_netconn(req->netconn)) { - while((res = NETCON_recv(req->netconn, buf+ret, size-ret, blocking_mode != BLOCKING_DISALLOW, &len)) == ERROR_SUCCESS) { - if(!len) { + res = NETCON_recv(req->netconn, buf, size, allow_blocking, &ret); + if(res == ERROR_SUCCESS) { + if(!ret) netconn_stream->content_length = netconn_stream->content_read; - break; - } - ret += len; - netconn_stream->content_read += len; - if(blocking_mode != BLOCKING_WAITALL || size == ret) - break; - } - - if(ret || (blocking_mode == BLOCKING_DISALLOW && res == WSAEWOULDBLOCK)) - res = ERROR_SUCCESS; - } - - TRACE("read %u bytes\n", ret); + netconn_stream->content_read += ret; + } + } + + TRACE("res %u read %u bytes\n", res, ret); *read = ret; return res; } @@ -2680,17 +2632,20 @@ { netconn_stream_t *netconn_stream = (netconn_stream_t*)stream; BYTE buf[1024]; - int len; - - if(netconn_end_of_data(stream, req)) - return TRUE; - - do { - if(NETCON_recv(req->netconn, buf, sizeof(buf), FALSE, &len) != ERROR_SUCCESS) + int len, res; + size_t size; + + if(netconn_stream->content_length == ~0u) + return FALSE; + + while(netconn_stream->content_read < netconn_stream->content_length) { + size = min(sizeof(buf), netconn_stream->content_length-netconn_stream->content_read); + res = NETCON_recv(req->netconn, buf, size, FALSE, &len); + if(res || !len) return FALSE;
netconn_stream->content_read += len; - }while(netconn_stream->content_read < netconn_stream->content_length); + }
return TRUE; } @@ -2700,7 +2655,6 @@ }
static const data_stream_vtbl_t netconn_stream_vtbl = { - netconn_get_avail_data, netconn_end_of_data, netconn_read, netconn_drain_content, @@ -2722,7 +2676,7 @@ }
static DWORD chunked_read(data_stream_t *stream, http_request_t *req, BYTE *buf, DWORD size, - DWORD *read, blocking_mode_t blocking_mode) + DWORD *read, BOOL allow_blocking) { chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; DWORD ret_read = 0, res = ERROR_SUCCESS; @@ -2741,10 +2695,12 @@ case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA: case CHUNKED_STREAM_STATE_DISCARD_EOL_AT_END: chunked_stream->buf_pos = 0; - res = NETCON_recv(req->netconn, chunked_stream->buf, sizeof(chunked_stream->buf), blocking_mode != BLOCKING_DISALLOW, &read_bytes); + res = NETCON_recv(req->netconn, chunked_stream->buf, sizeof(chunked_stream->buf), allow_blocking, &read_bytes); if(res == ERROR_SUCCESS && read_bytes) { chunked_stream->buf_size += read_bytes; }else if(res == WSAEWOULDBLOCK) { + if(ret_read) + res = ERROR_SUCCESS; continue_read = FALSE; continue; }else { @@ -2803,7 +2759,7 @@ chunked_stream->buf_size -= read_bytes; }else { res = NETCON_recv(req->netconn, (char*)buf+ret_read, read_bytes, - blocking_mode != BLOCKING_DISALLOW, (int*)&read_bytes); + allow_blocking, (int*)&read_bytes); if(res != ERROR_SUCCESS) { continue_read = FALSE; break; @@ -2820,8 +2776,7 @@ ret_read += read_bytes; if(!chunked_stream->chunk_size) chunked_stream->state = CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA; - if(blocking_mode == BLOCKING_ALLOW) - blocking_mode = BLOCKING_DISALLOW; + allow_blocking = FALSE; break;
case CHUNKED_STREAM_STATE_DISCARD_EOL_AFTER_DATA: @@ -2848,7 +2803,7 @@
if(ret_read) res = ERROR_SUCCESS; - if(res != ERROR_SUCCESS && res != WSAEWOULDBLOCK) + if(res != ERROR_SUCCESS) return res;
TRACE("read %d bytes\n", ret_read); @@ -2856,26 +2811,6 @@ return ERROR_SUCCESS; }
-static DWORD chunked_get_avail_data(data_stream_t *stream, http_request_t *req) -{ - chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; - DWORD avail = 0; - - if(chunked_stream->state != CHUNKED_STREAM_STATE_READING_CHUNK) { - DWORD res, read; - - /* try to process to the next chunk */ - res = chunked_read(stream, req, NULL, 0, &read, BLOCKING_DISALLOW); - if(res != ERROR_SUCCESS || chunked_stream->state != CHUNKED_STREAM_STATE_READING_CHUNK) - return 0; - } - - if(is_valid_netconn(req->netconn) && chunked_stream->buf_size < chunked_stream->chunk_size) - NETCON_query_data_available(req->netconn, &avail); - - return min(avail + chunked_stream->buf_size, chunked_stream->chunk_size); -} - static BOOL chunked_drain_content(data_stream_t *stream, http_request_t *req) { chunked_stream_t *chunked_stream = (chunked_stream_t*)stream; @@ -2889,7 +2824,6 @@ }
static const data_stream_vtbl_t chunked_stream_vtbl = { - chunked_get_avail_data, chunked_end_of_data, chunked_read, chunked_drain_content, @@ -2941,7 +2875,7 @@ request->contentLength = ~0u; }
- if(request->decoding) { + if(request->hdr.decoding) { int encoding_idx;
static const WCHAR deflateW[] = {'d','e','f','l','a','t','e',0}; @@ -2980,48 +2914,38 @@ sizeof(INTERNET_ASYNC_RESULT)); }
-static void HTTP_ReceiveRequestData(http_request_t *req, BOOL first_notif, DWORD *ret_size) -{ - DWORD res, read = 0, avail = 0; - blocking_mode_t mode; +static void HTTP_ReceiveRequestData(http_request_t *req) +{ + DWORD res, read = 0;
TRACE("%p\n", req);
EnterCriticalSection( &req->read_section );
- mode = first_notif && req->read_size ? BLOCKING_DISALLOW : BLOCKING_ALLOW; - res = refill_read_buffer(req, mode, &read); + res = refill_read_buffer(req, FALSE, &read); if(res == ERROR_SUCCESS) - avail = get_avail_data(req); + read += req->read_size;
LeaveCriticalSection( &req->read_section );
- if(res != ERROR_SUCCESS || (mode != BLOCKING_DISALLOW && !read)) { + if(res != WSAEWOULDBLOCK && (res != ERROR_SUCCESS || !read)) { WARN("res %u read %u, closing connection\n", res, read); http_release_netconn(req, FALSE); }
- if(res != ERROR_SUCCESS) { + if(res != ERROR_SUCCESS && res != WSAEWOULDBLOCK) { send_request_complete(req, 0, res); return; }
- if(ret_size) - *ret_size = avail; - if(first_notif) - avail = 0; - - send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, avail); + send_request_complete(req, req->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)req->hdr.hInternet : 1, 0); }
/* 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) +static DWORD HTTPREQ_Read(http_request_t *req, void *buffer, DWORD size, DWORD *read, BOOL allow_blocking) { DWORD current_read = 0, ret_read = 0; - blocking_mode_t blocking_mode; DWORD res = ERROR_SUCCESS; - - blocking_mode = req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC ? BLOCKING_ALLOW : BLOCKING_WAITALL;
EnterCriticalSection( &req->read_section );
@@ -3030,13 +2954,15 @@ memcpy(buffer, req->read_buf+req->read_pos, ret_read); req->read_size -= ret_read; req->read_pos += ret_read; - if(blocking_mode == BLOCKING_ALLOW) - blocking_mode = BLOCKING_DISALLOW; + allow_blocking = FALSE; }
if(ret_read < size) { - res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, blocking_mode); - ret_read += current_read; + res = read_http_stream(req, (BYTE*)buffer+ret_read, size-ret_read, ¤t_read, allow_blocking); + if(res == ERROR_SUCCESS) + ret_read += current_read; + else if(res == WSAEWOULDBLOCK && ret_read) + res = ERROR_SUCCESS; }
LeaveCriticalSection( &req->read_section ); @@ -3044,7 +2970,7 @@ *read = ret_read; TRACE( "retrieved %u bytes (%u)\n", ret_read, req->contentLength );
- if(size && !ret_read) + if(res != WSAEWOULDBLOCK && (!ret_read || res != ERROR_SUCCESS)) http_release_netconn(req, res == ERROR_SUCCESS);
return res; @@ -3069,7 +2995,7 @@ DWORD bytes_read, res; BYTE buf[4096];
- res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read); + res = HTTPREQ_Read(req, buf, sizeof(buf), &bytes_read, TRUE); if(res != ERROR_SUCCESS) { ret = FALSE; break; @@ -3088,114 +3014,136 @@ task_header_t hdr; void *buf; DWORD size; + DWORD read_pos; DWORD *ret_read; -} read_file_ex_task_t; - -static void AsyncReadFileExProc(task_header_t *hdr) -{ - read_file_ex_task_t *task = (read_file_ex_task_t*)hdr; +} read_file_task_t; + +static void async_read_file_proc(task_header_t *hdr) +{ + read_file_task_t *task = (read_file_task_t*)hdr; http_request_t *req = (http_request_t*)task->hdr.hdr; - DWORD res = ERROR_SUCCESS, read = 0, buffered = 0; - - TRACE("%p\n", req); + DWORD res = ERROR_SUCCESS, read = task->read_pos, complete_arg = 0; + + TRACE("req %p buf %p size %u read_pos %u ret_read %p\n", req, task->buf, task->size, task->read_pos, task->ret_read); + + if(task->buf) { + DWORD read_bytes; + while (read < task->size) { + res = HTTPREQ_Read(req, (char*)task->buf + read, task->size - read, &read_bytes, TRUE); + if (res != ERROR_SUCCESS || !read_bytes) + break; + read += read_bytes; + } + }else { + EnterCriticalSection(&req->read_section); + res = refill_read_buffer(req, TRUE, &read); + LeaveCriticalSection(&req->read_section); + + if(task->ret_read) + complete_arg = read; /* QueryDataAvailable reports read bytes in request complete notification */ + if(res != ERROR_SUCCESS || !read) + http_release_netconn(req, drain_content(req, FALSE)); + } + + TRACE("res %u read %u\n", res, read);
if(task->ret_read) - res = HTTPREQ_Read(req, task->buf, task->size, &read); - if(res == ERROR_SUCCESS) - res = refill_read_buffer(req, task->ret_read ? BLOCKING_DISALLOW : BLOCKING_ALLOW, &buffered); - if (res == ERROR_SUCCESS) - { - if(task->ret_read) - *task->ret_read = read; - read += buffered; + *task->ret_read = read; + + /* FIXME: We should report bytes transferred before decoding content. */ + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, &read, sizeof(read)); + + if(res != ERROR_SUCCESS) + complete_arg = res; + send_request_complete(req, res == ERROR_SUCCESS, complete_arg); +} + +static DWORD async_read(http_request_t *req, void *buf, DWORD size, DWORD read_pos, DWORD *ret_read) +{ + read_file_task_t *task; + + task = alloc_async_task(&req->hdr, async_read_file_proc, sizeof(*task)); + if(!task) + return ERROR_OUTOFMEMORY; + + task->buf = buf; + task->size = size; + task->read_pos = read_pos; + task->ret_read = ret_read; + + INTERNET_AsyncCall(&task->hdr); + return ERROR_IO_PENDING; +} + +static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_read, + DWORD flags, DWORD_PTR context) +{ + http_request_t *req = (http_request_t*)hdr; + DWORD res = ERROR_SUCCESS, read = 0, cread, error = ERROR_SUCCESS; + BOOL allow_blocking, notify_received = FALSE; + + TRACE("(%p %p %u %x)\n", req, buf, size, flags); + + if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) + FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); + + allow_blocking = !(req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC); + + if(allow_blocking || TryEnterCriticalSection(&req->read_section)) { + if(allow_blocking) + EnterCriticalSection(&req->read_section); + if(hdr->dwError == ERROR_SUCCESS) + hdr->dwError = INTERNET_HANDLE_IN_USE; + else if(hdr->dwError == INTERNET_HANDLE_IN_USE) + hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; + + if(req->read_size) { + read = min(size, req->read_size); + memcpy(buf, req->read_buf + req->read_pos, read); + req->read_size -= read; + req->read_pos += read; + } + + 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); + EnterCriticalSection( &req->read_section ); + notify_received = TRUE; + + while(read < size) { + res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread, allow_blocking); + read += cread; + if (res != ERROR_SUCCESS || !cread) + break; + } + } + + if(hdr->dwError == INTERNET_HANDLE_IN_USE) + hdr->dwError = ERROR_SUCCESS; + else + error = hdr->dwError; + + LeaveCriticalSection( &req->read_section ); + }else { + res = WSAEWOULDBLOCK; + } + + if(res == WSAEWOULDBLOCK) { + if(!(flags & IRF_NO_WAIT)) + return async_read(req, buf, size, read, ret_read); + if(!read) + return async_read(req, NULL, 0, 0, NULL); + res = ERROR_SUCCESS; + } + + *ret_read = read; + if (res != ERROR_SUCCESS) + return res; + + if(notify_received) INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, &read, sizeof(read)); - } - - send_request_complete(req, res == ERROR_SUCCESS, res); -} - -static DWORD HTTPREQ_ReadFileEx(object_header_t *hdr, void *buf, DWORD size, DWORD *ret_read, - DWORD flags, DWORD_PTR context) -{ - - http_request_t *req = (http_request_t*)hdr; - DWORD res, read, cread, error = ERROR_SUCCESS; - - TRACE("(%p %p %u %x)\n", req, buf, size, flags); - - if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) - FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - - if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - read_file_ex_task_t *task; - - if (TryEnterCriticalSection( &req->read_section )) - { - if (get_avail_data(req) || end_of_read_data(req)) - { - res = HTTPREQ_Read(req, buf, size, &read); - LeaveCriticalSection( &req->read_section ); - goto done; - } - LeaveCriticalSection( &req->read_section ); - } - - task = alloc_async_task(&req->hdr, AsyncReadFileExProc, sizeof(*task)); - task->buf = buf; - task->size = size; - task->ret_read = (flags & IRF_NO_WAIT) ? NULL : ret_read; - - INTERNET_AsyncCall(&task->hdr); - - return ERROR_IO_PENDING; - } - - read = 0; - - EnterCriticalSection( &req->read_section ); - if(hdr->dwError == ERROR_SUCCESS) - hdr->dwError = INTERNET_HANDLE_IN_USE; - else if(hdr->dwError == INTERNET_HANDLE_IN_USE) - hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; - - while(1) { - res = HTTPREQ_Read(req, (char*)buf+read, size-read, &cread); - if(res != ERROR_SUCCESS) - break; - - read += cread; - if(read == size || end_of_read_data(req)) - break; - - LeaveCriticalSection( &req->read_section ); - - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, - &cread, sizeof(cread)); - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, - INTERNET_STATUS_RECEIVING_RESPONSE, NULL, 0); - - EnterCriticalSection( &req->read_section ); - } - - if(hdr->dwError == INTERNET_HANDLE_IN_USE) - hdr->dwError = ERROR_SUCCESS; - else - error = hdr->dwError; - - LeaveCriticalSection( &req->read_section ); - -done: - *ret_read = read; - if (res == ERROR_SUCCESS) { - INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, - &read, sizeof(read)); - } - - return res==ERROR_SUCCESS ? error : res; + return error; }
static DWORD HTTPREQ_WriteFile(object_header_t *hdr, const void *buffer, DWORD size, DWORD *written) @@ -3214,99 +3162,60 @@ return res; }
-static DWORD HTTPREQ_ReadFile(object_header_t *hdr, void *buffer, DWORD size, DWORD *read) +static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) { http_request_t *req = (http_request_t*)hdr; - DWORD res; - - if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - read_file_ex_task_t *task; - - if (TryEnterCriticalSection( &req->read_section )) - { - if (get_avail_data(req) || end_of_read_data(req)) - { - res = HTTPREQ_Read(req, buffer, size, read); - LeaveCriticalSection( &req->read_section ); - return res; - } - LeaveCriticalSection( &req->read_section ); - } - - task = alloc_async_task(&req->hdr, AsyncReadFileExProc, sizeof(*task)); - task->buf = buffer; - task->size = size; - task->ret_read = read; - - *read = 0; - INTERNET_AsyncCall(&task->hdr); - - return ERROR_IO_PENDING; - } - - EnterCriticalSection( &req->read_section ); - if(hdr->dwError == INTERNET_HANDLE_IN_USE) - hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; - - res = HTTPREQ_Read(req, buffer, size, read); - if(res == ERROR_SUCCESS) - res = hdr->dwError; - LeaveCriticalSection( &req->read_section ); - - return res; -} - -typedef struct { - task_header_t hdr; - DWORD *ret_size; -} http_data_available_task_t; - -static void AsyncQueryDataAvailableProc(task_header_t *hdr) -{ - http_data_available_task_t *task = (http_data_available_task_t*)hdr; - - HTTP_ReceiveRequestData((http_request_t*)task->hdr.hdr, FALSE, task->ret_size); -} - -static DWORD HTTPREQ_QueryDataAvailable(object_header_t *hdr, DWORD *available, DWORD flags, DWORD_PTR ctx) -{ - http_request_t *req = (http_request_t*)hdr; + DWORD res = ERROR_SUCCESS, avail = 0, error = ERROR_SUCCESS; + BOOL allow_blocking, notify_received = FALSE;
TRACE("(%p %p %x %lx)\n", req, available, flags, ctx);
- if (req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC) - { - http_data_available_task_t *task; - - /* never wait, if we can't enter the section we queue an async request right away */ - if (TryEnterCriticalSection( &req->read_section )) - { - refill_read_buffer(req, BLOCKING_DISALLOW, NULL); - if ((*available = get_avail_data( req ))) goto done; - if (end_of_read_data( req )) goto done; - LeaveCriticalSection( &req->read_section ); - } - - task = alloc_async_task(&req->hdr, AsyncQueryDataAvailableProc, sizeof(*task)); - task->ret_size = available; - INTERNET_AsyncCall(&task->hdr); - return ERROR_IO_PENDING; - } - - EnterCriticalSection( &req->read_section ); - - if (!(*available = get_avail_data( req )) && !end_of_read_data( req )) - { - refill_read_buffer( req, BLOCKING_ALLOW, NULL ); - *available = get_avail_data( req ); - } - -done: - LeaveCriticalSection( &req->read_section ); - - TRACE( "returning %u\n", *available ); - return ERROR_SUCCESS; + if (flags & ~(IRF_ASYNC|IRF_NO_WAIT)) + FIXME("these dwFlags aren't implemented: 0x%x\n", flags & ~(IRF_ASYNC|IRF_NO_WAIT)); + + *available = 0; + allow_blocking = !(req->session->appInfo->hdr.dwFlags & INTERNET_FLAG_ASYNC); + + if(allow_blocking || TryEnterCriticalSection(&req->read_section)) { + if(allow_blocking) + EnterCriticalSection(&req->read_section); + if(hdr->dwError == ERROR_SUCCESS) + hdr->dwError = INTERNET_HANDLE_IN_USE; + else if(hdr->dwError == INTERNET_HANDLE_IN_USE) + hdr->dwError = ERROR_INTERNET_INTERNAL_ERROR; + + avail = req->read_size; + + if(!avail && !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 ); + notify_received = TRUE; + + res = refill_read_buffer(req, allow_blocking, &avail); + } + + if(hdr->dwError == INTERNET_HANDLE_IN_USE) + hdr->dwError = ERROR_SUCCESS; + else + error = hdr->dwError; + + LeaveCriticalSection( &req->read_section ); + }else { + res = WSAEWOULDBLOCK; + } + + if(res == WSAEWOULDBLOCK) + return async_read(req, NULL, 0, 0, available); + + if (res != ERROR_SUCCESS) + return res; + + *available = avail; + if(notify_received) + INTERNET_SendCallback(&req->hdr, req->hdr.dwContext, INTERNET_STATUS_RESPONSE_RECEIVED, + &avail, sizeof(avail)); + return error; }
static DWORD HTTPREQ_LockRequestFile(object_header_t *hdr, req_file_t **ret) @@ -3330,7 +3239,6 @@ HTTPREQ_QueryOption, HTTPREQ_SetOption, HTTPREQ_ReadFile, - HTTPREQ_ReadFileEx, HTTPREQ_WriteFile, HTTPREQ_QueryDataAvailable, NULL, @@ -3365,6 +3273,7 @@ request->hdr.htype = WH_HHTTPREQ; request->hdr.dwFlags = dwFlags; request->hdr.dwContext = dwContext; + request->hdr.decoding = session->hdr.decoding; request->contentLength = ~0u;
request->netconn_stream.data_stream.vtbl = &netconn_stream_vtbl; @@ -4137,6 +4046,9 @@ if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) return INTERNET_GetLastError();
+ if (!urlComponents.dwHostNameLength) + return ERROR_INTERNET_INVALID_URL; + if(urlComponents.nScheme == INTERNET_SCHEME_HTTP) { if(request->hdr.dwFlags & INTERNET_FLAG_SECURE) { TRACE("redirect from secure page to non-secure page\n"); @@ -4380,7 +4292,7 @@ while (isspaceW(*ptr)) ptr++;
- for (monthPtr = month; !isspace(*ptr) && + for (monthPtr = month; !isspaceW(*ptr) && monthPtr - month < sizeof(month) / sizeof(month[0]) - 1; monthPtr++, ptr++) *monthPtr = *ptr; @@ -4477,7 +4389,7 @@ while (isspaceW(*ptr)) ptr++;
- for (monthPtr = month; !isspace(*ptr) && + for (monthPtr = month; !isspaceW(*ptr) && monthPtr - month < sizeof(month) / sizeof(month[0]) - 1; monthPtr++, ptr++) *monthPtr = *ptr; @@ -5221,7 +5133,7 @@ { if (res == ERROR_SUCCESS) { if(bEndRequest && request->contentLength && request->bytesWritten == request->bytesToWrite) - HTTP_ReceiveRequestData(request, TRUE, NULL); + HTTP_ReceiveRequestData(request); else send_request_complete(request, request->session->hdr.dwInternalFlags & INET_OPENURL ? (DWORD_PTR)request->hdr.hInternet : 1, 0); @@ -5328,7 +5240,7 @@ create_cache_entry(request);
if (res == ERROR_SUCCESS && request->contentLength) - HTTP_ReceiveRequestData(request, TRUE, NULL); + HTTP_ReceiveRequestData(request); else send_request_complete(request, res == ERROR_SUCCESS, res);
@@ -5818,7 +5730,6 @@ NULL, NULL, NULL, - NULL, NULL };
@@ -5859,6 +5770,7 @@ session->hdr.dwFlags = dwFlags; session->hdr.dwContext = dwContext; session->hdr.dwInternalFlags |= dwInternalFlags; + session->hdr.decoding = hIC->hdr.decoding;
WININET_AddRef( &hIC->hdr ); session->appInfo = hIC;
Modified: trunk/reactos/dll/win32/wininet/internet.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/wininet/internet.... ============================================================================== --- trunk/reactos/dll/win32/wininet/internet.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/wininet/internet.c [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -943,7 +943,6 @@ APPINFO_SetOption, NULL, NULL, - NULL, NULL };
@@ -1146,11 +1145,7 @@ { TRACE("(%p, 0x%08x)\n", lpdwStatus, dwReserved);
- if (lpdwStatus) { - WARN("always returning LAN connection.\n"); - *lpdwStatus = INTERNET_CONNECTION_LAN; - } - return TRUE; + return InternetGetConnectedStateExW(lpdwStatus, NULL, 0, dwReserved); }
@@ -2149,8 +2144,11 @@ return FALSE; }
- if(hdr->vtbl->ReadFile) - res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead); + if(hdr->vtbl->ReadFile) { + res = hdr->vtbl->ReadFile(hdr, lpBuffer, dwNumOfBytesToRead, pdwNumOfBytesRead, 0, 0); + if(res == ERROR_IO_PENDING) + *pdwNumOfBytesRead = 0; + }
WININET_Release(hdr);
@@ -2208,8 +2206,8 @@ return FALSE; }
- if(hdr->vtbl->ReadFileEx) - res = hdr->vtbl->ReadFileEx(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength, + if(hdr->vtbl->ReadFile) + res = hdr->vtbl->ReadFile(hdr, lpBuffersOut->lpvBuffer, lpBuffersOut->dwBufferLength, &lpBuffersOut->dwBufferLength, dwFlags, dwContext);
WININET_Release(hdr); @@ -2246,8 +2244,8 @@ return FALSE; }
- if(hdr->vtbl->ReadFileEx) - res = hdr->vtbl->ReadFileEx(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength, + if(hdr->vtbl->ReadFile) + res = hdr->vtbl->ReadFile(hdr, lpBuffer->lpvBuffer, lpBuffer->dwBufferLength, &lpBuffer->dwBufferLength, dwFlags, dwContext);
WININET_Release(hdr); @@ -2839,10 +2837,21 @@ FIXME("Option INTERNET_OPTION_DISABLE_AUTODIAL; STUB\n"); break; case INTERNET_OPTION_HTTP_DECODING: - FIXME("INTERNET_OPTION_HTTP_DECODING; STUB\n"); - SetLastError(ERROR_INTERNET_INVALID_OPTION); - ret = FALSE; + { + if (!lpwhh) + { + SetLastError(ERROR_INTERNET_INCORRECT_HANDLE_TYPE); + return FALSE; + } + if (!lpBuffer || dwBufferLength != sizeof(BOOL)) + { + SetLastError(ERROR_INVALID_PARAMETER); + ret = FALSE; + } + else + lpwhh->decoding = *(BOOL *)lpBuffer; break; + } case INTERNET_OPTION_COOKIES_3RD_PARTY: FIXME("INTERNET_OPTION_COOKIES_3RD_PARTY; STUB\n"); SetLastError(ERROR_INTERNET_INVALID_OPTION); @@ -3458,7 +3467,9 @@ if(!InternetCrackUrlW(lpszUrl, strlenW(lpszUrl), 0, &urlComponents)) return NULL;
- if(urlComponents.nScheme == INTERNET_SCHEME_HTTP && urlComponents.dwExtraInfoLength) { + if ((urlComponents.nScheme == INTERNET_SCHEME_HTTP || urlComponents.nScheme == INTERNET_SCHEME_HTTPS) && + urlComponents.dwExtraInfoLength) + { assert(urlComponents.lpszUrlPath + urlComponents.dwUrlPathLength == urlComponents.lpszExtraInfo); urlComponents.dwUrlPathLength += urlComponents.dwExtraInfoLength; }
Modified: trunk/reactos/dll/win32/wininet/internet.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/wininet/internet.... ============================================================================== --- trunk/reactos/dll/win32/wininet/internet.h [iso-8859-1] (original) +++ trunk/reactos/dll/win32/wininet/internet.h [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -336,8 +336,7 @@ void (*CloseConnection)(object_header_t*); DWORD (*QueryOption)(object_header_t*,DWORD,void*,DWORD*,BOOL); DWORD (*SetOption)(object_header_t*,DWORD,void*,DWORD); - DWORD (*ReadFile)(object_header_t*,void*,DWORD,DWORD*); - DWORD (*ReadFileEx)(object_header_t*,void*,DWORD,DWORD*,DWORD,DWORD_PTR); + 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); DWORD (*FindNextFileW)(object_header_t*,void*); @@ -358,6 +357,7 @@ ULONG ErrorMask; DWORD dwInternalFlags; LONG refs; + BOOL decoding; INTERNET_STATUS_CALLBACK lpfnStatusCB; struct list entry; struct list children; @@ -454,7 +454,6 @@ DWORD read_size; /* valid data size in read_buf */ BYTE read_buf[READ_BUFFER_SIZE]; /* buffer for already read but not returned data */
- BOOL decoding; data_stream_t *data_stream; netconn_stream_t netconn_stream; } http_request_t; @@ -512,7 +511,6 @@ DWORD NETCON_send(netconn_t *connection, const void *msg, size_t len, int flags, int *sent /* out */) DECLSPEC_HIDDEN; DWORD NETCON_recv(netconn_t*,void*,size_t,BOOL,int*) DECLSPEC_HIDDEN; -BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available) DECLSPEC_HIDDEN; BOOL NETCON_is_alive(netconn_t*) DECLSPEC_HIDDEN; LPCVOID NETCON_GetCert(netconn_t *connection) DECLSPEC_HIDDEN; int NETCON_GetCipherStrength(netconn_t*) DECLSPEC_HIDDEN;
Modified: trunk/reactos/dll/win32/wininet/netconnection.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/wininet/netconnec... ============================================================================== --- trunk/reactos/dll/win32/wininet/netconnection.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/wininet/netconnection.c [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -862,32 +862,6 @@ } }
-/****************************************************************************** - * NETCON_query_data_available - * Returns the number of bytes of peeked data plus the number of bytes of - * queued, but unread data. - */ -BOOL NETCON_query_data_available(netconn_t *connection, DWORD *available) -{ - *available = 0; - - if(!connection->secure) - { - ULONG unread; - int retval = ioctlsocket(connection->socket, FIONREAD, &unread); - if (!retval) - { - TRACE("%d bytes of queued, but unread data\n", unread); - *available += unread; - } - } - else - { - *available = connection->peek_len; - } - return TRUE; -} - BOOL NETCON_is_alive(netconn_t *netconn) { int len;
Modified: trunk/reactos/dll/win32/wininet/wininet.spec URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/wininet/wininet.s... ============================================================================== --- trunk/reactos/dll/win32/wininet/wininet.spec [iso-8859-1] (original) +++ trunk/reactos/dll/win32/wininet/wininet.spec [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -53,8 +53,8 @@ @ stub ForceNexusLookupExW @ stdcall FreeUrlCacheSpaceA(str long long) @ stdcall FreeUrlCacheSpaceW(wstr long long) -@ stdcall FtpCommandA(long long long str ptr ptr) -@ stdcall FtpCommandW(long long long wstr ptr ptr) +@ stdcall FtpCommandA(long long long str long ptr) +@ stdcall FtpCommandW(long long long wstr long ptr) @ stdcall FtpCreateDirectoryA(ptr str) @ stdcall FtpCreateDirectoryW(ptr wstr) @ stdcall FtpDeleteFileA(ptr str) @@ -119,8 +119,8 @@ @ stdcall InternetAutodialHangup(long) @ stdcall InternetCanonicalizeUrlA(str ptr ptr long) @ stdcall InternetCanonicalizeUrlW(wstr ptr ptr long) -@ stdcall InternetCheckConnectionA(ptr long long) -@ stdcall InternetCheckConnectionW(ptr long long) +@ stdcall InternetCheckConnectionA(str long long) +@ stdcall InternetCheckConnectionW(wstr long long) @ stdcall InternetClearAllPerSiteCookieDecisions() @ stdcall InternetCloseHandle(long) @ stdcall InternetCombineUrlA(str str str ptr long) @@ -150,10 +150,10 @@ @ stdcall InternetGetConnectedStateEx(ptr ptr long long) InternetGetConnectedStateExA @ stdcall InternetGetConnectedStateExA(ptr ptr long long) @ stdcall InternetGetConnectedStateExW(ptr ptr long long) -@ stdcall InternetGetCookieA(str str ptr long) +@ stdcall InternetGetCookieA(str str ptr ptr) @ stdcall InternetGetCookieExA(str str ptr ptr long ptr) @ stdcall InternetGetCookieExW(wstr wstr ptr ptr long ptr) -@ stdcall InternetGetCookieW(wstr wstr ptr long) +@ stdcall InternetGetCookieW(wstr wstr ptr ptr) @ stdcall InternetGetLastResponseInfoA(ptr ptr ptr) @ stdcall InternetGetLastResponseInfoW(ptr ptr ptr) @ stdcall InternetGetPerSiteCookieDecisionA(str ptr) @@ -183,8 +183,8 @@ @ stub InternetSecurityProtocolToStringW @ stub InternetServerPushParse @ stdcall InternetSetCookieA(str str str) -@ stdcall InternetSetCookieExA(str str str long ptr) -@ stdcall InternetSetCookieExW(wstr wstr wstr long ptr) +@ stdcall InternetSetCookieExA(str str str long long) +@ stdcall InternetSetCookieExW(wstr wstr wstr long long) @ stdcall InternetSetCookieW(wstr wstr wstr) @ stub InternetSetDialState @ stub InternetSetDialStateA
Modified: trunk/reactos/media/doc/README.WINE URL: http://svn.reactos.org/svn/reactos/trunk/reactos/media/doc/README.WINE?rev=7... ============================================================================== --- trunk/reactos/media/doc/README.WINE [iso-8859-1] (original) +++ trunk/reactos/media/doc/README.WINE [iso-8859-1] Sun Jun 4 01:48:55 2017 @@ -201,7 +201,7 @@ reactos/dll/win32/winemp3.acm # Synced to WineStaging-2.2 reactos/dll/win32/wing32 # Synced to WineStaging-1.9.11 reactos/dll/win32/winhttp # Synced to WineStaging-2.9 -reactos/dll/win32/wininet # Synced to WineStaging-2.2 +reactos/dll/win32/wininet # Synced to WineStaging-2.9 reactos/dll/win32/winmm # Forked at Wine-20050628 reactos/dll/win32/winmm/midimap # Forked at Wine-20050628 reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628