1/*
2 * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <BufferedDataIO.h>
8
9#include <new>
10
11#include <stdio.h>
12#include <string.h>
13
14
15//#define TRACE_DATA_IO
16#ifdef TRACE_DATA_IO
17#	define TRACE(x...) printf(x)
18#else
19#	define TRACE(x...) ;
20#endif
21
22
23BBufferedDataIO::BBufferedDataIO(BDataIO& stream, size_t bufferSize,
24	bool ownsStream, bool partialReads)
25	:
26	fStream(stream),
27	fPosition(0),
28	fSize(0),
29	fDirty(false),
30	fOwnsStream(ownsStream),
31	fPartialReads(partialReads)
32{
33	fBufferSize = max_c(bufferSize, 512);
34	fBuffer = new(std::nothrow) uint8[fBufferSize];
35}
36
37
38BBufferedDataIO::~BBufferedDataIO()
39{
40	Flush();
41	delete[] fBuffer;
42
43	if (fOwnsStream)
44		delete &fStream;
45}
46
47
48status_t
49BBufferedDataIO::InitCheck() const
50{
51	return fBuffer == NULL ? B_NO_MEMORY : B_OK;
52}
53
54
55BDataIO*
56BBufferedDataIO::Stream() const
57{
58	return &fStream;
59}
60
61
62size_t
63BBufferedDataIO::BufferSize() const
64{
65	return fBufferSize;
66}
67
68
69bool
70BBufferedDataIO::OwnsStream() const
71{
72	return fOwnsStream;
73}
74
75
76void
77BBufferedDataIO::SetOwnsStream(bool ownsStream)
78{
79	fOwnsStream = ownsStream;
80}
81
82
83status_t
84BBufferedDataIO::Flush()
85{
86	if (!fDirty)
87		return B_OK;
88
89	ssize_t bytesWritten = fStream.Write(fBuffer + fPosition, fSize);
90	if ((size_t)bytesWritten == fSize) {
91		fDirty = false;
92		fPosition = 0;
93		fSize = 0;
94		return B_OK;
95	} else if (bytesWritten >= 0) {
96		fSize -= bytesWritten;
97		fPosition += bytesWritten;
98		return B_ERROR;
99	}
100
101	return bytesWritten;
102}
103
104
105ssize_t
106BBufferedDataIO::Read(void* buffer, size_t size)
107{
108	if (buffer == NULL)
109		return B_BAD_VALUE;
110
111	TRACE("%p::Read(size %lu)\n", this, size);
112
113	size_t bytesRead = 0;
114
115	if (fSize > 0) {
116		// fill the part of the stream we already have
117		bytesRead = min_c(size, fSize);
118		TRACE("%p: read %lu bytes we already have in the buffer.\n", this,
119			bytesRead);
120		memcpy(buffer, fBuffer + fPosition, bytesRead);
121
122		buffer = (void*)((uint8_t*)buffer + bytesRead);
123		size -= bytesRead;
124		fPosition += bytesRead;
125		fSize -= bytesRead;
126
127		if (fPartialReads)
128			return bytesRead;
129	}
130
131	if (size > fBufferSize || fBuffer == NULL) {
132		// request is larger than our buffer, just fill it directly
133		return fStream.Read(buffer, size);
134	}
135
136	if (size > 0) {
137		// retrieve next buffer
138
139		status_t status = Flush();
140		if (status != B_OK)
141			return status;
142
143		TRACE("%p: read %" B_PRIuSIZE " bytes from stream\n", this, fBufferSize);
144		fSize = fStream.Read(fBuffer, fBufferSize);
145		TRACE("%p: retrieved %" B_PRIuSIZE " bytes from stream\n", this, fSize);
146		fPosition = 0;
147
148		// Copy the remaining part
149		size_t copy = min_c(size, fSize);
150		memcpy(buffer, fBuffer, copy);
151		TRACE("%p: copy %" B_PRIuSIZE" bytes to buffer\n", this, copy);
152
153		bytesRead += copy;
154		fPosition = copy;
155		fSize -= copy;
156	}
157
158	return bytesRead;
159}
160
161
162ssize_t
163BBufferedDataIO::Write(const void* buffer, size_t size)
164{
165	if (buffer == NULL)
166		return B_BAD_VALUE;
167
168	TRACE("%p::Write(size %lu)\n", this, size);
169
170	if (!fDirty) {
171		// Throw away a read-only buffer if necessary
172		TRACE("%p: throw away previous buffer.\n", this);
173		fPosition = 0;
174		fSize = 0;
175	}
176
177	size_t bytesWritten = 0;
178
179	if (size > fBufferSize || fBuffer == NULL) {
180		// request is larger than our buffer, just fill it directly
181		bytesWritten = fSize;
182
183		status_t status = Flush();
184		if (status != B_OK)
185			return status;
186
187		ssize_t streamWritten = fStream.Write(buffer, size);
188		if (streamWritten >= 0)
189			return bytesWritten + streamWritten;
190
191		return streamWritten;
192	}
193
194	bytesWritten = min_c(size, fBufferSize - fSize - fPosition);
195	TRACE("%p: write %" B_PRIuSIZE " bytes to the buffer.\n", this,
196		bytesWritten);
197	memcpy(fBuffer + fPosition + fSize, buffer, bytesWritten);
198	fSize += bytesWritten;
199	size -= bytesWritten;
200
201	if (size > 0) {
202		status_t status = Flush();
203		if (status != B_OK)
204			return status;
205
206		memcpy(fBuffer, (uint8*)buffer + bytesWritten, size);
207		fPosition = 0;
208		fSize = size;
209		fDirty = true;
210		bytesWritten += size;
211	}
212
213	return bytesWritten;
214}
215
216
217//	#pragma mark - FBC
218
219
220status_t BBufferedDataIO::_Reserved0(void*) { return B_ERROR; }
221status_t BBufferedDataIO::_Reserved1(void*) { return B_ERROR; }
222status_t BBufferedDataIO::_Reserved2(void*) { return B_ERROR; }
223status_t BBufferedDataIO::_Reserved3(void*) { return B_ERROR; }
224status_t BBufferedDataIO::_Reserved4(void*) { return B_ERROR; }
225