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