1 /*
2  * This source file is part of libRocket, the HTML/CSS Interface Middleware
3  *
4  * For the latest information, see http://www.librocket.com
5  *
6  * Copyright (c) 2008-2010 CodePoint Ltd, Shift Technology Ltd
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a copy
9  * of this software and associated documentation files (the "Software"), to deal
10  * in the Software without restriction, including without limitation the rights
11  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12  * copies of the Software, and to permit persons to whom the Software is
13  * furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24  * THE SOFTWARE.
25  *
26  */
27 
28 #include "precompiled.h"
29 #include "../../Include/Rocket/Core/StreamMemory.h"
30 #include <stdio.h>
31 
32 namespace Rocket {
33 namespace Core {
34 
35 const int DEFAULT_BUFFER_SIZE = 256;
36 const int BUFFER_INCREMENTS = 256;
37 
StreamMemory()38 StreamMemory::StreamMemory()
39 {
40 	buffer = NULL;
41 	buffer_ptr = NULL;
42 	buffer_size = 0;
43 	buffer_used = 0;
44 	owns_buffer = true;
45 	Reallocate(DEFAULT_BUFFER_SIZE);
46 }
47 
StreamMemory(size_t initial_size)48 StreamMemory::StreamMemory(size_t initial_size)
49 {
50 	buffer = NULL;
51 	buffer_ptr = NULL;
52 	buffer_size = 0;
53 	buffer_used = 0;
54 	owns_buffer = true;
55 	Reallocate(initial_size);
56 }
57 
StreamMemory(const byte * _buffer,size_t _buffer_size)58 StreamMemory::StreamMemory(const byte* _buffer, size_t _buffer_size)
59 {
60 	buffer = (byte*)_buffer;
61 	buffer_size = _buffer_size;
62 	buffer_used = _buffer_size;
63 	owns_buffer = false;
64 	buffer_ptr = buffer;
65 }
66 
StreamMemory(const StreamMemory & copy)67 StreamMemory::StreamMemory(const StreamMemory& copy) : Stream(copy)
68 {
69 	buffer = NULL;
70 	buffer_ptr = NULL;
71 	buffer_size = 0;
72 	buffer_used = 0;
73 	owns_buffer = true;
74 
75 	// Copy the buffer and pointer offsets
76 	Reallocate( ( ( copy.buffer_used + BUFFER_INCREMENTS ) / BUFFER_INCREMENTS ) * BUFFER_INCREMENTS );
77 	ROCKET_ASSERTMSG(buffer != NULL, "Could not allocate buffer for StreamMemory reader.");
78 	if(buffer != NULL)
79 	{
80 		memcpy( buffer, copy.buffer, copy.buffer_used );
81 		buffer_ptr = buffer + ( copy.buffer_ptr - copy.buffer );
82 	}
83 }
84 
~StreamMemory()85 StreamMemory::~StreamMemory()
86 {
87 	if ( owns_buffer )
88 		free( buffer );
89 }
90 
operator =(const StreamMemory & copy)91 StreamMemory& StreamMemory::operator=( const StreamMemory& copy )
92 {
93 	// Copy the buffer and pointer offsets
94 	Reallocate( ( ( copy.buffer_used + BUFFER_INCREMENTS ) / BUFFER_INCREMENTS ) * BUFFER_INCREMENTS );
95 	memcpy( buffer, copy.buffer, copy.buffer_used );
96 	buffer_ptr = buffer + ( copy.buffer_ptr - copy.buffer );
97 
98 	return *this;
99 }
100 
Close()101 void StreamMemory::Close()
102 {
103 	Stream::Close();
104 }
105 
IsEOS() const106 bool StreamMemory::IsEOS() const
107 {
108 	return buffer_ptr >= buffer + buffer_used;
109 }
110 
111 // Get current offset
Tell() const112 size_t StreamMemory::Tell() const
113 {
114 	return buffer_ptr - buffer;
115 }
116 
Length() const117 size_t StreamMemory::Length() const
118 {
119 	return buffer_used;
120 }
121 
122 // Read bytes from the buffer, advancing the internal pointer
Read(void * _buffer,size_t bytes) const123 size_t StreamMemory::Read(void *_buffer, size_t bytes) const
124 {
125 	bytes = Math::ClampUpper(bytes, (size_t) (buffer + buffer_used - buffer_ptr));
126 
127 	memcpy(_buffer, buffer_ptr, bytes);
128 
129 	buffer_ptr += bytes;
130 
131 	return bytes;
132 }
133 
134 // Read bytes from the buffer, not advancing the internal pointer
Peek(void * _buffer,size_t bytes) const135 size_t StreamMemory::Peek( void *_buffer, size_t bytes ) const
136 {
137 	bytes = Math::ClampUpper(bytes, (size_t) (buffer + buffer_used - buffer_ptr));
138 
139 	memcpy(_buffer, buffer_ptr, bytes);
140 
141 	return bytes;
142 }
143 
144 // Read bytes from the buffer, advancing the internal pointer
Write(const void * _buffer,size_t bytes)145 size_t StreamMemory::Write( const void *_buffer, size_t bytes )
146 {
147 	if ( buffer_ptr + bytes > buffer + buffer_size )
148 		if ( !Reallocate( bytes + BUFFER_INCREMENTS ) )
149 			return 0;
150 
151 	memcpy( buffer_ptr, _buffer, bytes );
152 
153 	buffer_ptr += bytes;
154 	buffer_used = Math::Max( (size_t)(buffer_ptr - buffer), buffer_used );
155 
156 	return bytes;
157 }
158 
159 // Truncate the stream to the specified length
Truncate(size_t bytes)160 size_t StreamMemory::Truncate( size_t bytes )
161 {
162 	if ( bytes > buffer_used )
163 		return 0;
164 
165 	size_t old_size = buffer_used;
166 	buffer_used = bytes;
167 	buffer_ptr = buffer + bytes;
168 	return old_size - buffer_used;
169 }
170 
171 // Set pointer to the specified offset
Seek(long offset,int origin) const172 bool StreamMemory::Seek( long offset, int origin ) const
173 {
174 	byte* new_ptr = NULL;
175 
176 	switch ( origin )
177 	{
178 	case SEEK_SET:
179 		new_ptr = buffer + offset;
180 		break;
181 	case SEEK_END:
182 		new_ptr = buffer + ( buffer_used - offset );
183 		break;
184 	case SEEK_CUR:
185 		new_ptr = buffer_ptr + offset;
186 	}
187 
188 	// Check of overruns
189 	if ( new_ptr < buffer || new_ptr > buffer + buffer_used )
190 		return false;
191 
192 	buffer_ptr = new_ptr;
193 
194 	return true;
195 }
196 
PushFront(const void * _buffer,size_t bytes)197 size_t StreamMemory::PushFront( const void* _buffer, size_t bytes )
198 {
199 	if ( buffer_used + bytes > buffer_size )
200 		if ( !Reallocate( bytes + BUFFER_INCREMENTS ) )
201 			return 0;
202 
203 	memmove( &buffer[ bytes ], &buffer[ 0 ], buffer_used );
204 	memcpy( buffer, _buffer, bytes );
205 	buffer_used += bytes;
206 	buffer_ptr += bytes;
207 	return bytes;
208 }
209 
PopFront(size_t bytes)210 size_t StreamMemory::PopFront( size_t bytes )
211 {
212 	Erase( 0, bytes );
213 	buffer_ptr -= bytes;
214 	buffer_ptr = Math::ClampLower(buffer_ptr, buffer);
215 	return bytes;
216 }
217 
RawStream() const218 const byte* StreamMemory::RawStream() const
219 {
220 	return buffer;
221 }
222 
Erase(size_t offset,size_t bytes)223 void StreamMemory::Erase( size_t offset, size_t bytes )
224 {
225 	bytes = Math::ClampUpper(bytes, buffer_used - offset);
226 	memmove(&buffer[offset], &buffer[offset + bytes], buffer_used - offset - bytes);
227 	buffer_used -= bytes;
228 }
229 
IsReadReady()230 bool StreamMemory::IsReadReady()
231 {
232 	return !IsEOS();
233 }
234 
IsWriteReady()235 bool StreamMemory::IsWriteReady()
236 {
237 	return true;
238 }
239 
SetSourceURL(const URL & url)240 void StreamMemory::SetSourceURL(const URL& url)
241 {
242 	SetStreamDetails(url, Stream::MODE_READ | (owns_buffer ? Stream::MODE_WRITE : 0));
243 }
244 
245 // Resize the buffer
Reallocate(size_t size)246 bool StreamMemory::Reallocate( size_t size )
247 {
248 	ROCKET_ASSERT( owns_buffer );
249 	if ( !owns_buffer )
250 		return false;
251 
252 	byte *new_buffer = (byte*)realloc( buffer, buffer_size + size );
253 	if ( new_buffer == NULL )
254 		return false;
255 
256 	buffer_ptr = new_buffer + ( buffer_ptr - buffer );
257 
258 	buffer = new_buffer;
259 	buffer_size += size;
260 
261 	return true;
262 }
263 
264 }
265 }
266