Commit c80e16ae authored by Jacek Caban's avatar Jacek Caban Committed by Alexandre Julliard

scrrun: Rewrite text stream to use read ahead buffer.

parent 7c29f5a3
......@@ -20,6 +20,7 @@
#include <stdarg.h>
#include <limits.h>
#include <assert.h>
#include "windef.h"
#include "winbase.h"
......@@ -122,9 +123,12 @@ struct textstream {
IOMode mode;
BOOL unicode;
BOOL first_read;
LARGE_INTEGER size;
HANDLE file;
BOOL eof;
WCHAR *read_buf;
size_t read_buf_size;
};
enum iotype {
......@@ -272,6 +276,7 @@ static ULONG WINAPI textstream_Release(ITextStream *iface)
if (!ref)
{
if (This->read_buf_size) heap_free(This->read_buf);
CloseHandle(This->file);
heap_free(This);
}
......@@ -355,7 +360,6 @@ static HRESULT WINAPI textstream_get_Column(ITextStream *iface, LONG *column)
static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_BOOL *eos)
{
struct textstream *This = impl_from_ITextStream(iface);
LARGE_INTEGER pos, dist;
TRACE("(%p)->(%p)\n", This, eos);
......@@ -367,11 +371,7 @@ static HRESULT WINAPI textstream_get_AtEndOfStream(ITextStream *iface, VARIANT_B
return CTL_E_BADFILEMODE;
}
dist.QuadPart = 0;
if (!SetFilePointerEx(This->file, dist, &pos, FILE_CURRENT))
return E_FAIL;
*eos = This->size.QuadPart == pos.QuadPart ? VARIANT_TRUE : VARIANT_FALSE;
*eos = (This->eof && !This->read_buf_size) ? VARIANT_TRUE : VARIANT_FALSE;
return S_OK;
}
......@@ -382,67 +382,89 @@ static HRESULT WINAPI textstream_get_AtEndOfLine(ITextStream *iface, VARIANT_BOO
return E_NOTIMPL;
}
/*
Reads 'toread' bytes from a file, converts if needed
BOM is skipped if 'bof' is set.
*/
static HRESULT textstream_read(struct textstream *stream, LONG toread, BOOL bof, BSTR *text)
static HRESULT append_read_data(struct textstream *stream, const char *buf, size_t buf_size)
{
HRESULT hr = S_OK;
DWORD read;
char *buff;
BOOL ret;
LARGE_INTEGER revert;
size_t len;
WCHAR *new_buf;
if (toread == 0) {
*text = SysAllocStringLen(NULL, 0);
return *text ? S_FALSE : E_OUTOFMEMORY;
revert.QuadPart = 0;
if (stream->unicode)
{
len = buf_size / sizeof(WCHAR);
if (buf_size & 1) revert.QuadPart = -1;
}
else
{
for (len = 0; len < buf_size; len++)
{
if (!IsDBCSLeadByte(buf[len])) continue;
if (len + 1 == buf_size)
{
revert.QuadPart = -1;
buf_size--;
break;
}
len++;
}
len = MultiByteToWideChar(CP_ACP, 0, buf, buf_size, NULL, 0);
}
if (!len)
return S_OK;
if (revert.QuadPart)
SetFilePointerEx(stream->file, revert, NULL, FILE_CURRENT);
if (toread < sizeof(WCHAR))
return CTL_E_ENDOFFILE;
if (!stream->read_buf_size)
new_buf = heap_alloc(len * sizeof(WCHAR));
else
new_buf = heap_realloc(stream->read_buf, (len + stream->read_buf_size) * sizeof(WCHAR));
if (!new_buf) return E_OUTOFMEMORY;
buff = heap_alloc(toread);
if (!buff)
return E_OUTOFMEMORY;
if (stream->unicode)
memcpy(new_buf + stream->read_buf_size, buf, len * sizeof(WCHAR));
else
MultiByteToWideChar(CP_ACP, 0, buf, buf_size, new_buf + stream->read_buf_size, len);
stream->read_buf = new_buf;
stream->read_buf_size += len;
return S_OK;
}
ret = ReadFile(stream->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;
static HRESULT read_more_data(struct textstream *stream)
{
char buf[256];
DWORD read;
if (stream->eof) return S_OK;
if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
{
ITextStream_Release(&stream->ITextStream_iface);
return create_error(GetLastError());
}
if (stream->unicode) {
int i = 0;
stream->eof = read != sizeof(buf);
return append_read_data(stream, buf, read);
}
/* skip BOM */
if (bof && *(WCHAR*)buff == utf16bom) {
read -= sizeof(WCHAR);
i += sizeof(WCHAR);
}
static BOOL read_from_buffer(struct textstream *stream, size_t len, BSTR *ret, size_t skip)
{
assert(len + skip <= stream->read_buf_size);
*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);
if (!(*ret = SysAllocStringLen(stream->read_buf, len))) return FALSE;
return hr;
len += skip;
stream->read_buf_size -= len;
if (stream->read_buf_size)
memmove(stream->read_buf, stream->read_buf + len, stream->read_buf_size * sizeof(WCHAR));
else
heap_free(stream->read_buf);
return TRUE;
}
static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
{
struct textstream *This = impl_from_ITextStream(iface);
LARGE_INTEGER start, end, dist;
DWORD toread;
HRESULT hr;
HRESULT hr = S_OK;
TRACE("(%p)->(%d %p)\n", This, len, text);
......@@ -456,35 +478,22 @@ static HRESULT WINAPI textstream_Read(ITextStream *iface, LONG len, BSTR *text)
if (textstream_check_iomode(This, IORead))
return CTL_E_BADFILEMODE;
if (!This->first_read) {
VARIANT_BOOL eos;
/* check for EOF */
hr = ITextStream_get_AtEndOfStream(iface, &eos);
if (FAILED(hr))
while (!This->eof && len > This->read_buf_size)
{
if (FAILED(hr = read_more_data(This)))
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);
if (This->eof && !This->read_buf_size)
return CTL_E_ENDOFFILE;
This->first_read = FALSE;
if (This->unicode) len *= sizeof(WCHAR);
if (len > This->read_buf_size)
{
len = This->read_buf_size;
hr = S_FALSE;
}
hr = textstream_read(This, min(toread, len), start.QuadPart == 0, text);
if (FAILED(hr))
return hr;
else
return toread <= len ? S_FALSE : S_OK;
return read_from_buffer(This, len, text, 0) ? hr : E_OUTOFMEMORY;
}
static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
......@@ -516,8 +525,6 @@ static HRESULT WINAPI textstream_ReadLine(ITextStream *iface, BSTR *text)
static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
{
struct textstream *This = impl_from_ITextStream(iface);
LARGE_INTEGER start, end, dist;
DWORD toread;
HRESULT hr;
TRACE("(%p)->(%p)\n", This, text);
......@@ -529,31 +536,16 @@ static HRESULT WINAPI textstream_ReadAll(ITextStream *iface, BSTR *text)
if (textstream_check_iomode(This, IORead))
return CTL_E_BADFILEMODE;
if (!This->first_read) {
VARIANT_BOOL eos;
/* check for EOF */
hr = ITextStream_get_AtEndOfStream(iface, &eos);
if (FAILED(hr))
while (!This->eof)
{
if (FAILED(hr = read_more_data(This)))
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 (This->eof && !This->read_buf_size)
return CTL_E_ENDOFFILE;
hr = textstream_read(This, toread, start.QuadPart == 0, text);
return FAILED(hr) ? hr : S_FALSE;
return read_from_buffer(This, This->read_buf_size, text, 0) ? S_FALSE : E_OUTOFMEMORY;
}
static HRESULT textstream_writestr(struct textstream *stream, BSTR text)
......@@ -693,6 +685,7 @@ static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMod
{
struct textstream *stream;
DWORD access = 0;
HRESULT hr;
/* map access mode */
switch (mode)
......@@ -716,7 +709,9 @@ static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMod
stream->ITextStream_iface.lpVtbl = &textstreamvtbl;
stream->ref = 1;
stream->mode = mode;
stream->first_read = TRUE;
stream->eof = FALSE;
stream->read_buf = NULL;
stream->read_buf_size = 0;
stream->file = CreateFileW(filename, access, 0, NULL, disposition, FILE_ATTRIBUTE_NORMAL, NULL);
if (stream->file == INVALID_HANDLE_VALUE)
......@@ -746,24 +741,38 @@ static HRESULT create_textstream(const WCHAR *filename, DWORD disposition, IOMod
}
else
{
if (format == TristateUseDefault)
{
BYTE buf[64];
DWORD read;
BOOL ret;
DWORD read, buf_offset = 0;
BYTE buf[64];
ret = ReadFile(stream->file, buf, sizeof(buf), &read, NULL);
if (!ret) {
if (format == TristateUseDefault || mode == ForReading)
{
if (!ReadFile(stream->file, buf, sizeof(buf), &read, NULL))
{
ITextStream_Release(&stream->ITextStream_iface);
return create_error(GetLastError());
}
}
if (format == TristateUseDefault)
stream->unicode = IsTextUnicode(buf, read, NULL);
if (mode == ForReading) SetFilePointer(stream->file, 0, 0, FILE_BEGIN);
}
else stream->unicode = format != TristateFalse;
else
stream->unicode = format != TristateFalse;
if (mode == ForAppending) SetFilePointer(stream->file, 0, 0, FILE_END);
if (mode == ForReading)
{
if (stream->unicode && read >= 2 && buf[0] == 0xff && buf[1] == 0xfe)
buf_offset += 2; /* skip utf16 BOM */
hr = append_read_data(stream, (const char *)buf + buf_offset, read - buf_offset);
if (FAILED(hr))
{
ITextStream_Release(&stream->ITextStream_iface);
return hr;
}
stream->eof = read != sizeof(buf);
}
else SetFilePointer(stream->file, 0, 0, FILE_END);
}
init_classinfo(&CLSID_TextStream, (IUnknown *)&stream->ITextStream_iface, &stream->classinfo);
......
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