xref: /haiku/src/add-ons/translators/shared/StreamBuffer.cpp (revision a381c8a06378de22ff08adf4282b4e3f7e50d250)
1 /*
2  * Copyright 2003-2008, Haiku, Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors :
6  *		Michael Wilber
7  *		Jérôme Duval
8  */
9 
10 #include <stdio.h>
11 #include <string.h>
12 #include "StreamBuffer.h"
13 
14 #ifndef min
15 #define min(x,y) (((x) < (y)) ? (x) : (y))
16 #endif
17 
18 #ifndef max
19 #define max(x,y) (((x) > (y)) ? (x) : (y))
20 #endif
21 
22 // ---------------------------------------------------------------
23 // Constructor
24 //
25 // Initializes the StreamBuffer to read from pstream, buffering
26 // nbuffersize bytes of data at a time. Note that if nbuffersize
27 // is smaller than MIN_BUFFER_SIZE, MIN_BUFFER_SIZE is used
28 // as the buffer size.
29 //
30 // Preconditions:
31 //
32 // Parameters: pstream,	the stream to be buffered
33 //
34 //             nbuffersize,	number of bytes to be read from
35 //			                pstream at a time
36 //
37 // Postconditions:
38 //
39 // Returns:
40 // ---------------------------------------------------------------
41 StreamBuffer::StreamBuffer(BPositionIO *pstream, size_t nbuffersize, bool toRead)
42 {
43 	fStream = pstream;
44 	fBuffer = NULL;
45 	fBufferSize = 0;
46 	fLen = 0;
47 	fPos = 0;
48 	fToRead = toRead;
49 
50 	if (!pstream)
51 		return;
52 
53 	fBufferSize = max(nbuffersize, MIN_BUFFER_SIZE);
54 	fBuffer = new uint8[fBufferSize];
55 }
56 
57 // ---------------------------------------------------------------
58 // Destructor
59 //
60 // Destroys data allocated for this object
61 //
62 // Preconditions:
63 //
64 // Parameters:
65 //
66 // Postconditions:
67 //
68 // Returns:
69 // ---------------------------------------------------------------
70 StreamBuffer::~StreamBuffer()
71 {
72 	if (!fToRead && fLen > 0)
73 		fStream->Write(fBuffer, fLen);
74 	delete[] fBuffer;
75 	fBuffer = NULL;
76 }
77 
78 // ---------------------------------------------------------------
79 // InitCheck
80 //
81 // Determines whether the constructor failed or not
82 //
83 // Preconditions:
84 //
85 // Parameters:
86 //
87 // Postconditions:
88 //
89 // Returns: B_OK if object has been initialized successfully,
90 // B_ERROR if not
91 // ---------------------------------------------------------------
92 status_t
93 StreamBuffer::InitCheck()
94 {
95 	if (fStream && fBuffer)
96 		return B_OK;
97 	else
98 		return B_ERROR;
99 }
100 
101 // ---------------------------------------------------------------
102 // Read
103 //
104 // Copies up to nbytes of data from the stream into pinto
105 //
106 // Preconditions: ReadStream() must be called once before this
107 // function is called (the constructor does this)
108 //
109 // Parameters:	pinto,	the buffer to be copied to
110 //
111 //				nbytes,	the maximum number of bytes to copy
112 //
113 // Postconditions:
114 //
115 // Returns: the number of bytes successfully read or an
116 // error code returned by BPositionIO::Read()
117 // ---------------------------------------------------------------
118 ssize_t
119 StreamBuffer::Read(void *_pinto, size_t nbytes)
120 {
121 	if (_pinto == NULL)
122 		return B_BAD_VALUE;
123 	if (nbytes == 0)
124 		return 0;
125 
126 	ssize_t result = B_ERROR;
127 	uint8 *pinto = (uint8 *)_pinto;
128 
129 	size_t totalRead = min(nbytes, fLen - fPos);
130 	memcpy(pinto, fBuffer + fPos, totalRead);
131 	fPos += totalRead;
132 	pinto += totalRead;
133 	nbytes -= totalRead;
134 
135 	while (nbytes > 0) {
136 		result = _ReadStream();
137 		if (result <= 0)
138 			return result;
139 		if (result > 0) {
140 			size_t left = min(nbytes, fLen - fPos);
141 			memcpy(pinto, fBuffer + fPos, left);
142 			fPos += left;
143 			pinto += left;
144 			nbytes -= left;
145 			totalRead += left;
146 		}
147 	}
148 
149 	return totalRead;
150 }
151 
152 
153 // ---------------------------------------------------------------
154 // Write
155 //
156 // Copies up to nbytes of data from pinto into the stream
157 //
158 // Parameters:	pinto,	the buffer to be copied from
159 //				nbytes,	the maximum number of bytes to copy
160 //
161 // Returns: the number of bytes successfully read or an
162 // error code returned by BPositionIO::Read()
163 // ---------------------------------------------------------------
164 void
165 StreamBuffer::Write(void *pinto, size_t nbytes)
166 {
167 	if (nbytes < fBufferSize - fLen) {
168 		memcpy(fBuffer + fLen, pinto, nbytes);
169 		fLen += nbytes;
170 	} else {
171 		if (fLen > 0) {
172 			fStream->Write(fBuffer, fLen);
173 			fLen = 0;
174 		}
175 		fStream->Write(pinto, nbytes);
176 	}
177 }
178 
179 
180 // ---------------------------------------------------------------
181 // Seek
182 //
183 // Seeks the stream to the given position. If the seek operation fails,
184 // the read buffer will be reset.
185 //
186 // Preconditions: fBuffer must be allocated and fBufferSize
187 // must be valid
188 //
189 // Parameters:
190 //
191 // Postconditions:
192 //
193 // Returns: the new position
194 // ---------------------------------------------------------------
195 off_t
196 StreamBuffer::Seek(off_t position, uint32 seekMode)
197 {
198 	// just seek in the current buffer if the new position is in it
199 	if (seekMode == SEEK_CUR) {
200 		if (fToRead
201 			&& (fPos + position < fLen)
202 			&& (fPos + position >= 0)) {
203 			fPos += position;
204 			return Position();
205 		} else if (!fToRead
206 			&& (fLen + position < fBufferSize)
207 			&& (fLen + position >= 0)) {
208 			fLen += position;
209 			return Position();
210 		}
211 	}
212 
213 	// flush if something to write
214 	if (!fToRead
215 		&& fLen > 0) {
216 			fStream->Write(fBuffer, fLen);
217 	}
218 
219 	fLen = 0;
220 	fPos = 0;
221 
222 	return fStream->Seek(position, seekMode);
223 }
224 
225 
226 // ---------------------------------------------------------------
227 // Position
228 //
229 // Returns the current position in the stream.
230 //
231 // Preconditions: fBuffer must be allocated and fBufferSize
232 // must be valid
233 //
234 // Parameters:
235 //
236 // Postconditions:
237 //
238 // Returns: the position
239 // ---------------------------------------------------------------
240 off_t
241 StreamBuffer::Position()
242 {
243 	off_t position = fStream->Position();
244 	if (fToRead)
245 		position -= fPos;
246 	else
247 		position += fLen;
248 	return position;
249 }
250 
251 
252 // ---------------------------------------------------------------
253 // _ReadStream
254 //
255 // Fills the stream buffer with data read in from the stream
256 //
257 // Preconditions: fBuffer must be allocated and fBufferSize
258 // must be valid
259 //
260 // Parameters:
261 //
262 // Postconditions:
263 //
264 // Returns: the number of bytes successfully read or an
265 // error code returned by BPositionIO::Read()
266 // ---------------------------------------------------------------
267 ssize_t
268 StreamBuffer::_ReadStream()
269 {
270 	ssize_t len = fStream->Read(fBuffer, fBufferSize);
271 	if (len < 0)
272 		return len;
273 	fLen = len;
274 	fPos = 0;
275 	return fLen;
276 }
277