xref: /haiku/src/kits/support/BufferedDataIO.cpp (revision f0a016dcb150e1f96b39f6d6a82a5f50c6e6d921)
1 /*
2  * Copyright 2011-2013, 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 
BBufferedDataIO(BDataIO & stream,size_t bufferSize,bool ownsStream,bool partialReads)23 BBufferedDataIO::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 
~BBufferedDataIO()38 BBufferedDataIO::~BBufferedDataIO()
39 {
40 	Flush();
41 	delete[] fBuffer;
42 
43 	if (fOwnsStream)
44 		delete &fStream;
45 }
46 
47 
48 status_t
InitCheck() const49 BBufferedDataIO::InitCheck() const
50 {
51 	return fBuffer == NULL ? B_NO_MEMORY : B_OK;
52 }
53 
54 
55 BDataIO*
Stream() const56 BBufferedDataIO::Stream() const
57 {
58 	return &fStream;
59 }
60 
61 
62 size_t
BufferSize() const63 BBufferedDataIO::BufferSize() const
64 {
65 	return fBufferSize;
66 }
67 
68 
69 bool
OwnsStream() const70 BBufferedDataIO::OwnsStream() const
71 {
72 	return fOwnsStream;
73 }
74 
75 
76 void
SetOwnsStream(bool ownsStream)77 BBufferedDataIO::SetOwnsStream(bool ownsStream)
78 {
79 	fOwnsStream = ownsStream;
80 }
81 
82 
83 status_t
Flush()84 BBufferedDataIO::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_PARTIAL_WRITE;
99 	}
100 
101 	return B_OK;
102 }
103 
104 
105 ssize_t
Read(void * buffer,size_t size)106 BBufferedDataIO::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,
144 			fBufferSize);
145 		ssize_t nextRead = fStream.Read(fBuffer, fBufferSize);
146 		if (nextRead < 0)
147 			return nextRead;
148 
149 		fSize = nextRead;
150 		TRACE("%p: retrieved %" B_PRIuSIZE " bytes from stream\n", this, fSize);
151 		fPosition = 0;
152 
153 		// Copy the remaining part
154 		size_t copy = min_c(size, fSize);
155 		memcpy(buffer, fBuffer, copy);
156 		TRACE("%p: copy %" B_PRIuSIZE" bytes to buffer\n", this, copy);
157 
158 		bytesRead += copy;
159 		fPosition = copy;
160 		fSize -= copy;
161 	}
162 
163 	return bytesRead;
164 }
165 
166 
167 ssize_t
Write(const void * buffer,size_t size)168 BBufferedDataIO::Write(const void* buffer, size_t size)
169 {
170 	if (buffer == NULL)
171 		return B_BAD_VALUE;
172 
173 	TRACE("%p::Write(size %lu)\n", this, size);
174 
175 	if (size > fBufferSize || fBuffer == NULL) {
176 		// request is larger than our buffer, just fill it directly
177 		status_t status = Flush();
178 		if (status != B_OK)
179 			return status;
180 
181 		return fStream.Write(buffer, size);
182 	}
183 
184 	if (!fDirty) {
185 		// Throw away a read-only buffer if necessary
186 		TRACE("%p: throw away previous buffer.\n", this);
187 		fPosition = 0;
188 		fSize = 0;
189 	}
190 
191 	size_t bytesWritten = 0;
192 	while (size > 0) {
193 		size_t toCopy = min_c(size, fBufferSize - (fPosition + fSize));
194 		TRACE("%p: write %" B_PRIuSIZE " bytes to the buffer.\n", this,
195 			toCopy);
196 		memcpy(fBuffer + (fPosition + fSize), buffer, toCopy);
197 		fSize += toCopy;
198 		bytesWritten += toCopy;
199 		size -= toCopy;
200 		fDirty = true;
201 
202 		if ((fPosition + fSize) == fBufferSize) {
203 			status_t status = Flush();
204 			if (status != B_OK)
205 				return bytesWritten;
206 		}
207 	}
208 
209 	return bytesWritten;
210 }
211 
212 
213 //	#pragma mark - FBC
214 
215 
_Reserved0(void *)216 status_t BBufferedDataIO::_Reserved0(void*) { return B_ERROR; }
_Reserved1(void *)217 status_t BBufferedDataIO::_Reserved1(void*) { return B_ERROR; }
_Reserved2(void *)218 status_t BBufferedDataIO::_Reserved2(void*) { return B_ERROR; }
_Reserved3(void *)219 status_t BBufferedDataIO::_Reserved3(void*) { return B_ERROR; }
_Reserved4(void *)220 status_t BBufferedDataIO::_Reserved4(void*) { return B_ERROR; }
221