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