From c927336c5a5da95efe6159c689b91b71ac5b6457 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Thu, 3 Apr 2014 17:34:25 +0400 Subject: [PATCH] scrrun: Implement ReadAll(). --- dlls/scrrun/filesystem.c | 119 +++++++++++++++++++++++--- dlls/scrrun/scrrun.idl | 1 + dlls/scrrun/tests/filesystem.c | 149 ++++++++++++++++++++++++++++++++- dlls/scrrun/tests/scrrun.idl | 1 + 4 files changed, 256 insertions(+), 14 deletions(-) diff --git a/dlls/scrrun/filesystem.c b/dlls/scrrun/filesystem.c index cd0ec2b86c1..20eac0b1629 100644 --- a/dlls/scrrun/filesystem.c +++ b/dlls/scrrun/filesystem.c @@ -37,6 +37,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(scrrun); static const WCHAR bsW[] = {'\\',0}; +static const WCHAR utf16bom = 0xfeff; struct foldercollection { IFolderCollection IFolderCollection_iface; @@ -110,7 +111,7 @@ struct textstream { IOMode mode; BOOL unicode; - BOOL first_write; + BOOL first_read; LARGE_INTEGER size; HANDLE file; }; @@ -374,23 +375,114 @@ static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text) static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text) { struct textstream *This = impl_from_ITextStream(iface); + VARIANT_BOOL eos; + HRESULT hr; + FIXME("(%p)->(%p): stub\n", This, text); + if (!text) + return E_POINTER; + + *text = NULL; if (textstream_check_iomode(This, IORead)) return CTL_E_BADFILEMODE; + /* check for EOF */ + hr = ITextStream_get_AtEndOfStream(iface, &eos); + if (FAILED(hr)) + return hr; + + if (eos == VARIANT_TRUE) + return CTL_E_ENDOFFILE; + return E_NOTIMPL; } static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text) { struct textstream *This = impl_from_ITextStream(iface); - FIXME("(%p)->(%p): stub\n", This, text); + LARGE_INTEGER start, end, dist; + DWORD toread, read; + HRESULT hr; + char *buff; + BOOL ret; + TRACE("(%p)->(%p)\n", This, text); + + if (!text) + return E_POINTER; + + *text = NULL; if (textstream_check_iomode(This, IORead)) return CTL_E_BADFILEMODE; - return E_NOTIMPL; + if (!This->first_read) { + VARIANT_BOOL eos; + + /* check for EOF */ + hr = ITextStream_get_AtEndOfStream(iface, &eos); + if (FAILED(hr)) + return hr; + + if (eos == VARIANT_TRUE) + return CTL_E_ENDOFFILE; + } + + /* read everything from current position */ + dist.QuadPart = 0; + SetFilePointerEx(This->file, dist, &start, FILE_CURRENT); + SetFilePointerEx(This->file, dist, &end, FILE_END); + toread = end.QuadPart - start.QuadPart; + /* rewind back */ + dist.QuadPart = start.QuadPart; + SetFilePointerEx(This->file, dist, NULL, FILE_BEGIN); + + This->first_read = FALSE; + + if (toread == 0) { + *text = SysAllocStringLen(NULL, 0); + return *text ? S_FALSE : E_OUTOFMEMORY; + } + + if (toread < sizeof(WCHAR)) + return CTL_E_ENDOFFILE; + + buff = heap_alloc(toread); + if (!buff) + return E_OUTOFMEMORY; + + ret = ReadFile(This->file, buff, toread, &read, NULL); + if (!ret || toread != read) { + WARN("failed to read from file %d, %d, error %d\n", read, toread, GetLastError()); + heap_free(buff); + return E_FAIL; + } + + hr = S_FALSE; + + if (This->unicode) { + int i = 0; + + /* skip BOM */ + if (start.QuadPart == 0 && *(WCHAR*)buff == utf16bom) { + read -= sizeof(WCHAR); + i += sizeof(WCHAR); + } + + *text = SysAllocStringLen(read ? (WCHAR*)&buff[i] : NULL, read/sizeof(WCHAR)); + if (!*text) hr = E_OUTOFMEMORY; + } + else { + INT len = MultiByteToWideChar(CP_ACP, 0, buff, read, NULL, 0); + *text = SysAllocStringLen(NULL, len); + if (*text) + MultiByteToWideChar(CP_ACP, 0, buff, read, *text, len); + else + hr = E_OUTOFMEMORY; + } + heap_free(buff); + + return hr; } static HRESULT textstream_writestr(struct textstream *stream, BSTR text) @@ -399,15 +491,6 @@ static HRESULT textstream_writestr(struct textstream *stream, BSTR text) BOOL ret; if (stream->unicode) { - if (stream->first_write) { - static const WCHAR utf16bom = 0xfeff; - DWORD written = 0; - BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL); - if (!ret || written != sizeof(utf16bom)) - return create_error(GetLastError()); - stream->first_write = FALSE; - } - ret = WriteFile(stream->file, text, SysStringByteLen(text), &written, NULL); return (ret && written == SysStringByteLen(text)) ? S_OK : create_error(GetLastError()); } else { @@ -555,7 +638,7 @@ static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMod stream->ref = 1; stream->mode = mode; stream->unicode = unicode; - stream->first_write = TRUE; + stream->first_read = TRUE; stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL); if (stream->file == INVALID_HANDLE_VALUE) @@ -570,6 +653,16 @@ static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMod else stream->size.QuadPart = 0; + /* Write Unicode BOM */ + if (unicode && mode == ForWriting && (disposition == CREATE_ALWAYS || disposition == CREATE_NEW)) { + DWORD written = 0; + BOOL ret = WriteFile(stream->file, &utf16bom, sizeof(utf16bom), &written, NULL); + if (!ret || written != sizeof(utf16bom)) { + ITextStream_Release(&stream->ITextStream_iface); + return create_error(GetLastError()); + } + } + *ret = &stream->ITextStream_iface; return S_OK; } diff --git a/dlls/scrrun/scrrun.idl b/dlls/scrrun/scrrun.idl index 5571e77ef0a..53125ee619a 100644 --- a/dlls/scrrun/scrrun.idl +++ b/dlls/scrrun/scrrun.idl @@ -27,6 +27,7 @@ cpp_quote("#undef CopyFile") cpp_quote("#undef DeleteFile") cpp_quote("#undef MoveFile") cpp_quote("#endif") +cpp_quote("#define CTL_E_ENDOFFILE STD_CTL_SCODE(62)") /* this is not defined in public headers */ [ uuid(420B2830-E718-11CF-893D-00A0C9054228), diff --git a/dlls/scrrun/tests/filesystem.c b/dlls/scrrun/tests/filesystem.c index d947d15c26e..96b1b64bc29 100644 --- a/dlls/scrrun/tests/filesystem.c +++ b/dlls/scrrun/tests/filesystem.c @@ -40,6 +40,8 @@ static inline ULONG get_refcount(IUnknown *iface) return IUnknown_Release(iface); } +static const WCHAR crlfW[] = {'\r','\n',0}; + #define GET_REFCOUNT(iface) \ get_refcount((IUnknown*)iface) @@ -1293,6 +1295,7 @@ static void test_CreateTextFile(void) { static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0}; static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0}; + static const WCHAR bomAW[] = {0xff,0xfe,0}; WCHAR pathW[MAX_PATH], dirW[MAX_PATH]; ITextStream *stream; BSTR nameW, str; @@ -1335,6 +1338,19 @@ static void test_CreateTextFile(void) ok(hr == S_OK, "got 0x%08x\n", hr); ITextStream_Release(stream); + /* overwrite in Unicode mode, check for BOM */ + hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_TRUE, VARIANT_TRUE, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + ITextStream_Release(stream); + + hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateFalse, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + hr = ITextStream_ReadAll(stream, &str); + ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr); + ok(!lstrcmpW(str, bomAW), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + ITextStream_Release(stream); + DeleteFileW(nameW); RemoveDirectoryW(dirW); SysFreeString(nameW); @@ -1344,7 +1360,6 @@ static void test_WriteLine(void) { static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0}; static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0}; - static const WCHAR crlfW[] = {'\r','\n',0}; WCHAR pathW[MAX_PATH], dirW[MAX_PATH]; WCHAR buffW[MAX_PATH], buff2W[MAX_PATH]; char buffA[MAX_PATH]; @@ -1415,6 +1430,137 @@ static void test_WriteLine(void) SysFreeString(nameW); } +static void test_ReadAll(void) +{ + static const WCHAR scrrunW[] = {'s','c','r','r','u','n','\\',0}; + static const WCHAR testfileW[] = {'t','e','s','t','.','t','x','t',0}; + static const WCHAR secondlineW[] = {'s','e','c','o','n','d',0}; + static const WCHAR aW[] = {'A',0}; + WCHAR pathW[MAX_PATH], dirW[MAX_PATH], buffW[500]; + ITextStream *stream; + BSTR nameW; + HRESULT hr; + BOOL ret; + BSTR str; + + GetTempPathW(sizeof(pathW)/sizeof(WCHAR), pathW); + lstrcatW(pathW, scrrunW); + lstrcpyW(dirW, pathW); + lstrcatW(pathW, testfileW); + + ret = CreateDirectoryW(dirW, NULL); + ok(ret, "got %d, %d\n", ret, GetLastError()); + + /* Unicode file -> read with ascii stream */ + nameW = SysAllocString(pathW); + hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_FALSE, VARIANT_TRUE, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = ITextStream_WriteLine(stream, nameW); + ok(hr == S_OK, "got 0x%08x\n", hr); + + str = SysAllocString(secondlineW); + hr = ITextStream_WriteLine(stream, str); + ok(hr == S_OK, "got 0x%08x\n", hr); + SysFreeString(str); + + hr = ITextStream_ReadAll(stream, NULL); + ok(hr == E_POINTER, "got 0x%08x\n", hr); + + str = (void*)0xdeadbeef; + hr = ITextStream_ReadAll(stream, &str); + ok(hr == CTL_E_BADFILEMODE, "got 0x%08x\n", hr); + ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str); + + ITextStream_Release(stream); + + hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateFalse, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + hr = ITextStream_ReadAll(stream, NULL); + ok(hr == E_POINTER, "got 0x%08x\n", hr); + + /* Buffer content is not interpreted - BOM is kept, all data is converted to WCHARs */ + str = NULL; + hr = ITextStream_ReadAll(stream, &str); + ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr); + ok(str[0] == 0x00ff && str[1] == 0x00fe, "got %s, %d\n", wine_dbgstr_w(str), SysStringLen(str)); + SysFreeString(str); + ITextStream_Release(stream); + + /* Unicode file -> read with unicode stream */ + hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + lstrcpyW(buffW, nameW); + lstrcatW(buffW, crlfW); + lstrcatW(buffW, secondlineW); + lstrcatW(buffW, crlfW); + str = NULL; + hr = ITextStream_ReadAll(stream, &str); + ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr); + ok(!lstrcmpW(buffW, str), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + + /* ReadAll one more time */ + str = (void*)0xdeadbeef; + hr = ITextStream_ReadAll(stream, &str); + ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr); + ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str); + + /* ReadLine fails the same way */ + str = (void*)0xdeadbeef; + hr = ITextStream_ReadLine(stream, &str); + ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr); + ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str); + ITextStream_Release(stream); + + /* Open again and skip first line before ReadAll */ + hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + str = NULL; + hr = ITextStream_ReadLine(stream, &str); +todo_wine { + ok(hr == S_OK, "got 0x%08x\n", hr); + ok(str != NULL, "got %p\n", str); +} + SysFreeString(str); + + lstrcpyW(buffW, secondlineW); + lstrcatW(buffW, crlfW); + str = NULL; + hr = ITextStream_ReadAll(stream, &str); + ok(hr == S_FALSE || broken(hr == S_OK) /* win2k */, "got 0x%08x\n", hr); +todo_wine + ok(!lstrcmpW(buffW, str), "got %s\n", wine_dbgstr_w(str)); + SysFreeString(str); + ITextStream_Release(stream); + + /* ASCII file, read with Unicode stream */ + /* 1. one byte content, not enough for Unicode read */ + hr = IFileSystem3_CreateTextFile(fs3, nameW, VARIANT_TRUE, VARIANT_FALSE, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + str = SysAllocString(aW); + hr = ITextStream_Write(stream, str); + SysFreeString(str); + ITextStream_Release(stream); + + hr = IFileSystem3_OpenTextFile(fs3, nameW, ForReading, VARIANT_FALSE, TristateTrue, &stream); + ok(hr == S_OK, "got 0x%08x\n", hr); + + str = (void*)0xdeadbeef; + hr = ITextStream_ReadAll(stream, &str); + ok(hr == CTL_E_ENDOFFILE, "got 0x%08x\n", hr); + ok(str == NULL || broken(str == (void*)0xdeadbeef) /* win2k */, "got %p\n", str); + + ITextStream_Release(stream); + + DeleteFileW(nameW); + RemoveDirectoryW(dirW); + SysFreeString(nameW); +} + START_TEST(filesystem) { HRESULT hr; @@ -1445,6 +1591,7 @@ START_TEST(filesystem) test_DriveCollection(); test_CreateTextFile(); test_WriteLine(); + test_ReadAll(); IFileSystem3_Release(fs3); diff --git a/dlls/scrrun/tests/scrrun.idl b/dlls/scrrun/tests/scrrun.idl index 671dbba13c9..96835c7579d 100644 --- a/dlls/scrrun/tests/scrrun.idl +++ b/dlls/scrrun/tests/scrrun.idl @@ -24,6 +24,7 @@ cpp_quote("#undef CopyFile") cpp_quote("#undef DeleteFile") cpp_quote("#undef MoveFile") cpp_quote("#endif") +cpp_quote("#define CTL_E_ENDOFFILE STD_CTL_SCODE(62)") /* this is not defined in public headers */ [ uuid(420B2830-E718-11CF-893D-00A0C9054228),