/src/mupdf/source/fitz/buffer.c
Line | Count | Source |
1 | | // Copyright (C) 2004-2026 Artifex Software, Inc. |
2 | | // |
3 | | // This file is part of MuPDF. |
4 | | // |
5 | | // MuPDF is free software: you can redistribute it and/or modify it under the |
6 | | // terms of the GNU Affero General Public License as published by the Free |
7 | | // Software Foundation, either version 3 of the License, or (at your option) |
8 | | // any later version. |
9 | | // |
10 | | // MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY |
11 | | // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
12 | | // FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
13 | | // details. |
14 | | // |
15 | | // You should have received a copy of the GNU Affero General Public License |
16 | | // along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html> |
17 | | // |
18 | | // Alternative licensing terms are available from the licensor. |
19 | | // For commercial licensing, see <https://www.artifex.com/> or contact |
20 | | // Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
21 | | // CA 94129, USA, for further information. |
22 | | |
23 | | #include "mupdf/fitz.h" |
24 | | |
25 | | #include <string.h> |
26 | | #include <stdarg.h> |
27 | | |
28 | | fz_buffer * |
29 | | fz_new_buffer(fz_context *ctx, size_t size) |
30 | 3 | { |
31 | 3 | fz_buffer *b; |
32 | | |
33 | 3 | size = size > 1 ? size : 16; |
34 | | |
35 | 3 | b = fz_malloc_struct(ctx, fz_buffer); |
36 | 3 | b->refs = 1; |
37 | 6 | fz_try(ctx) |
38 | 6 | { |
39 | 3 | b->data = Memento_label(fz_malloc(ctx, size), "fz_buffer_data"); |
40 | 3 | } |
41 | 6 | fz_catch(ctx) |
42 | 0 | { |
43 | 0 | fz_free(ctx, b); |
44 | 0 | fz_rethrow(ctx); |
45 | 0 | } |
46 | 3 | b->cap = size; |
47 | 3 | b->len = 0; |
48 | 3 | b->unused_bits = 0; |
49 | | |
50 | 3 | return b; |
51 | 3 | } |
52 | | |
53 | | fz_buffer * |
54 | | fz_new_buffer_from_data(fz_context *ctx, unsigned char *data, size_t size) |
55 | 0 | { |
56 | 0 | fz_buffer *b = NULL; |
57 | |
|
58 | 0 | fz_try(ctx) |
59 | 0 | { |
60 | 0 | b = fz_malloc_struct(ctx, fz_buffer); |
61 | 0 | b->refs = 1; |
62 | 0 | b->data = data; |
63 | 0 | b->cap = size; |
64 | 0 | b->len = size; |
65 | 0 | b->unused_bits = 0; |
66 | 0 | } |
67 | 0 | fz_catch(ctx) |
68 | 0 | { |
69 | 0 | fz_free(ctx, data); |
70 | 0 | fz_rethrow(ctx); |
71 | 0 | } |
72 | | |
73 | 0 | return b; |
74 | 0 | } |
75 | | |
76 | | fz_buffer * |
77 | | fz_new_buffer_from_shared_data(fz_context *ctx, const unsigned char *data, size_t size) |
78 | 85 | { |
79 | 85 | fz_buffer *b; |
80 | | |
81 | 85 | b = fz_malloc_struct(ctx, fz_buffer); |
82 | 85 | b->refs = 1; |
83 | 85 | b->data = (unsigned char *)data; /* cast away const */ |
84 | 85 | b->cap = size; |
85 | 85 | b->len = size; |
86 | 85 | b->unused_bits = 0; |
87 | 85 | b->shared = 1; |
88 | | |
89 | 85 | return b; |
90 | 85 | } |
91 | | |
92 | | fz_buffer * |
93 | | fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size) |
94 | 0 | { |
95 | 0 | fz_buffer *b; |
96 | 0 | if (size > 0 && data == NULL) |
97 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "no data provided"); |
98 | 0 | b = fz_new_buffer(ctx, size); |
99 | 0 | b->len = size; |
100 | 0 | memcpy(b->data, data, size); |
101 | 0 | return b; |
102 | 0 | } |
103 | | |
104 | | fz_buffer * |
105 | | fz_new_buffer_from_printf(fz_context *ctx, const char *fmt, ...) |
106 | 0 | { |
107 | 0 | size_t len; |
108 | 0 | fz_buffer *buf; |
109 | 0 | va_list ap; |
110 | 0 | va_start(ap, fmt); |
111 | 0 | len = fz_vsnprintf(NULL, 0, fmt, ap); |
112 | 0 | va_end(ap); |
113 | 0 | buf = fz_new_buffer(ctx, len+1); |
114 | 0 | va_start(ap, fmt); |
115 | 0 | fz_append_vprintf(ctx, buf, fmt, ap); |
116 | 0 | va_end(ap); |
117 | 0 | return buf; |
118 | 0 | } |
119 | | |
120 | | fz_buffer *fz_clone_buffer(fz_context *ctx, fz_buffer *buf) |
121 | 0 | { |
122 | 0 | return fz_new_buffer_from_copied_data(ctx, buf ? buf->data : NULL, buf ? buf->len : 0); |
123 | 0 | } |
124 | | |
125 | | static inline int iswhite(int a) |
126 | 0 | { |
127 | 0 | switch (a) { |
128 | 0 | case '\n': case '\r': case '\t': case ' ': |
129 | 0 | case '\f': |
130 | 0 | return 1; |
131 | 0 | } |
132 | 0 | return 0; |
133 | 0 | } |
134 | | |
135 | | fz_buffer * |
136 | | fz_new_buffer_from_base64(fz_context *ctx, const char *data, size_t size) |
137 | 0 | { |
138 | 0 | fz_buffer *out = fz_new_buffer(ctx, size > 0 ? size : strlen(data)); |
139 | 0 | const char *end = data + (size > 0 ? size : strlen(data)); |
140 | 0 | const char *s = data; |
141 | 0 | uint32_t buf = 0; |
142 | 0 | int bits = 0; |
143 | | |
144 | | /* This is https://infra.spec.whatwg.org/#forgiving-base64-decode |
145 | | * but even more relaxed. We allow any number of trailing '=' code |
146 | | * points and instead of returning failure on invalid characters, we |
147 | | * warn and truncate. |
148 | | */ |
149 | |
|
150 | 0 | while (s < end && iswhite(*s)) |
151 | 0 | s++; |
152 | 0 | while (s < end && iswhite(end[-1])) |
153 | 0 | end--; |
154 | 0 | while (s < end && end[-1] == '=') |
155 | 0 | end--; |
156 | |
|
157 | 0 | fz_try(ctx) |
158 | 0 | { |
159 | 0 | while (s < end) |
160 | 0 | { |
161 | 0 | int c = *s++; |
162 | |
|
163 | 0 | if (c >= 'A' && c <= 'Z') |
164 | 0 | c = c - 'A'; |
165 | 0 | else if (c >= 'a' && c <= 'z') |
166 | 0 | c = c - 'a' + 26; |
167 | 0 | else if (c >= '0' && c <= '9') |
168 | 0 | c = c - '0' + 52; |
169 | 0 | else if (c == '+') |
170 | 0 | c = 62; |
171 | 0 | else if (c == '/') |
172 | 0 | c = 63; |
173 | 0 | else if (iswhite(c)) |
174 | 0 | continue; |
175 | 0 | else |
176 | 0 | { |
177 | 0 | fz_warn(ctx, "invalid character in base64"); |
178 | 0 | break; |
179 | 0 | } |
180 | | |
181 | 0 | buf <<= 6; |
182 | 0 | buf |= c & 0x3f; |
183 | 0 | bits += 6; |
184 | |
|
185 | 0 | if (bits == 24) |
186 | 0 | { |
187 | 0 | fz_append_byte(ctx, out, buf >> 16); |
188 | 0 | fz_append_byte(ctx, out, buf >> 8); |
189 | 0 | fz_append_byte(ctx, out, buf >> 0); |
190 | 0 | bits = 0; |
191 | 0 | } |
192 | 0 | } |
193 | |
|
194 | 0 | if (bits == 18) |
195 | 0 | { |
196 | 0 | fz_append_byte(ctx, out, buf >> 10); |
197 | 0 | fz_append_byte(ctx, out, buf >> 2); |
198 | 0 | } |
199 | 0 | else if (bits == 12) |
200 | 0 | { |
201 | 0 | fz_append_byte(ctx, out, buf >> 4); |
202 | 0 | } |
203 | 0 | } |
204 | 0 | fz_catch(ctx) |
205 | 0 | { |
206 | 0 | fz_drop_buffer(ctx, out); |
207 | 0 | fz_rethrow(ctx); |
208 | 0 | } |
209 | 0 | return out; |
210 | 0 | } |
211 | | |
212 | | fz_buffer * |
213 | | fz_keep_buffer(fz_context *ctx, fz_buffer *buf) |
214 | 111 | { |
215 | 111 | return fz_keep_imp(ctx, buf, &buf->refs); |
216 | 111 | } |
217 | | |
218 | | void |
219 | | fz_drop_buffer(fz_context *ctx, fz_buffer *buf) |
220 | 11.0k | { |
221 | 11.0k | if (fz_drop_imp(ctx, buf, &buf->refs)) |
222 | 88 | { |
223 | 88 | if (!buf->shared) |
224 | 3 | fz_free(ctx, buf->data); |
225 | 88 | fz_free(ctx, buf); |
226 | 88 | } |
227 | 11.0k | } |
228 | | |
229 | | void |
230 | | fz_resize_buffer(fz_context *ctx, fz_buffer *buf, size_t size) |
231 | 36 | { |
232 | 36 | if (buf->shared) |
233 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot resize a buffer with shared storage"); |
234 | 36 | buf->data = fz_realloc(ctx, buf->data, size); |
235 | 36 | buf->cap = size; |
236 | 36 | if (buf->len > buf->cap) |
237 | 0 | buf->len = buf->cap; |
238 | 36 | } |
239 | | |
240 | | void |
241 | | fz_grow_buffer(fz_context *ctx, fz_buffer *buf) |
242 | 36 | { |
243 | 36 | size_t newsize = 256; |
244 | 36 | if (buf->cap == SIZE_MAX) |
245 | 0 | fz_throw(ctx, FZ_ERROR_SYSTEM, "buffer too large"); |
246 | 36 | else if (buf->cap == 0) |
247 | 0 | newsize = 256; |
248 | 36 | else |
249 | 36 | { |
250 | 36 | newsize = buf->cap + (buf->cap >> 1); |
251 | | // check for integer overflow |
252 | 36 | if (newsize < buf->cap) |
253 | 0 | newsize = SIZE_MAX; |
254 | 36 | } |
255 | 36 | fz_resize_buffer(ctx, buf, newsize); |
256 | 36 | } |
257 | | |
258 | | static void |
259 | | fz_ensure_buffer(fz_context *ctx, fz_buffer *buf, size_t min) |
260 | 0 | { |
261 | 0 | size_t newsize = buf->cap; |
262 | 0 | if (newsize < 16) |
263 | 0 | newsize = 16; |
264 | 0 | while (newsize < min) |
265 | 0 | { |
266 | 0 | size_t tmp = newsize + (newsize >> 1); |
267 | | // check for integer overflow |
268 | 0 | if (tmp < newsize) |
269 | 0 | newsize = min; |
270 | 0 | else |
271 | 0 | newsize = tmp; |
272 | 0 | } |
273 | 0 | fz_resize_buffer(ctx, buf, newsize); |
274 | 0 | } |
275 | | |
276 | | void |
277 | | fz_trim_buffer(fz_context *ctx, fz_buffer *buf) |
278 | 0 | { |
279 | 0 | if (buf->cap > buf->len+1) |
280 | 0 | fz_resize_buffer(ctx, buf, buf->len); |
281 | 0 | } |
282 | | |
283 | | void |
284 | | fz_clear_buffer(fz_context *ctx, fz_buffer *buf) |
285 | 0 | { |
286 | 0 | buf->len = 0; |
287 | 0 | } |
288 | | |
289 | | void |
290 | | fz_terminate_buffer(fz_context *ctx, fz_buffer *buf) |
291 | 0 | { |
292 | | /* ensure that there is a zero-byte after the end of the data */ |
293 | 0 | if (buf->len + 1 > buf->cap) |
294 | 0 | fz_grow_buffer(ctx, buf); |
295 | 0 | buf->data[buf->len] = 0; |
296 | 0 | } |
297 | | |
298 | | size_t |
299 | | fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap) |
300 | 111 | { |
301 | 111 | if (datap) |
302 | 111 | *datap = (buf ? buf->data : NULL); |
303 | 111 | return (buf ? buf->len : 0); |
304 | 111 | } |
305 | | |
306 | | const char * |
307 | | fz_string_from_buffer(fz_context *ctx, fz_buffer *buf) |
308 | 0 | { |
309 | 0 | if (!buf) |
310 | 0 | return ""; |
311 | 0 | fz_terminate_buffer(ctx, buf); |
312 | 0 | return (const char *)buf->data; |
313 | 0 | } |
314 | | |
315 | | size_t |
316 | | fz_buffer_extract(fz_context *ctx, fz_buffer *buf, unsigned char **datap) |
317 | 0 | { |
318 | 0 | size_t len = buf ? buf->len : 0; |
319 | 0 | *datap = (buf ? buf->data : NULL); |
320 | |
|
321 | 0 | if (buf) |
322 | 0 | { |
323 | 0 | buf->data = NULL; |
324 | 0 | buf->len = 0; |
325 | 0 | } |
326 | 0 | return len; |
327 | 0 | } |
328 | | |
329 | | fz_buffer * |
330 | | fz_slice_buffer(fz_context *ctx, fz_buffer *buf, int64_t start, int64_t end) |
331 | 0 | { |
332 | 0 | unsigned char *src = NULL; |
333 | 0 | size_t size = fz_buffer_storage(ctx, buf, &src); |
334 | 0 | size_t s, e; |
335 | |
|
336 | 0 | if (start < 0) |
337 | 0 | start += size; |
338 | 0 | if (end < 0) |
339 | 0 | end += size; |
340 | |
|
341 | 0 | s = fz_clamp64(start, 0, size); |
342 | 0 | e = fz_clamp64(end, 0, size); |
343 | |
|
344 | 0 | if (s == size || e <= s) |
345 | 0 | return fz_new_buffer(ctx, 0); |
346 | | |
347 | 0 | return fz_new_buffer_from_copied_data(ctx, &src[s], e - s); |
348 | 0 | } |
349 | | |
350 | | void |
351 | | fz_append_buffer(fz_context *ctx, fz_buffer *buf, fz_buffer *extra) |
352 | 0 | { |
353 | 0 | if (extra == NULL) |
354 | 0 | return; |
355 | 0 | if (buf->cap - buf->len < extra->len) |
356 | 0 | { |
357 | 0 | buf->data = fz_realloc(ctx, buf->data, buf->len + extra->len); |
358 | 0 | buf->cap = buf->len + extra->len; |
359 | 0 | } |
360 | |
|
361 | 0 | memcpy(buf->data + buf->len, extra->data, extra->len); |
362 | 0 | buf->len += extra->len; |
363 | 0 | } |
364 | | |
365 | | void |
366 | | fz_append_data(fz_context *ctx, fz_buffer *buf, const void *data, size_t len) |
367 | 0 | { |
368 | 0 | if (buf->len + len > buf->cap) |
369 | 0 | fz_ensure_buffer(ctx, buf, buf->len + len); |
370 | 0 | memcpy(buf->data + buf->len, data, len); |
371 | 0 | buf->len += len; |
372 | 0 | buf->unused_bits = 0; |
373 | 0 | } |
374 | | |
375 | | void |
376 | | fz_append_string(fz_context *ctx, fz_buffer *buf, const char *data) |
377 | 0 | { |
378 | 0 | size_t len = strlen(data); |
379 | 0 | if (buf->len + len > buf->cap) |
380 | 0 | fz_ensure_buffer(ctx, buf, buf->len + len); |
381 | 0 | memcpy(buf->data + buf->len, data, len); |
382 | 0 | buf->len += len; |
383 | 0 | buf->unused_bits = 0; |
384 | 0 | } |
385 | | |
386 | | void |
387 | | fz_append_byte(fz_context *ctx, fz_buffer *buf, int val) |
388 | 0 | { |
389 | 0 | if (buf->len + 1 > buf->cap) |
390 | 0 | fz_grow_buffer(ctx, buf); |
391 | 0 | buf->data[buf->len++] = val; |
392 | 0 | buf->unused_bits = 0; |
393 | 0 | } |
394 | | |
395 | | void |
396 | | fz_append_rune(fz_context *ctx, fz_buffer *buf, int c) |
397 | 0 | { |
398 | 0 | char data[10]; |
399 | 0 | int len = fz_runetochar(data, c); |
400 | 0 | if (buf->len + len > buf->cap) |
401 | 0 | fz_ensure_buffer(ctx, buf, buf->len + len); |
402 | 0 | memcpy(buf->data + buf->len, data, len); |
403 | 0 | buf->len += len; |
404 | 0 | buf->unused_bits = 0; |
405 | 0 | } |
406 | | |
407 | | void |
408 | | fz_append_uint32_be(fz_context *ctx, fz_buffer *buf, uint32_t x) |
409 | 0 | { |
410 | 0 | fz_append_byte(ctx, buf, (x >> 24) & 0xFF); |
411 | 0 | fz_append_byte(ctx, buf, (x >> 16) & 0xFF); |
412 | 0 | fz_append_byte(ctx, buf, (x >> 8) & 0xFF); |
413 | 0 | fz_append_byte(ctx, buf, (x) & 0xFF); |
414 | 0 | } |
415 | | |
416 | | void |
417 | | fz_append_uint16_be(fz_context *ctx, fz_buffer *buf, uint16_t x) |
418 | 0 | { |
419 | 0 | fz_append_byte(ctx, buf, (x >> 8) & 0xFF); |
420 | 0 | fz_append_byte(ctx, buf, (x) & 0xFF); |
421 | 0 | } |
422 | | |
423 | | void |
424 | | fz_append_uint32_le(fz_context *ctx, fz_buffer *buf, uint32_t x) |
425 | 0 | { |
426 | 0 | fz_append_byte(ctx, buf, (x)&0xFF); |
427 | 0 | fz_append_byte(ctx, buf, (x>>8)&0xFF); |
428 | 0 | fz_append_byte(ctx, buf, (x>>16)&0xFF); |
429 | 0 | fz_append_byte(ctx, buf, (x>>24)&0xFF); |
430 | 0 | } |
431 | | |
432 | | void |
433 | | fz_append_uint16_le(fz_context *ctx, fz_buffer *buf, uint16_t x) |
434 | 0 | { |
435 | 0 | fz_append_byte(ctx, buf, (x)&0xFF); |
436 | 0 | fz_append_byte(ctx, buf, (x>>8)&0xFF); |
437 | 0 | } |
438 | | |
439 | | void |
440 | | fz_append_int32_be(fz_context *ctx, fz_buffer *buf, int32_t x) |
441 | 0 | { |
442 | 0 | fz_append_uint32_be(ctx, buf, x); |
443 | 0 | } |
444 | | |
445 | | void |
446 | | fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int16_t x) |
447 | 0 | { |
448 | 0 | fz_append_uint16_be(ctx, buf, x); |
449 | 0 | } |
450 | | |
451 | | void |
452 | | fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int32_t x) |
453 | 0 | { |
454 | 0 | fz_append_uint32_le(ctx, buf, x); |
455 | 0 | } |
456 | | |
457 | | void |
458 | | fz_append_int16_le(fz_context *ctx, fz_buffer *buf, int16_t x) |
459 | 0 | { |
460 | 0 | fz_append_uint16_le(ctx, buf, x); |
461 | 0 | } |
462 | | |
463 | | void |
464 | | fz_append_bits(fz_context *ctx, fz_buffer *buf, int val, int bits) |
465 | 0 | { |
466 | 0 | int shift; |
467 | | |
468 | | /* Throughout this code, the invariant is that we need to write the |
469 | | * bottom 'bits' bits of 'val' into the stream. On entry we assume |
470 | | * that val & ((1<<bits)-1) == val, but we do not rely on this after |
471 | | * having written the first partial byte. */ |
472 | |
|
473 | 0 | if (bits == 0) |
474 | 0 | return; |
475 | | |
476 | | /* buf->len always covers all the bits in the buffer, including |
477 | | * any unused ones in the last byte, which will always be 0. |
478 | | * buf->unused_bits = the number of unused bits in the last byte. |
479 | | */ |
480 | | |
481 | | /* Find the amount we need to shift val up by so that it will be in |
482 | | * the correct position to be inserted into any existing data byte. */ |
483 | 0 | shift = (buf->unused_bits - bits); |
484 | | |
485 | | /* Extend the buffer as required before we start; that way we never |
486 | | * fail part way during writing. If shift < 0, then we'll need -shift |
487 | | * more bits. */ |
488 | 0 | if (shift < 0) |
489 | 0 | { |
490 | 0 | int extra = (7-shift)>>3; /* Round up to bytes */ |
491 | 0 | fz_ensure_buffer(ctx, buf, buf->len + extra); |
492 | 0 | } |
493 | | |
494 | | /* Write any bits that will fit into the existing byte */ |
495 | 0 | if (buf->unused_bits) |
496 | 0 | { |
497 | 0 | buf->data[buf->len-1] |= (shift >= 0 ? (((unsigned int)val)<<shift) : (((unsigned int)val)>>-shift)); |
498 | 0 | if (shift >= 0) |
499 | 0 | { |
500 | | /* If we were shifting up, we're done. */ |
501 | 0 | buf->unused_bits -= bits; |
502 | 0 | return; |
503 | 0 | } |
504 | | /* The number of bits left to write is the number that didn't |
505 | | * fit in this first byte. */ |
506 | 0 | bits = -shift; |
507 | 0 | } |
508 | | |
509 | | /* Write any whole bytes */ |
510 | 0 | while (bits >= 8) |
511 | 0 | { |
512 | 0 | bits -= 8; |
513 | 0 | buf->data[buf->len++] = val>>bits; |
514 | 0 | } |
515 | | |
516 | | /* Write trailing bits (with 0's in unused bits) */ |
517 | 0 | if (bits > 0) |
518 | 0 | { |
519 | 0 | bits = 8-bits; |
520 | 0 | buf->data[buf->len++] = val<<bits; |
521 | 0 | } |
522 | 0 | buf->unused_bits = bits; |
523 | 0 | } |
524 | | |
525 | | void |
526 | | fz_append_bits_pad(fz_context *ctx, fz_buffer *buf) |
527 | 0 | { |
528 | 0 | buf->unused_bits = 0; |
529 | 0 | } |
530 | | |
531 | | static void fz_append_emit(fz_context *ctx, void *buffer, int c) |
532 | 0 | { |
533 | 0 | fz_append_byte(ctx, buffer, c); |
534 | 0 | } |
535 | | |
536 | | void |
537 | | fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...) |
538 | 0 | { |
539 | 0 | va_list args; |
540 | 0 | va_start(args, fmt); |
541 | 0 | fz_format_string(ctx, buffer, fz_append_emit, fmt, args); |
542 | 0 | va_end(args); |
543 | 0 | } |
544 | | |
545 | | void |
546 | | fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args) |
547 | 0 | { |
548 | 0 | fz_format_string(ctx, buffer, fz_append_emit, fmt, args); |
549 | 0 | } |
550 | | |
551 | | void |
552 | | fz_append_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text) |
553 | 0 | { |
554 | 0 | size_t len = 2; |
555 | 0 | const char *s = text; |
556 | 0 | char *d; |
557 | 0 | char c; |
558 | |
|
559 | 0 | while ((c = *s++) != 0) |
560 | 0 | { |
561 | 0 | switch (c) |
562 | 0 | { |
563 | 0 | case '\n': |
564 | 0 | case '\r': |
565 | 0 | case '\t': |
566 | 0 | case '\b': |
567 | 0 | case '\f': |
568 | 0 | case '(': |
569 | 0 | case ')': |
570 | 0 | case '\\': |
571 | 0 | len++; |
572 | 0 | break; |
573 | 0 | } |
574 | 0 | len++; |
575 | 0 | } |
576 | | |
577 | 0 | while(buffer->cap - buffer->len < len) |
578 | 0 | fz_grow_buffer(ctx, buffer); |
579 | |
|
580 | 0 | s = text; |
581 | 0 | d = (char *)buffer->data + buffer->len; |
582 | 0 | *d++ = '('; |
583 | 0 | while ((c = *s++) != 0) |
584 | 0 | { |
585 | 0 | switch (c) |
586 | 0 | { |
587 | 0 | case '\n': |
588 | 0 | *d++ = '\\'; |
589 | 0 | *d++ = 'n'; |
590 | 0 | break; |
591 | 0 | case '\r': |
592 | 0 | *d++ = '\\'; |
593 | 0 | *d++ = 'r'; |
594 | 0 | break; |
595 | 0 | case '\t': |
596 | 0 | *d++ = '\\'; |
597 | 0 | *d++ = 't'; |
598 | 0 | break; |
599 | 0 | case '\b': |
600 | 0 | *d++ = '\\'; |
601 | 0 | *d++ = 'b'; |
602 | 0 | break; |
603 | 0 | case '\f': |
604 | 0 | *d++ = '\\'; |
605 | 0 | *d++ = 'f'; |
606 | 0 | break; |
607 | 0 | case '(': |
608 | 0 | *d++ = '\\'; |
609 | 0 | *d++ = '('; |
610 | 0 | break; |
611 | 0 | case ')': |
612 | 0 | *d++ = '\\'; |
613 | 0 | *d++ = ')'; |
614 | 0 | break; |
615 | 0 | case '\\': |
616 | 0 | *d++ = '\\'; |
617 | 0 | *d++ = '\\'; |
618 | 0 | break; |
619 | 0 | default: |
620 | 0 | *d++ = c; |
621 | 0 | } |
622 | 0 | } |
623 | 0 | *d = ')'; |
624 | 0 | buffer->len += len; |
625 | 0 | } |
626 | | |
627 | | void |
628 | | fz_md5_buffer(fz_context *ctx, fz_buffer *buffer, unsigned char digest[16]) |
629 | 108 | { |
630 | 108 | fz_md5 state; |
631 | 108 | fz_md5_init(&state); |
632 | 108 | if (buffer) |
633 | 108 | fz_md5_update(&state, buffer->data, buffer->len); |
634 | 108 | fz_md5_final(&state, digest); |
635 | 108 | } |
636 | | |
637 | | #ifdef TEST_BUFFER_WRITE |
638 | | |
639 | | #define TEST_LEN 1024 |
640 | | |
641 | | void |
642 | | fz_test_buffer_write(fz_context *ctx) |
643 | | { |
644 | | fz_buffer *master = fz_new_buffer(ctx, TEST_LEN); |
645 | | fz_buffer *copy = fz_new_buffer(ctx, TEST_LEN); |
646 | | fz_stream *stm; |
647 | | int i, j, k; |
648 | | |
649 | | /* Make us a dummy buffer */ |
650 | | for (i = 0; i < TEST_LEN; i++) |
651 | | { |
652 | | master->data[i] = rand(); |
653 | | } |
654 | | master->len = TEST_LEN; |
655 | | |
656 | | /* Now copy that buffer several times, checking it for validity */ |
657 | | stm = fz_open_buffer(ctx, master); |
658 | | for (i = 0; i < 256; i++) |
659 | | { |
660 | | memset(copy->data, i, TEST_LEN); |
661 | | copy->len = 0; |
662 | | j = TEST_LEN * 8; |
663 | | do |
664 | | { |
665 | | k = (rand() & 31)+1; |
666 | | if (k > j) |
667 | | k = j; |
668 | | fz_append_bits(ctx, copy, fz_read_bits(ctx, stm, k), k); |
669 | | j -= k; |
670 | | } |
671 | | while (j); |
672 | | |
673 | | if (memcmp(copy->data, master->data, TEST_LEN) != 0) |
674 | | fprintf(stderr, "Copied buffer is different!\n"); |
675 | | fz_seek(stm, 0, 0); |
676 | | } |
677 | | fz_drop_stream(stm); |
678 | | fz_drop_buffer(ctx, master); |
679 | | fz_drop_buffer(ctx, copy); |
680 | | } |
681 | | #endif |