1#include "fitz-imp.h"
2
3#include <string.h>
4#include <stdarg.h>
5
6fz_buffer *
7fz_new_buffer(fz_context *ctx, size_t size)
8{
9 fz_buffer *b;
10
11 size = size > 1 ? size : 16;
12
13 b = fz_malloc_struct(ctx, fz_buffer);
14 b->refs = 1;
15 fz_try(ctx)
16 {
17 b->data = fz_malloc(ctx, size);
18 }
19 fz_catch(ctx)
20 {
21 fz_free(ctx, b);
22 fz_rethrow(ctx);
23 }
24 b->cap = size;
25 b->len = 0;
26 b->unused_bits = 0;
27
28 return b;
29}
30
31/*
32 Create a new buffer with existing data.
33
34 data: Pointer to existing data.
35 size: Size of existing data.
36
37 Takes ownership of data. Does not make a copy. Calls fz_free on the
38 data when the buffer is deallocated. Do not use 'data' after passing
39 to this function.
40
41 Returns pointer to new buffer. Throws exception on allocation
42 failure.
43*/
44fz_buffer *
45fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, size_t size)
46{
47 fz_buffer *b = NULL;
48
49 fz_try(ctx)
50 {
51 b = fz_malloc_struct(ctx, fz_buffer);
52 b->refs = 1;
53 b->data = data;
54 b->cap = size;
55 b->len = size;
56 b->unused_bits = 0;
57 }
58 fz_catch(ctx)
59 {
60 fz_free(ctx, data);
61 fz_rethrow(ctx);
62 }
63
64 return b;
65}
66
67/*
68 Like fz_new_buffer, but does not take ownership.
69*/
70fz_buffer *
71fz_new_buffer_from_shared_data(fz_context *ctx, const unsigned char *data, size_t size)
72{
73 fz_buffer *b;
74
75 b = fz_malloc_struct(ctx, fz_buffer);
76 b->refs = 1;
77 b->data = (unsigned char *)data; /* cast away const */
78 b->cap = size;
79 b->len = size;
80 b->unused_bits = 0;
81 b->shared = 1;
82
83 return b;
84}
85
86/*
87 Create a new buffer containing a copy of the passed data.
88*/
89fz_buffer *
90fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size)
91{
92 fz_buffer *b = fz_new_buffer(ctx, size);
93 b->len = size;
94 memcpy(b->data, data, size);
95 return b;
96}
97
98/*
99 Create a new buffer with data decoded from a base64 input string.
100*/
101fz_buffer *
102fz_new_buffer_from_base64(fz_context *ctx, const char *data, size_t size)
103{
104 fz_buffer *buf = fz_new_buffer(ctx, size);
105 const char *end = data + (size > 0 ? size : strlen(data));
106 const char *s = data;
107 fz_try(ctx)
108 {
109 while (s < end)
110 {
111 int c = *s++;
112 if (c >= 'A' && c <= 'Z')
113 fz_append_bits(ctx, buf, c - 'A', 6);
114 else if (c >= 'a' && c <= 'z')
115 fz_append_bits(ctx, buf, c - 'a' + 26, 6);
116 else if (c >= '0' && c <= '9')
117 fz_append_bits(ctx, buf, c - '0' + 52, 6);
118 else if (c == '+')
119 fz_append_bits(ctx, buf, 62, 6);
120 else if (c == '/')
121 fz_append_bits(ctx, buf, 63, 6);
122 }
123 }
124 fz_catch(ctx)
125 {
126 fz_drop_buffer(ctx, buf);
127 fz_rethrow(ctx);
128 }
129 return buf;
130}
131
132fz_buffer *
133fz_keep_buffer(fz_context *ctx, fz_buffer *buf)
134{
135 return fz_keep_imp(ctx, buf, &buf->refs);
136}
137
138void
139fz_drop_buffer(fz_context *ctx, fz_buffer *buf)
140{
141 if (fz_drop_imp(ctx, buf, &buf->refs))
142 {
143 if (!buf->shared)
144 fz_free(ctx, buf->data);
145 fz_free(ctx, buf);
146 }
147}
148
149/*
150 Ensure that a buffer has a given capacity,
151 truncating data if required.
152
153 capacity: The desired capacity for the buffer. If the current size
154 of the buffer contents is smaller than capacity, it is truncated.
155*/
156void
157fz_resize_buffer(fz_context *ctx, fz_buffer *buf, size_t size)
158{
159 if (buf->shared)
160 fz_throw(ctx, FZ_ERROR_GENERIC, "cannot resize a buffer with shared storage");
161 buf->data = fz_realloc(ctx, buf->data, size);
162 buf->cap = size;
163 if (buf->len > buf->cap)
164 buf->len = buf->cap;
165}
166
167/*
168 Make some space within a buffer (i.e. ensure that
169 capacity > size).
170*/
171void
172fz_grow_buffer(fz_context *ctx, fz_buffer *buf)
173{
174 size_t newsize = (buf->cap * 3) / 2;
175 if (newsize == 0)
176 newsize = 256;
177 fz_resize_buffer(ctx, buf, newsize);
178}
179
180static void
181fz_ensure_buffer(fz_context *ctx, fz_buffer *buf, size_t min)
182{
183 size_t newsize = buf->cap;
184 if (newsize < 16)
185 newsize = 16;
186 while (newsize < min)
187 {
188 newsize = (newsize * 3) / 2;
189 }
190 fz_resize_buffer(ctx, buf, newsize);
191}
192
193/*
194 Trim wasted capacity from a buffer by resizing internal memory.
195*/
196void
197fz_trim_buffer(fz_context *ctx, fz_buffer *buf)
198{
199 if (buf->cap > buf->len+1)
200 fz_resize_buffer(ctx, buf, buf->len);
201}
202
203void
204fz_clear_buffer(fz_context *ctx, fz_buffer *buf)
205{
206 buf->len = 0;
207}
208
209/*
210 Zero-terminate buffer in order to use as a C string.
211
212 This byte is invisible and does not affect the length of the buffer as returned by fz_buffer_storage.
213 The zero byte is written *after* the data, and subsequent writes will overwrite the terminating byte.
214*/
215void
216fz_terminate_buffer(fz_context *ctx, fz_buffer *buf)
217{
218 /* ensure that there is a zero-byte after the end of the data */
219 if (buf->len + 1 > buf->cap)
220 fz_grow_buffer(ctx, buf);
221 buf->data[buf->len] = 0;
222}
223
224/*
225 Retrieve internal memory of buffer.
226
227 datap: Output parameter that will be pointed to the data.
228
229 Returns the current size of the data in bytes.
230*/
231size_t
232fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
233{
234 if (datap)
235 *datap = (buf ? buf->data : NULL);
236 return (buf ? buf->len : 0);
237}
238
239/*
240 Ensure that a buffer's data ends in a
241 0 byte, and return a pointer to it.
242*/
243const char *
244fz_string_from_buffer(fz_context *ctx, fz_buffer *buf)
245{
246 if (!buf)
247 return "";
248 fz_terminate_buffer(ctx, buf);
249 return (const char *)buf->data;
250}
251
252/*
253 Take ownership of buffer contents.
254 Performs the same task as fz_buffer_storage, but ownership of
255 the data buffer returns with this call. The buffer is left
256 empty.
257
258 Note: Bad things may happen if this is called on a buffer with
259 multiple references that is being used from multiple threads.
260
261 data: Pointer to place to retrieve data pointer.
262
263 Returns length of stream.
264*/
265size_t
266fz_buffer_extract(fz_context *ctx, fz_buffer *buf, unsigned char **datap)
267{
268 size_t len = buf ? buf->len : 0;
269 *datap = (buf ? buf->data : NULL);
270
271 if (buf)
272 {
273 buf->data = NULL;
274 buf->len = 0;
275 }
276 return len;
277}
278
279void
280fz_append_buffer(fz_context *ctx, fz_buffer *buf, fz_buffer *extra)
281{
282 if (buf->cap - buf->len < extra->len)
283 {
284 buf->data = fz_realloc(ctx, buf->data, buf->len + extra->len);
285 buf->cap = buf->len + extra->len;
286 }
287
288 memcpy(buf->data + buf->len, extra->data, extra->len);
289 buf->len += extra->len;
290}
291
292/*
293 fz_append_*: Append data to a buffer.
294 fz_append_printf: Format and append data to buffer using printf-like formatting (see fz_vsnprintf).
295 fz_append_pdf_string: Append a string with PDF syntax quotes and escapes.
296 The buffer will automatically grow as required.
297*/
298void
299fz_append_data(fz_context *ctx, fz_buffer *buf, const void *data, size_t len)
300{
301 if (buf->len + len > buf->cap)
302 fz_ensure_buffer(ctx, buf, buf->len + len);
303 memcpy(buf->data + buf->len, data, len);
304 buf->len += len;
305 buf->unused_bits = 0;
306}
307
308void
309fz_append_string(fz_context *ctx, fz_buffer *buf, const char *data)
310{
311 size_t len = strlen(data);
312 if (buf->len + len > buf->cap)
313 fz_ensure_buffer(ctx, buf, buf->len + len);
314 memcpy(buf->data + buf->len, data, len);
315 buf->len += len;
316 buf->unused_bits = 0;
317}
318
319void
320fz_append_byte(fz_context *ctx, fz_buffer *buf, int val)
321{
322 if (buf->len + 1 > buf->cap)
323 fz_grow_buffer(ctx, buf);
324 buf->data[buf->len++] = val;
325 buf->unused_bits = 0;
326}
327
328void
329fz_append_rune(fz_context *ctx, fz_buffer *buf, int c)
330{
331 char data[10];
332 int len = fz_runetochar(data, c);
333 if (buf->len + len > buf->cap)
334 fz_ensure_buffer(ctx, buf, buf->len + len);
335 memcpy(buf->data + buf->len, data, len);
336 buf->len += len;
337 buf->unused_bits = 0;
338}
339
340void
341fz_append_int32_be(fz_context *ctx, fz_buffer *buf, int x)
342{
343 fz_append_byte(ctx, buf, (x >> 24) & 0xFF);
344 fz_append_byte(ctx, buf, (x >> 16) & 0xFF);
345 fz_append_byte(ctx, buf, (x >> 8) & 0xFF);
346 fz_append_byte(ctx, buf, (x) & 0xFF);
347}
348
349void
350fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int x)
351{
352 fz_append_byte(ctx, buf, (x >> 8) & 0xFF);
353 fz_append_byte(ctx, buf, (x) & 0xFF);
354}
355
356void
357fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int x)
358{
359 fz_append_byte(ctx, buf, (x)&0xFF);
360 fz_append_byte(ctx, buf, (x>>8)&0xFF);
361 fz_append_byte(ctx, buf, (x>>16)&0xFF);
362 fz_append_byte(ctx, buf, (x>>24)&0xFF);
363}
364
365void
366fz_append_int16_le(fz_context *ctx, fz_buffer *buf, int x)
367{
368 fz_append_byte(ctx, buf, (x)&0xFF);
369 fz_append_byte(ctx, buf, (x>>8)&0xFF);
370}
371
372void
373fz_append_bits(fz_context *ctx, fz_buffer *buf, int val, int bits)
374{
375 int shift;
376
377 /* Throughout this code, the invariant is that we need to write the
378 * bottom 'bits' bits of 'val' into the stream. On entry we assume
379 * that val & ((1<<bits)-1) == val, but we do not rely on this after
380 * having written the first partial byte. */
381
382 if (bits == 0)
383 return;
384
385 /* buf->len always covers all the bits in the buffer, including
386 * any unused ones in the last byte, which will always be 0.
387 * buf->unused_bits = the number of unused bits in the last byte.
388 */
389
390 /* Find the amount we need to shift val up by so that it will be in
391 * the correct position to be inserted into any existing data byte. */
392 shift = (buf->unused_bits - bits);
393
394 /* Extend the buffer as required before we start; that way we never
395 * fail part way during writing. If shift < 0, then we'll need -shift
396 * more bits. */
397 if (shift < 0)
398 {
399 int extra = (7-shift)>>3; /* Round up to bytes */
400 fz_ensure_buffer(ctx, buf, buf->len + extra);
401 }
402
403 /* Write any bits that will fit into the existing byte */
404 if (buf->unused_bits)
405 {
406 buf->data[buf->len-1] |= (shift >= 0 ? (((unsigned int)val)<<shift) : (((unsigned int)val)>>-shift));
407 if (shift >= 0)
408 {
409 /* If we were shifting up, we're done. */
410 buf->unused_bits -= bits;
411 return;
412 }
413 /* The number of bits left to write is the number that didn't
414 * fit in this first byte. */
415 bits = -shift;
416 }
417
418 /* Write any whole bytes */
419 while (bits >= 8)
420 {
421 bits -= 8;
422 buf->data[buf->len++] = val>>bits;
423 }
424
425 /* Write trailing bits (with 0's in unused bits) */
426 if (bits > 0)
427 {
428 bits = 8-bits;
429 buf->data[buf->len++] = val<<bits;
430 }
431 buf->unused_bits = bits;
432}
433
434void
435fz_append_bits_pad(fz_context *ctx, fz_buffer *buf)
436{
437 buf->unused_bits = 0;
438}
439
440static void fz_append_emit(fz_context *ctx, void *buffer, int c)
441{
442 fz_append_byte(ctx, buffer, c);
443}
444
445void
446fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...)
447{
448 va_list args;
449 va_start(args, fmt);
450 fz_format_string(ctx, buffer, fz_append_emit, fmt, args);
451 va_end(args);
452}
453
454void
455fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args)
456{
457 fz_format_string(ctx, buffer, fz_append_emit, fmt, args);
458}
459
460void
461fz_append_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text)
462{
463 size_t len = 2;
464 const char *s = text;
465 char *d;
466 char c;
467
468 while ((c = *s++) != 0)
469 {
470 switch (c)
471 {
472 case '\n':
473 case '\r':
474 case '\t':
475 case '\b':
476 case '\f':
477 case '(':
478 case ')':
479 case '\\':
480 len++;
481 break;
482 }
483 len++;
484 }
485
486 while(buffer->cap - buffer->len < len)
487 fz_grow_buffer(ctx, buffer);
488
489 s = text;
490 d = (char *)buffer->data + buffer->len;
491 *d++ = '(';
492 while ((c = *s++) != 0)
493 {
494 switch (c)
495 {
496 case '\n':
497 *d++ = '\\';
498 *d++ = 'n';
499 break;
500 case '\r':
501 *d++ = '\\';
502 *d++ = 'r';
503 break;
504 case '\t':
505 *d++ = '\\';
506 *d++ = 't';
507 break;
508 case '\b':
509 *d++ = '\\';
510 *d++ = 'b';
511 break;
512 case '\f':
513 *d++ = '\\';
514 *d++ = 'f';
515 break;
516 case '(':
517 *d++ = '\\';
518 *d++ = '(';
519 break;
520 case ')':
521 *d++ = '\\';
522 *d++ = ')';
523 break;
524 case '\\':
525 *d++ = '\\';
526 *d++ = '\\';
527 break;
528 default:
529 *d++ = c;
530 }
531 }
532 *d = ')';
533 buffer->len += len;
534}
535
536void
537fz_md5_buffer(fz_context *ctx, fz_buffer *buffer, unsigned char digest[16])
538{
539 fz_md5 state;
540 fz_md5_init(&state);
541 if (buffer)
542 fz_md5_update(&state, buffer->data, buffer->len);
543 fz_md5_final(&state, digest);
544}
545
546#ifdef TEST_BUFFER_WRITE
547
548#define TEST_LEN 1024
549
550void
551fz_test_buffer_write(fz_context *ctx)
552{
553 fz_buffer *master = fz_new_buffer(ctx, TEST_LEN);
554 fz_buffer *copy = fz_new_buffer(ctx, TEST_LEN);
555 fz_stream *stm;
556 int i, j, k;
557
558 /* Make us a dummy buffer */
559 for (i = 0; i < TEST_LEN; i++)
560 {
561 master->data[i] = rand();
562 }
563 master->len = TEST_LEN;
564
565 /* Now copy that buffer several times, checking it for validity */
566 stm = fz_open_buffer(ctx, master);
567 for (i = 0; i < 256; i++)
568 {
569 memset(copy->data, i, TEST_LEN);
570 copy->len = 0;
571 j = TEST_LEN * 8;
572 do
573 {
574 k = (rand() & 31)+1;
575 if (k > j)
576 k = j;
577 fz_append_bits(ctx, copy, fz_read_bits(ctx, stm, k), k);
578 j -= k;
579 }
580 while (j);
581
582 if (memcmp(copy->data, master->data, TEST_LEN) != 0)
583 fprintf(stderr, "Copied buffer is different!\n");
584 fz_seek(stm, 0, 0);
585 }
586 fz_drop_stream(stm);
587 fz_drop_buffer(ctx, master);
588 fz_drop_buffer(ctx, copy);
589}
590#endif
591