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