1 /* A dynamic memory buffer that expands as you write.
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301 USA
22
23 */
24
25 /*
26
27 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
28
29 */
30
31 /*
32 #define DEBUG
33 */
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif /*HAVE_CONFIG_H*/
38 #include <vips/intl.h>
39
40 #include <string.h>
41
42 #include <vips/vips.h>
43
44 /**
45 * vips_dbuf_init:
46 * @dbuf: the buffer
47 *
48 * Initialize @dbuf.
49 */
50 void
vips_dbuf_init(VipsDbuf * dbuf)51 vips_dbuf_init( VipsDbuf *dbuf )
52 {
53 dbuf->data = NULL;
54 dbuf->allocated_size = 0;
55 dbuf->data_size = 0;
56 dbuf->write_point = 0;
57 }
58
59 /**
60 * vips_dbuf_minimum_size:
61 * @dbuf: the buffer
62 * @size: the minimum size
63 *
64 * Make sure @dbuf is at least @size bytes.
65 *
66 * Returns: %FALSE on out of memory, %TRUE otherwise.
67 */
68 gboolean
vips_dbuf_minimum_size(VipsDbuf * dbuf,size_t size)69 vips_dbuf_minimum_size( VipsDbuf *dbuf, size_t size )
70 {
71 if( size > dbuf->allocated_size ) {
72 const size_t new_allocated_size = 3 * (16 + size) / 2;
73
74 unsigned char *new_data;
75
76 if( !(new_data =
77 g_try_realloc( dbuf->data, new_allocated_size )) ) {
78 vips_error( "VipsDbuf", "%s", _( "out of memory" ) );
79 return( FALSE );
80 }
81
82 dbuf->data = new_data;
83 dbuf->allocated_size = new_allocated_size;
84 }
85
86 return( TRUE );
87 }
88
89 /**
90 * vips_dbuf_allocate:
91 * @dbuf: the buffer
92 * @size: the size to allocate
93 *
94 * Make sure @dbuf has at least @size bytes available after the write point.
95 *
96 * Returns: %FALSE on out of memory, %TRUE otherwise.
97 */
98 gboolean
vips_dbuf_allocate(VipsDbuf * dbuf,size_t size)99 vips_dbuf_allocate( VipsDbuf *dbuf, size_t size )
100 {
101 return( vips_dbuf_minimum_size( dbuf, dbuf->write_point + size ) );
102 }
103
104 /**
105 * vips_dbuf_read:
106 * @dbuf: the buffer
107 * @data: read to this area
108 * @size: read up to this many bytes
109 *
110 * Up to @size bytes are read from the buffer and copied to @data. The number
111 * of bytes transferred is returned.
112 *
113 * Returns: the number of bytes transferred.
114 */
115 size_t
vips_dbuf_read(VipsDbuf * dbuf,unsigned char * data,size_t size)116 vips_dbuf_read( VipsDbuf *dbuf, unsigned char *data, size_t size )
117 {
118 const size_t available = dbuf->data_size - dbuf->write_point;
119 const size_t copied = VIPS_MIN( size, available );
120
121 memcpy( data, dbuf->data + dbuf->write_point, copied );
122 dbuf->write_point += copied;
123
124 return( copied );
125 }
126
127 /**
128 * vips_dbuf_get_write:
129 * @dbuf: the buffer
130 * @size: (allow-none): optionally return length in bytes here
131 *
132 * Return a pointer to an area you can write to, return length of area in
133 * @size. Use vips_dbuf_allocate() before this call to set a minimum amount of
134 * space to have available.
135 *
136 * The write point moves to just beyond the returned block. Use
137 * vips_dbuf_seek() to move it back again.
138 *
139 * Returns: (transfer none): start of write area.
140 */
141 unsigned char *
vips_dbuf_get_write(VipsDbuf * dbuf,size_t * size)142 vips_dbuf_get_write( VipsDbuf *dbuf, size_t *size )
143 {
144 unsigned char *write = dbuf->data + dbuf->write_point;
145 const size_t available = dbuf->allocated_size - dbuf->write_point;
146
147 memset( write, 0, available );
148 dbuf->write_point = dbuf->allocated_size;
149 dbuf->data_size = dbuf->allocated_size;
150
151 if( size )
152 *size = available;
153
154 return( write );
155 }
156
157 /**
158 * vips_dbuf_write:
159 * @dbuf: the buffer
160 * @data: the data to write to the buffer
161 * @size: the size of the len to write
162 *
163 * Append @size bytes from @data. @dbuf expands if necessary.
164 *
165 * Returns: %FALSE on out of memory, %TRUE otherwise.
166 */
167 gboolean
vips_dbuf_write(VipsDbuf * dbuf,const unsigned char * data,size_t size)168 vips_dbuf_write( VipsDbuf *dbuf, const unsigned char *data, size_t size )
169 {
170 if( !vips_dbuf_allocate( dbuf, size ) )
171 return( FALSE );
172
173 memcpy( dbuf->data + dbuf->write_point, data, size );
174 dbuf->write_point += size;
175 dbuf->data_size = VIPS_MAX( dbuf->data_size, dbuf->write_point );
176
177 return( TRUE );
178 }
179
180 /**
181 * vips_dbuf_writef:
182 * @dbuf: the buffer
183 * @fmt: <function>printf()</function>-style format string
184 * @...: arguments to format string
185 *
186 * Format the string and write to @dbuf.
187 *
188 * Returns: %FALSE on out of memory, %TRUE otherwise.
189 */
190 gboolean
vips_dbuf_writef(VipsDbuf * dbuf,const char * fmt,...)191 vips_dbuf_writef( VipsDbuf *dbuf, const char *fmt, ... )
192 {
193 va_list ap;
194 char *line;
195
196 va_start( ap, fmt );
197 line = g_strdup_vprintf( fmt, ap );
198 va_end( ap );
199
200 if( vips_dbuf_write( dbuf, (unsigned char *) line, strlen( line ) ) ) {
201 g_free( line );
202 return( FALSE );
203 }
204 g_free( line );
205
206 return( TRUE );
207 }
208
209 /**
210 * vips_dbuf_write_amp:
211 * @dbuf: the buffer
212 * @str: string to write
213 *
214 * Write @str to @dbuf, but escape stuff that xml hates in text. Our
215 * argument string is utf-8.
216 *
217 * XML rules:
218 *
219 * - We must escape &<>
220 * - Don't escape \n, \t, \r
221 * - Do escape the other ASCII codes.
222 *
223 * Returns: %FALSE on out of memory, %TRUE otherwise.
224 */
225 gboolean
vips_dbuf_write_amp(VipsDbuf * dbuf,const char * str)226 vips_dbuf_write_amp( VipsDbuf *dbuf, const char *str )
227 {
228 const char *p;
229
230 for( p = str; *p; p++ )
231 if( *p < 32 &&
232 *p != '\n' &&
233 *p != '\t' &&
234 *p != '\r' ) {
235 /* You'd think we could output "%x;", but xml
236 * 1.0 parsers barf on that. xml 1.1 allows this, but
237 * there are almost no parsers.
238 *
239 * U+2400 onwards are unicode glyphs for the ASCII
240 * control characters, so we can use them -- thanks
241 * electroly.
242 */
243 if( !vips_dbuf_writef( dbuf, "&#x%04x;", 0x2400 + *p ) )
244 return( FALSE );
245 }
246 else if( *p == '<' ) {
247 if( !vips_dbuf_write( dbuf, (guchar *) "<", 4 ) )
248 return( FALSE );
249 }
250 else if( *p == '>' ) {
251 if( !vips_dbuf_write( dbuf, (guchar *) ">", 4 ) )
252 return( FALSE );
253 }
254 else if( *p == '&' ) {
255 if( !vips_dbuf_write( dbuf, (guchar *) "&", 5 ) )
256 return( FALSE );
257 }
258 else {
259 if( !vips_dbuf_write( dbuf, (guchar *) p, 1 ) )
260 return( FALSE );
261 }
262
263 return( TRUE );
264 }
265
266 /**
267 * vips_dbuf_reset:
268 * @dbuf: the buffer
269 *
270 * Reset the buffer to empty. No memory is freed, just the data size and
271 * write point are reset.
272 */
273 void
vips_dbuf_reset(VipsDbuf * dbuf)274 vips_dbuf_reset( VipsDbuf *dbuf )
275 {
276 dbuf->write_point = 0;
277 dbuf->data_size = 0;
278 }
279
280 /**
281 * vips_dbuf_destroy:
282 * @dbuf: the buffer
283 *
284 * Destroy @dbuf. This frees any allocated memory.
285 */
286 void
vips_dbuf_destroy(VipsDbuf * dbuf)287 vips_dbuf_destroy( VipsDbuf *dbuf )
288 {
289 vips_dbuf_reset( dbuf );
290
291 VIPS_FREE( dbuf->data );
292 dbuf->allocated_size = 0;
293 }
294
295 /**
296 * vips_dbuf_seek:
297 * @dbuf: the buffer
298 * @offset: how to move the write point
299 * @whence: from start, from end, from current
300 *
301 * Move the write point. @whence can be %SEEK_SET, %SEEK_CUR, %SEEK_END, with
302 * the usual meaning.
303 */
304 gboolean
vips_dbuf_seek(VipsDbuf * dbuf,off_t offset,int whence)305 vips_dbuf_seek( VipsDbuf *dbuf, off_t offset, int whence )
306 {
307 off_t new_write_point;
308
309 switch( whence ) {
310 case SEEK_SET:
311 new_write_point = offset;
312 break;
313
314 case SEEK_END:
315 new_write_point = dbuf->data_size + offset;
316 break;
317
318 case SEEK_CUR:
319 new_write_point = dbuf->write_point + offset;
320 break;
321
322 default:
323 g_assert( 0 );
324 new_write_point = dbuf->write_point;
325 break;
326 }
327
328 if( new_write_point < 0 ) {
329 vips_error( "VipsDbuf", "%s", "negative seek" );
330 return( FALSE );
331 }
332
333 /* Possibly need to grow the buffer
334 */
335 if( !vips_dbuf_minimum_size( dbuf, new_write_point ) )
336 return( FALSE );
337 dbuf->write_point = new_write_point;
338 if( dbuf->data_size < dbuf->write_point ) {
339 memset( dbuf->data + dbuf->data_size, 0,
340 dbuf->write_point - dbuf->data_size );
341 dbuf->data_size = dbuf->write_point;
342 }
343
344 return( TRUE );
345 }
346
347 /**
348 * vips_dbuf_truncate:
349 * @dbuf: the buffer
350 *
351 * Truncate the data so that it ends at the write point. No memory is freed.
352 */
353 void
vips_dbuf_truncate(VipsDbuf * dbuf)354 vips_dbuf_truncate( VipsDbuf *dbuf )
355 {
356 dbuf->data_size = dbuf->write_point;
357 }
358
359 /**
360 * vips_dbuf_tell:
361 * @dbuf: the buffer
362 *
363 * Returns: the current write point
364 */
365 off_t
vips_dbuf_tell(VipsDbuf * dbuf)366 vips_dbuf_tell( VipsDbuf *dbuf )
367 {
368 return( dbuf->write_point );
369 }
370
371 /**
372 * vips_dbuf_null_terminate:
373 * @dbuf: the buffer
374 *
375 * Make sure the byte after the last data byte is `\0`. This extra byte is not
376 * included in the data size and the write point is not moved.
377 *
378 * This makes it safe to treat the dbuf contents as a C string.
379 *
380 * Returns: %FALSE on out of memory, %TRUE otherwise.
381 */
382 static gboolean
vips_dbuf_null_terminate(VipsDbuf * dbuf)383 vips_dbuf_null_terminate( VipsDbuf *dbuf )
384 {
385 if( !vips_dbuf_minimum_size( dbuf, dbuf->data_size + 1 ) )
386 return( FALSE );
387
388 dbuf->data[dbuf->data_size] = 0;
389
390 return( TRUE );
391 }
392
393 /**
394 * vips_dbuf_steal:
395 * @dbuf: the buffer
396 * @size: (allow-none): optionally return length in bytes here
397 *
398 * Destroy a buffer, but rather than freeing memory, a pointer is returned.
399 * This must be freed with g_free().
400 *
401 * A `\0` is appended, but not included in the character count. This is so the
402 * pointer can be safely treated as a C string.
403 *
404 * Returns: (transfer full): The pointer held by @dbuf.
405 */
406 unsigned char *
vips_dbuf_steal(VipsDbuf * dbuf,size_t * size)407 vips_dbuf_steal( VipsDbuf *dbuf, size_t *size )
408 {
409 unsigned char *data;
410
411 vips_dbuf_null_terminate( dbuf );
412
413 data = dbuf->data;
414
415 if( size )
416 *size = dbuf->data_size;
417
418 dbuf->data = NULL;
419 vips_dbuf_destroy( dbuf );
420
421 return( data );
422 }
423
424 /**
425 * vips_dbuf_string:
426 * @dbuf: the buffer
427 * @size: (allow-none): optionally return length in bytes here
428 *
429 * Return a pointer to @dbuf's internal data.
430 *
431 * A `\0` is appended, but not included in the character count. This is so the
432 * pointer can be safely treated as a C string.
433 *
434 * Returns: (transfer none): The pointer held by @dbuf.
435 */
436 unsigned char *
vips_dbuf_string(VipsDbuf * dbuf,size_t * size)437 vips_dbuf_string( VipsDbuf *dbuf, size_t *size )
438 {
439 vips_dbuf_null_terminate( dbuf );
440
441 if( size )
442 *size = dbuf->data_size;
443
444 return( dbuf->data );
445 }
446
447
448