HaikuDepot: notify work status from main window
[haiku.git] / src / kits / support / BufferIO.cpp
blob744f0e31cac89917ef0bf25877cf61be2b0a73b6
1 /*
2 * Copyright 2001-2008 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT license
5 * Authors:
6 * Stefano Ceccherini, burton666@libero.it
7 */
10 #include <BufferIO.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
17 BBufferIO::BBufferIO(BPositionIO* stream, size_t bufferSize, bool ownsStream)
19 fBufferStart(0),
20 fStream(stream),
21 fBuffer(NULL),
22 fBufferUsed(0),
23 fBufferIsDirty(false),
24 fOwnsStream(ownsStream)
27 fBufferSize = max_c(bufferSize, 512);
28 fPosition = stream->Position();
30 // What can we do if this malloc fails ?
31 // I think R5 uses new, but doesn't catch the thrown exception
32 // (if you specify a very big buffer, the application just
33 // terminates with abort).
34 fBuffer = (char*)malloc(fBufferSize);
38 BBufferIO::~BBufferIO()
40 if (fBufferIsDirty) {
41 // Write pending changes to the stream
42 Flush();
45 free(fBuffer);
47 if (fOwnsStream)
48 delete fStream;
52 ssize_t
53 BBufferIO::ReadAt(off_t pos, void* buffer, size_t size)
55 // We refuse to crash, even if
56 // you were lazy and didn't give a valid
57 // stream on construction.
58 if (fStream == NULL)
59 return B_NO_INIT;
60 if (buffer == NULL)
61 return B_BAD_VALUE;
63 // If the amount of data we want doesn't fit in the buffer, just
64 // read it directly from the disk (and don't touch the buffer).
65 if (size > fBufferSize || fBuffer == NULL) {
66 if (fBufferIsDirty)
67 Flush();
68 return fStream->ReadAt(pos, buffer, size);
71 // If the data we are looking for is not in the buffer...
72 if (size > fBufferUsed
73 || pos < fBufferStart
74 || pos > fBufferStart + (off_t)fBufferUsed
75 || pos + size > fBufferStart + fBufferUsed) {
76 if (fBufferIsDirty) {
77 // If there are pending writes, do them.
78 Flush();
81 // ...cache as much as we can from the stream
82 ssize_t sizeRead = fStream->ReadAt(pos, fBuffer, fBufferSize);
83 if (sizeRead < 0)
84 return sizeRead;
86 fBufferUsed = sizeRead;
87 if (fBufferUsed > 0) {
88 // The data is buffered starting from this offset
89 fBufferStart = pos;
93 size = min_c(size, fBufferUsed);
95 // copy data from the cache to the given buffer
96 memcpy(buffer, fBuffer + pos - fBufferStart, size);
98 return size;
102 ssize_t
103 BBufferIO::WriteAt(off_t pos, const void* buffer, size_t size)
105 if (fStream == NULL)
106 return B_NO_INIT;
107 if (buffer == NULL)
108 return B_BAD_VALUE;
110 // If data doesn't fit into the buffer, write it directly to the stream
111 if (size > fBufferSize || fBuffer == NULL)
112 return fStream->WriteAt(pos, buffer, size);
114 // If we have cached data in the buffer, whose offset into the stream
115 // is > 0, and the buffer isn't dirty, drop the data.
116 if (!fBufferIsDirty && fBufferStart > pos) {
117 fBufferStart = 0;
118 fBufferUsed = 0;
121 // If we want to write beyond the cached data...
122 if (pos > fBufferStart + (off_t)fBufferUsed
123 || pos < fBufferStart) {
124 ssize_t read;
125 off_t where = pos;
127 // Can we just cache from the beginning?
128 if (pos + size <= fBufferSize)
129 where = 0;
131 // ...cache more.
132 read = fStream->ReadAt(where, fBuffer, fBufferSize);
133 if (read > 0) {
134 fBufferUsed = read;
135 fBufferStart = where;
139 memcpy(fBuffer + pos - fBufferStart, buffer, size);
141 fBufferIsDirty = true;
142 fBufferUsed = max_c((size + pos), fBufferUsed);
144 return size;
148 off_t
149 BBufferIO::Seek(off_t position, uint32 seekMode)
151 if (fStream == NULL)
152 return B_NO_INIT;
154 off_t newPosition = fPosition;
156 switch (seekMode) {
157 case SEEK_CUR:
158 newPosition += position;
159 break;
160 case SEEK_SET:
161 newPosition = position;
162 break;
163 case SEEK_END:
165 off_t size;
166 status_t status = fStream->GetSize(&size);
167 if (status != B_OK)
168 return status;
170 newPosition = size - position;
171 break;
175 if (newPosition < 0)
176 return B_BAD_VALUE;
178 fPosition = newPosition;
179 return newPosition;
183 off_t
184 BBufferIO::Position() const
186 return fPosition;
190 status_t
191 BBufferIO::SetSize(off_t size)
193 if (fStream == NULL)
194 return B_NO_INIT;
196 return fStream->SetSize(size);
200 status_t
201 BBufferIO::Flush()
203 if (!fBufferIsDirty)
204 return B_OK;
206 // Write the cached data to the stream
207 ssize_t bytesWritten = fStream->WriteAt(fBufferStart, fBuffer, fBufferUsed);
208 if (bytesWritten > 0)
209 fBufferIsDirty = false;
211 return (bytesWritten < 0) ? bytesWritten : B_OK;
215 BPositionIO*
216 BBufferIO::Stream() const
218 return fStream;
222 size_t
223 BBufferIO::BufferSize() const
225 return fBufferSize;
229 bool
230 BBufferIO::OwnsStream() const
232 return fOwnsStream;
236 void
237 BBufferIO::SetOwnsStream(bool ownsStream)
239 fOwnsStream = ownsStream;
243 void
244 BBufferIO::PrintToStream() const
246 printf("stream %p\n", fStream);
247 printf("buffer %p\n", fBuffer);
248 printf("start %" B_PRId64 "\n", fBufferStart);
249 printf("used %ld\n", fBufferUsed);
250 printf("phys %ld\n", fBufferSize);
251 printf("dirty %s\n", (fBufferIsDirty) ? "true" : "false");
252 printf("owns %s\n", (fOwnsStream) ? "true" : "false");
256 // #pragma mark - FBC padding
259 // These functions are here to maintain future binary
260 // compatibility.
261 status_t BBufferIO::_Reserved_BufferIO_0(void*) { return B_ERROR; }
262 status_t BBufferIO::_Reserved_BufferIO_1(void*) { return B_ERROR; }
263 status_t BBufferIO::_Reserved_BufferIO_2(void*) { return B_ERROR; }
264 status_t BBufferIO::_Reserved_BufferIO_3(void*) { return B_ERROR; }
265 status_t BBufferIO::_Reserved_BufferIO_4(void*) { return B_ERROR; }