1 // distribution boxbackup-0.11_trunk_2979 (svn version: 2979)
2 // Box Backup, http://www.boxbackup.org/
3 //
4 // Copyright (c) 2003-2010, Ben Summers and contributors.
5 // All rights reserved.
6 //
7 // Note that this project uses mixed licensing. Any file with this license
8 // attached, or where the code LICENSE-DUAL appears on the first line, falls
9 // under this license. See the file COPYING.txt for more information.
10 //
11 // This file is dual licensed. You may use and distribute it providing that you
12 // comply EITHER with the terms of the BSD license, OR the GPL license. It is
13 // not necessary to comply with both licenses, only one.
14 //
15 // The BSD license option follows:
16 //
17 // Redistribution and use in source and binary forms, with or without
18 // modification, are permitted provided that the following conditions are met:
19 //
20 // 1. Redistributions of source code must retain the above copyright
21 //    notice, this list of conditions and the following disclaimer.
22 //
23 // 2. Redistributions in binary form must reproduce the above copyright
24 //    notice, this list of conditions and the following disclaimer in the
25 //    documentation and/or other materials provided with the distribution.
26 //
27 // 3. Neither the name of the Box Backup nor the names of its contributors may
28 //    be used to endorse or promote products derived from this software without
29 //    specific prior written permission.
30 //
31 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
32 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
33 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
34 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
35 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
36 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
38 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
39 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
40 // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 //
42 // [http://en.wikipedia.org/wiki/BSD_licenses#3-clause_license_.28.22New_BSD_License.22.29]
43 //
44 // The GPL license option follows:
45 //
46 // This program is free software; you can redistribute it and/or
47 // modify it under the terms of the GNU General Public License
48 // as published by the Free Software Foundation; either version 2
49 // of the License, or (at your option) any later version.
50 //
51 // This program is distributed in the hope that it will be useful,
52 // but WITHOUT ANY WARRANTY; without even the implied warranty of
53 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54 // GNU General Public License for more details.
55 //
56 // You should have received a copy of the GNU General Public License
57 // along with this program; if not, write to the Free Software
58 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
59 //
60 // [http://www.gnu.org/licenses/old-licenses/gpl-2.0.html#SEC4]
61 // --------------------------------------------------------------------------
62 //
63 // File
64 //		Name:    CollectInBufferStream.cpp
65 //		Purpose: Collect data in a buffer, and then read it out.
66 //		Created: 2003/08/26
67 //
68 // --------------------------------------------------------------------------
69 
70 #include "Box.h"
71 
72 #include <string.h>
73 
74 #include "CollectInBufferStream.h"
75 #include "CommonException.h"
76 
77 #include "MemLeakFindOn.h"
78 
79 #define INITIAL_BUFFER_SIZE	1024
80 #define MAX_BUFFER_ADDITION	(1024*64)
81 
82 // --------------------------------------------------------------------------
83 //
84 // Function
85 //		Name:    CollectInBufferStream::CollectInBufferStream()
86 //		Purpose: Constructor
87 //		Created: 2003/08/26
88 //
89 // --------------------------------------------------------------------------
CollectInBufferStream()90 CollectInBufferStream::CollectInBufferStream()
91 	: mBuffer(INITIAL_BUFFER_SIZE),
92 	  mBufferSize(INITIAL_BUFFER_SIZE),
93 	  mBytesInBuffer(0),
94 	  mReadPosition(0),
95 	  mInWritePhase(true)
96 {
97 }
98 
99 // --------------------------------------------------------------------------
100 //
101 // Function
102 //		Name:    CollectInBufferStream::~CollectInBufferStream()
103 //		Purpose: Destructor
104 //		Created: 2003/08/26
105 //
106 // --------------------------------------------------------------------------
~CollectInBufferStream()107 CollectInBufferStream::~CollectInBufferStream()
108 {
109 }
110 
111 // --------------------------------------------------------------------------
112 //
113 // Function
114 //		Name:    CollectInBufferStream::Read(void *, int, int)
115 //		Purpose: As interface. But only works in read phase
116 //		Created: 2003/08/26
117 //
118 // --------------------------------------------------------------------------
Read(void * pBuffer,int NBytes,int Timeout)119 int CollectInBufferStream::Read(void *pBuffer, int NBytes, int Timeout)
120 {
121 	if(mInWritePhase != false) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
122 
123 	// Adjust to number of bytes left
124 	if(NBytes > (mBytesInBuffer - mReadPosition))
125 	{
126 		NBytes = (mBytesInBuffer - mReadPosition);
127 	}
128 	ASSERT(NBytes >= 0);
129 	if(NBytes <= 0) return 0;	// careful now
130 
131 	// Copy in the requested number of bytes and adjust the read pointer
132 	::memcpy(pBuffer, ((char*)mBuffer) + mReadPosition, NBytes);
133 	mReadPosition += NBytes;
134 
135 	return NBytes;
136 }
137 
138 // --------------------------------------------------------------------------
139 //
140 // Function
141 //		Name:    CollectInBufferStream::BytesLeftToRead()
142 //		Purpose: As interface. But only works in read phase
143 //		Created: 2003/08/26
144 //
145 // --------------------------------------------------------------------------
BytesLeftToRead()146 IOStream::pos_type CollectInBufferStream::BytesLeftToRead()
147 {
148 	if(mInWritePhase != false) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
149 
150 	return (mBytesInBuffer - mReadPosition);
151 }
152 
153 // --------------------------------------------------------------------------
154 //
155 // Function
156 //		Name:    CollectInBufferStream::Write(void *, int)
157 //		Purpose: As interface. But only works in write phase
158 //		Created: 2003/08/26
159 //
160 // --------------------------------------------------------------------------
Write(const void * pBuffer,int NBytes)161 void CollectInBufferStream::Write(const void *pBuffer, int NBytes)
162 {
163 	if(mInWritePhase != true) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
164 
165 	// Enough space in the buffer
166 	if((mBytesInBuffer + NBytes) > mBufferSize)
167 	{
168 		// Need to reallocate... what's the block size we'll use?
169 		int allocateBlockSize = mBufferSize;
170 		if(allocateBlockSize > MAX_BUFFER_ADDITION)
171 		{
172 			allocateBlockSize = MAX_BUFFER_ADDITION;
173 		}
174 
175 		// Write it the easy way. Although it's not the most efficient...
176 		int newSize = mBufferSize;
177 		while(newSize < (mBytesInBuffer + NBytes))
178 		{
179 			newSize += allocateBlockSize;
180 		}
181 
182 		// Reallocate buffer
183 		mBuffer.Resize(newSize);
184 
185 		// Store new size
186 		mBufferSize = newSize;
187 	}
188 
189 	// Copy in data and adjust counter
190 	::memcpy(((char*)mBuffer) + mBytesInBuffer, pBuffer, NBytes);
191 	mBytesInBuffer += NBytes;
192 }
193 
194 // --------------------------------------------------------------------------
195 //
196 // Function
197 //		Name:    CollectInBufferStream::GetPosition()
198 //		Purpose: In write phase, returns the number of bytes written, in read
199 //				 phase, the number of bytes to go
200 //		Created: 2003/08/26
201 //
202 // --------------------------------------------------------------------------
GetPosition() const203 IOStream::pos_type CollectInBufferStream::GetPosition() const
204 {
205 	return mInWritePhase?mBytesInBuffer:mReadPosition;
206 }
207 
208 // --------------------------------------------------------------------------
209 //
210 // Function
211 //		Name:    CollectInBufferStream::Seek(pos_type, int)
212 //		Purpose: As interface. But read phase only.
213 //		Created: 2003/08/26
214 //
215 // --------------------------------------------------------------------------
Seek(pos_type Offset,int SeekType)216 void CollectInBufferStream::Seek(pos_type Offset, int SeekType)
217 {
218 	if(mInWritePhase != false) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
219 
220 	int newPos = 0;
221 	switch(SeekType)
222 	{
223 	case IOStream::SeekType_Absolute:
224 		newPos = Offset;
225 		break;
226 	case IOStream::SeekType_Relative:
227 		newPos = mReadPosition + Offset;
228 		break;
229 	case IOStream::SeekType_End:
230 		newPos = mBytesInBuffer + Offset;
231 		break;
232 	default:
233 		THROW_EXCEPTION(CommonException, IOStreamBadSeekType)
234 		break;
235 	}
236 
237 	// Make sure it doesn't go over
238 	if(newPos > mBytesInBuffer)
239 	{
240 		newPos = mBytesInBuffer;
241 	}
242 	// or under
243 	if(newPos < 0)
244 	{
245 		newPos = 0;
246 	}
247 
248 	// Set the new read position
249 	mReadPosition = newPos;
250 }
251 
252 // --------------------------------------------------------------------------
253 //
254 // Function
255 //		Name:    CollectInBufferStream::StreamDataLeft()
256 //		Purpose: As interface
257 //		Created: 2003/08/26
258 //
259 // --------------------------------------------------------------------------
StreamDataLeft()260 bool CollectInBufferStream::StreamDataLeft()
261 {
262 	return mInWritePhase?(false):(mReadPosition < mBytesInBuffer);
263 }
264 
265 // --------------------------------------------------------------------------
266 //
267 // Function
268 //		Name:    CollectInBufferStream::StreamClosed()
269 //		Purpose: As interface
270 //		Created: 2003/08/26
271 //
272 // --------------------------------------------------------------------------
StreamClosed()273 bool CollectInBufferStream::StreamClosed()
274 {
275 	return !mInWritePhase;
276 }
277 
278 // --------------------------------------------------------------------------
279 //
280 // Function
281 //		Name:    CollectInBufferStream::SetForReading()
282 //		Purpose: Switch to read phase, after all data written
283 //		Created: 2003/08/26
284 //
285 // --------------------------------------------------------------------------
SetForReading()286 void CollectInBufferStream::SetForReading()
287 {
288 	if(mInWritePhase != true) { THROW_EXCEPTION(CommonException, CollectInBufferStreamNotInCorrectPhase) }
289 
290 	// Move to read phase
291 	mInWritePhase = false;
292 }
293 
294 // --------------------------------------------------------------------------
295 //
296 // Function
297 //		Name:    CollectInBufferStream::GetBuffer()
298 //		Purpose: Returns the buffer
299 //		Created: 2003/09/05
300 //
301 // --------------------------------------------------------------------------
GetBuffer() const302 void *CollectInBufferStream::GetBuffer() const
303 {
304 	return mBuffer.GetPtr();
305 }
306 
307 // --------------------------------------------------------------------------
308 //
309 // Function
310 //		Name:    CollectInBufferStream::GetSize()
311 //		Purpose: Returns the buffer size
312 //		Created: 2003/09/05
313 //
314 // --------------------------------------------------------------------------
GetSize() const315 int CollectInBufferStream::GetSize() const
316 {
317 	return mBytesInBuffer;
318 }
319 
320 // --------------------------------------------------------------------------
321 //
322 // Function
323 //		Name:    CollectInBufferStream::Reset()
324 //		Purpose: Reset the stream, so it is empty and ready to be written to.
325 //		Created: 8/12/03
326 //
327 // --------------------------------------------------------------------------
Reset()328 void CollectInBufferStream::Reset()
329 {
330 	mInWritePhase = true;
331 	mBytesInBuffer = 0;
332 	mReadPosition = 0;
333 }
334 
335