/src/mupdf/source/fitz/buffer.c
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (C) 2004-2024 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 | 87.3k | { |
31 | 87.3k | fz_buffer *b; |
32 | | |
33 | 87.3k | size = size > 1 ? size : 16; |
34 | | |
35 | 87.3k | b = fz_malloc_struct(ctx, fz_buffer); |
36 | 87.3k | b->refs = 1; |
37 | 174k | fz_try(ctx) |
38 | 174k | { |
39 | 87.3k | b->data = Memento_label(fz_malloc(ctx, size), "fz_buffer_data"); |
40 | 87.3k | } |
41 | 174k | fz_catch(ctx) |
42 | 2 | { |
43 | 2 | fz_free(ctx, b); |
44 | 2 | fz_rethrow(ctx); |
45 | 2 | } |
46 | 87.3k | b->cap = size; |
47 | 87.3k | b->len = 0; |
48 | 87.3k | b->unused_bits = 0; |
49 | | |
50 | 87.3k | return b; |
51 | 87.3k | } |
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 | 73.1k | { |
79 | 73.1k | fz_buffer *b; |
80 | | |
81 | 73.1k | b = fz_malloc_struct(ctx, fz_buffer); |
82 | 73.1k | b->refs = 1; |
83 | 73.1k | b->data = (unsigned char *)data; /* cast away const */ |
84 | 73.1k | b->cap = size; |
85 | 73.1k | b->len = size; |
86 | 73.1k | b->unused_bits = 0; |
87 | 73.1k | b->shared = 1; |
88 | | |
89 | 73.1k | return b; |
90 | 73.1k | } |
91 | | |
92 | | fz_buffer * |
93 | | fz_new_buffer_from_copied_data(fz_context *ctx, const unsigned char *data, size_t size) |
94 | 3.47k | { |
95 | 3.47k | fz_buffer *b; |
96 | 3.47k | if (size > 0 && data == NULL) |
97 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "no data provided"); |
98 | 3.47k | b = fz_new_buffer(ctx, size); |
99 | 3.47k | b->len = size; |
100 | 3.47k | memcpy(b->data, data, size); |
101 | 3.47k | return b; |
102 | 3.47k | } |
103 | | |
104 | | fz_buffer *fz_clone_buffer(fz_context *ctx, fz_buffer *buf) |
105 | 0 | { |
106 | 0 | return fz_new_buffer_from_copied_data(ctx, buf ? buf->data : NULL, buf ? buf->len : 0); |
107 | 0 | } |
108 | | |
109 | | static inline int iswhite(int a) |
110 | 0 | { |
111 | 0 | switch (a) { |
112 | 0 | case '\n': case '\r': case '\t': case ' ': |
113 | 0 | case '\f': |
114 | 0 | return 1; |
115 | 0 | } |
116 | 0 | return 0; |
117 | 0 | } |
118 | | |
119 | | fz_buffer * |
120 | | fz_new_buffer_from_base64(fz_context *ctx, const char *data, size_t size) |
121 | 0 | { |
122 | 0 | fz_buffer *out = fz_new_buffer(ctx, size > 0 ? size : strlen(data)); |
123 | 0 | const char *end = data + (size > 0 ? size : strlen(data)); |
124 | 0 | const char *s = data; |
125 | 0 | uint32_t buf = 0; |
126 | 0 | int bits = 0; |
127 | | |
128 | | /* This is https://infra.spec.whatwg.org/#forgiving-base64-decode |
129 | | * but even more relaxed. We allow any number of trailing '=' code |
130 | | * points and instead of returning failure on invalid characters, we |
131 | | * warn and truncate. |
132 | | */ |
133 | |
|
134 | 0 | while (s < end && iswhite(*s)) |
135 | 0 | s++; |
136 | 0 | while (s < end && iswhite(end[-1])) |
137 | 0 | end--; |
138 | 0 | while (s < end && end[-1] == '=') |
139 | 0 | end--; |
140 | |
|
141 | 0 | fz_try(ctx) |
142 | 0 | { |
143 | 0 | while (s < end) |
144 | 0 | { |
145 | 0 | int c = *s++; |
146 | |
|
147 | 0 | if (c >= 'A' && c <= 'Z') |
148 | 0 | c = c - 'A'; |
149 | 0 | else if (c >= 'a' && c <= 'z') |
150 | 0 | c = c - 'a' + 26; |
151 | 0 | else if (c >= '0' && c <= '9') |
152 | 0 | c = c - '0' + 52; |
153 | 0 | else if (c == '+') |
154 | 0 | c = 62; |
155 | 0 | else if (c == '/') |
156 | 0 | c = 63; |
157 | 0 | else if (iswhite(c)) |
158 | 0 | continue; |
159 | 0 | else |
160 | 0 | { |
161 | 0 | fz_warn(ctx, "invalid character in base64"); |
162 | 0 | break; |
163 | 0 | } |
164 | | |
165 | 0 | buf <<= 6; |
166 | 0 | buf |= c & 0x3f; |
167 | 0 | bits += 6; |
168 | |
|
169 | 0 | if (bits == 24) |
170 | 0 | { |
171 | 0 | fz_append_byte(ctx, out, buf >> 16); |
172 | 0 | fz_append_byte(ctx, out, buf >> 8); |
173 | 0 | fz_append_byte(ctx, out, buf >> 0); |
174 | 0 | bits = 0; |
175 | 0 | } |
176 | 0 | } |
177 | |
|
178 | 0 | if (bits == 18) |
179 | 0 | { |
180 | 0 | fz_append_byte(ctx, out, buf >> 10); |
181 | 0 | fz_append_byte(ctx, out, buf >> 2); |
182 | 0 | } |
183 | 0 | else if (bits == 12) |
184 | 0 | { |
185 | 0 | fz_append_byte(ctx, out, buf >> 4); |
186 | 0 | } |
187 | 0 | } |
188 | 0 | fz_catch(ctx) |
189 | 0 | { |
190 | 0 | fz_drop_buffer(ctx, out); |
191 | 0 | fz_rethrow(ctx); |
192 | 0 | } |
193 | 0 | return out; |
194 | 0 | } |
195 | | |
196 | | fz_buffer * |
197 | | fz_keep_buffer(fz_context *ctx, fz_buffer *buf) |
198 | 217k | { |
199 | 217k | return fz_keep_imp(ctx, buf, &buf->refs); |
200 | 217k | } |
201 | | |
202 | | void |
203 | | fz_drop_buffer(fz_context *ctx, fz_buffer *buf) |
204 | 67.0M | { |
205 | 67.0M | if (fz_drop_imp(ctx, buf, &buf->refs)) |
206 | 160k | { |
207 | 160k | if (!buf->shared) |
208 | 87.3k | fz_free(ctx, buf->data); |
209 | 160k | fz_free(ctx, buf); |
210 | 160k | } |
211 | 67.0M | } |
212 | | |
213 | | void |
214 | | fz_resize_buffer(fz_context *ctx, fz_buffer *buf, size_t size) |
215 | 71.9k | { |
216 | 71.9k | if (buf->shared) |
217 | 0 | fz_throw(ctx, FZ_ERROR_ARGUMENT, "cannot resize a buffer with shared storage"); |
218 | 71.9k | buf->data = fz_realloc(ctx, buf->data, size); |
219 | 71.9k | buf->cap = size; |
220 | 71.9k | if (buf->len > buf->cap) |
221 | 0 | buf->len = buf->cap; |
222 | 71.9k | } |
223 | | |
224 | | void |
225 | | fz_grow_buffer(fz_context *ctx, fz_buffer *buf) |
226 | 39.9k | { |
227 | 39.9k | size_t newsize = (buf->cap * 3) / 2; |
228 | 39.9k | if (newsize == 0) |
229 | 0 | newsize = 256; |
230 | 39.9k | fz_resize_buffer(ctx, buf, newsize); |
231 | 39.9k | } |
232 | | |
233 | | static void |
234 | | fz_ensure_buffer(fz_context *ctx, fz_buffer *buf, size_t min) |
235 | 23.6k | { |
236 | 23.6k | size_t newsize = buf->cap; |
237 | 23.6k | if (newsize < 16) |
238 | 0 | newsize = 16; |
239 | 57.4k | while (newsize < min) |
240 | 33.8k | { |
241 | 33.8k | newsize = (newsize * 3) / 2; |
242 | 33.8k | } |
243 | 23.6k | fz_resize_buffer(ctx, buf, newsize); |
244 | 23.6k | } |
245 | | |
246 | | void |
247 | | fz_trim_buffer(fz_context *ctx, fz_buffer *buf) |
248 | 8.46k | { |
249 | 8.46k | if (buf->cap > buf->len+1) |
250 | 8.44k | fz_resize_buffer(ctx, buf, buf->len); |
251 | 8.46k | } |
252 | | |
253 | | void |
254 | | fz_clear_buffer(fz_context *ctx, fz_buffer *buf) |
255 | 0 | { |
256 | 0 | buf->len = 0; |
257 | 0 | } |
258 | | |
259 | | void |
260 | | fz_terminate_buffer(fz_context *ctx, fz_buffer *buf) |
261 | 948 | { |
262 | | /* ensure that there is a zero-byte after the end of the data */ |
263 | 948 | if (buf->len + 1 > buf->cap) |
264 | 518 | fz_grow_buffer(ctx, buf); |
265 | 948 | buf->data[buf->len] = 0; |
266 | 948 | } |
267 | | |
268 | | size_t |
269 | | fz_buffer_storage(fz_context *ctx, fz_buffer *buf, unsigned char **datap) |
270 | 116k | { |
271 | 116k | if (datap) |
272 | 85.9k | *datap = (buf ? buf->data : NULL); |
273 | 116k | return (buf ? buf->len : 0); |
274 | 116k | } |
275 | | |
276 | | const char * |
277 | | fz_string_from_buffer(fz_context *ctx, fz_buffer *buf) |
278 | 1 | { |
279 | 1 | if (!buf) |
280 | 0 | return ""; |
281 | 1 | fz_terminate_buffer(ctx, buf); |
282 | 1 | return (const char *)buf->data; |
283 | 1 | } |
284 | | |
285 | | size_t |
286 | | fz_buffer_extract(fz_context *ctx, fz_buffer *buf, unsigned char **datap) |
287 | 0 | { |
288 | 0 | size_t len = buf ? buf->len : 0; |
289 | 0 | *datap = (buf ? buf->data : NULL); |
290 | |
|
291 | 0 | if (buf) |
292 | 0 | { |
293 | 0 | buf->data = NULL; |
294 | 0 | buf->len = 0; |
295 | 0 | } |
296 | 0 | return len; |
297 | 0 | } |
298 | | |
299 | | fz_buffer * |
300 | | fz_slice_buffer(fz_context *ctx, fz_buffer *buf, int64_t start, int64_t end) |
301 | 0 | { |
302 | 0 | unsigned char *src = NULL; |
303 | 0 | size_t size = fz_buffer_storage(ctx, buf, &src); |
304 | 0 | size_t s, e; |
305 | |
|
306 | 0 | if (start < 0) |
307 | 0 | start += size; |
308 | 0 | if (end < 0) |
309 | 0 | end += size; |
310 | |
|
311 | 0 | s = fz_clamp64(start, 0, size); |
312 | 0 | e = fz_clamp64(end, 0, size); |
313 | |
|
314 | 0 | if (s == size || e <= s) |
315 | 0 | return fz_new_buffer(ctx, 0); |
316 | | |
317 | 0 | return fz_new_buffer_from_copied_data(ctx, &src[s], e - s); |
318 | 0 | } |
319 | | |
320 | | void |
321 | | fz_append_buffer(fz_context *ctx, fz_buffer *buf, fz_buffer *extra) |
322 | 519 | { |
323 | 519 | if (buf->cap - buf->len < extra->len) |
324 | 263 | { |
325 | 263 | buf->data = fz_realloc(ctx, buf->data, buf->len + extra->len); |
326 | 263 | buf->cap = buf->len + extra->len; |
327 | 263 | } |
328 | | |
329 | 519 | memcpy(buf->data + buf->len, extra->data, extra->len); |
330 | 519 | buf->len += extra->len; |
331 | 519 | } |
332 | | |
333 | | void |
334 | | fz_append_data(fz_context *ctx, fz_buffer *buf, const void *data, size_t len) |
335 | 5.76G | { |
336 | 5.76G | if (buf->len + len > buf->cap) |
337 | 8.92k | fz_ensure_buffer(ctx, buf, buf->len + len); |
338 | 5.76G | memcpy(buf->data + buf->len, data, len); |
339 | 5.76G | buf->len += len; |
340 | 5.76G | buf->unused_bits = 0; |
341 | 5.76G | } |
342 | | |
343 | | void |
344 | | fz_append_string(fz_context *ctx, fz_buffer *buf, const char *data) |
345 | 199k | { |
346 | 199k | size_t len = strlen(data); |
347 | 199k | if (buf->len + len > buf->cap) |
348 | 14.6k | fz_ensure_buffer(ctx, buf, buf->len + len); |
349 | 199k | memcpy(buf->data + buf->len, data, len); |
350 | 199k | buf->len += len; |
351 | 199k | buf->unused_bits = 0; |
352 | 199k | } |
353 | | |
354 | | void |
355 | | fz_append_byte(fz_context *ctx, fz_buffer *buf, int val) |
356 | 1.30G | { |
357 | 1.30G | if (buf->len + 1 > buf->cap) |
358 | 32.5k | fz_grow_buffer(ctx, buf); |
359 | 1.30G | buf->data[buf->len++] = val; |
360 | 1.30G | buf->unused_bits = 0; |
361 | 1.30G | } |
362 | | |
363 | | void |
364 | | fz_append_rune(fz_context *ctx, fz_buffer *buf, int c) |
365 | 0 | { |
366 | 0 | char data[10]; |
367 | 0 | int len = fz_runetochar(data, c); |
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_int32_be(fz_context *ctx, fz_buffer *buf, int x) |
377 | 24.1k | { |
378 | 24.1k | fz_append_byte(ctx, buf, (x >> 24) & 0xFF); |
379 | 24.1k | fz_append_byte(ctx, buf, (x >> 16) & 0xFF); |
380 | 24.1k | fz_append_byte(ctx, buf, (x >> 8) & 0xFF); |
381 | 24.1k | fz_append_byte(ctx, buf, (x) & 0xFF); |
382 | 24.1k | } |
383 | | |
384 | | void |
385 | | fz_append_int16_be(fz_context *ctx, fz_buffer *buf, int x) |
386 | 1.02k | { |
387 | 1.02k | fz_append_byte(ctx, buf, (x >> 8) & 0xFF); |
388 | 1.02k | fz_append_byte(ctx, buf, (x) & 0xFF); |
389 | 1.02k | } |
390 | | |
391 | | void |
392 | | fz_append_int32_le(fz_context *ctx, fz_buffer *buf, int x) |
393 | 0 | { |
394 | 0 | fz_append_byte(ctx, buf, (x)&0xFF); |
395 | 0 | fz_append_byte(ctx, buf, (x>>8)&0xFF); |
396 | 0 | fz_append_byte(ctx, buf, (x>>16)&0xFF); |
397 | 0 | fz_append_byte(ctx, buf, (x>>24)&0xFF); |
398 | 0 | } |
399 | | |
400 | | void |
401 | | fz_append_int16_le(fz_context *ctx, fz_buffer *buf, int x) |
402 | 0 | { |
403 | 0 | fz_append_byte(ctx, buf, (x)&0xFF); |
404 | 0 | fz_append_byte(ctx, buf, (x>>8)&0xFF); |
405 | 0 | } |
406 | | |
407 | | void |
408 | | fz_append_bits(fz_context *ctx, fz_buffer *buf, int val, int bits) |
409 | 0 | { |
410 | 0 | int shift; |
411 | | |
412 | | /* Throughout this code, the invariant is that we need to write the |
413 | | * bottom 'bits' bits of 'val' into the stream. On entry we assume |
414 | | * that val & ((1<<bits)-1) == val, but we do not rely on this after |
415 | | * having written the first partial byte. */ |
416 | |
|
417 | 0 | if (bits == 0) |
418 | 0 | return; |
419 | | |
420 | | /* buf->len always covers all the bits in the buffer, including |
421 | | * any unused ones in the last byte, which will always be 0. |
422 | | * buf->unused_bits = the number of unused bits in the last byte. |
423 | | */ |
424 | | |
425 | | /* Find the amount we need to shift val up by so that it will be in |
426 | | * the correct position to be inserted into any existing data byte. */ |
427 | 0 | shift = (buf->unused_bits - bits); |
428 | | |
429 | | /* Extend the buffer as required before we start; that way we never |
430 | | * fail part way during writing. If shift < 0, then we'll need -shift |
431 | | * more bits. */ |
432 | 0 | if (shift < 0) |
433 | 0 | { |
434 | 0 | int extra = (7-shift)>>3; /* Round up to bytes */ |
435 | 0 | fz_ensure_buffer(ctx, buf, buf->len + extra); |
436 | 0 | } |
437 | | |
438 | | /* Write any bits that will fit into the existing byte */ |
439 | 0 | if (buf->unused_bits) |
440 | 0 | { |
441 | 0 | buf->data[buf->len-1] |= (shift >= 0 ? (((unsigned int)val)<<shift) : (((unsigned int)val)>>-shift)); |
442 | 0 | if (shift >= 0) |
443 | 0 | { |
444 | | /* If we were shifting up, we're done. */ |
445 | 0 | buf->unused_bits -= bits; |
446 | 0 | return; |
447 | 0 | } |
448 | | /* The number of bits left to write is the number that didn't |
449 | | * fit in this first byte. */ |
450 | 0 | bits = -shift; |
451 | 0 | } |
452 | | |
453 | | /* Write any whole bytes */ |
454 | 0 | while (bits >= 8) |
455 | 0 | { |
456 | 0 | bits -= 8; |
457 | 0 | buf->data[buf->len++] = val>>bits; |
458 | 0 | } |
459 | | |
460 | | /* Write trailing bits (with 0's in unused bits) */ |
461 | 0 | if (bits > 0) |
462 | 0 | { |
463 | 0 | bits = 8-bits; |
464 | 0 | buf->data[buf->len++] = val<<bits; |
465 | 0 | } |
466 | 0 | buf->unused_bits = bits; |
467 | 0 | } |
468 | | |
469 | | void |
470 | | fz_append_bits_pad(fz_context *ctx, fz_buffer *buf) |
471 | 0 | { |
472 | 0 | buf->unused_bits = 0; |
473 | 0 | } |
474 | | |
475 | | static void fz_append_emit(fz_context *ctx, void *buffer, int c) |
476 | 84.1M | { |
477 | 84.1M | fz_append_byte(ctx, buffer, c); |
478 | 84.1M | } |
479 | | |
480 | | void |
481 | | fz_append_printf(fz_context *ctx, fz_buffer *buffer, const char *fmt, ...) |
482 | 5.42M | { |
483 | 5.42M | va_list args; |
484 | 5.42M | va_start(args, fmt); |
485 | 5.42M | fz_format_string(ctx, buffer, fz_append_emit, fmt, args); |
486 | 5.42M | va_end(args); |
487 | 5.42M | } |
488 | | |
489 | | void |
490 | | fz_append_vprintf(fz_context *ctx, fz_buffer *buffer, const char *fmt, va_list args) |
491 | 0 | { |
492 | 0 | fz_format_string(ctx, buffer, fz_append_emit, fmt, args); |
493 | 0 | } |
494 | | |
495 | | void |
496 | | fz_append_pdf_string(fz_context *ctx, fz_buffer *buffer, const char *text) |
497 | 0 | { |
498 | 0 | size_t len = 2; |
499 | 0 | const char *s = text; |
500 | 0 | char *d; |
501 | 0 | char c; |
502 | |
|
503 | 0 | while ((c = *s++) != 0) |
504 | 0 | { |
505 | 0 | switch (c) |
506 | 0 | { |
507 | 0 | case '\n': |
508 | 0 | case '\r': |
509 | 0 | case '\t': |
510 | 0 | case '\b': |
511 | 0 | case '\f': |
512 | 0 | case '(': |
513 | 0 | case ')': |
514 | 0 | case '\\': |
515 | 0 | len++; |
516 | 0 | break; |
517 | 0 | } |
518 | 0 | len++; |
519 | 0 | } |
520 | | |
521 | 0 | while(buffer->cap - buffer->len < len) |
522 | 0 | fz_grow_buffer(ctx, buffer); |
523 | |
|
524 | 0 | s = text; |
525 | 0 | d = (char *)buffer->data + buffer->len; |
526 | 0 | *d++ = '('; |
527 | 0 | while ((c = *s++) != 0) |
528 | 0 | { |
529 | 0 | switch (c) |
530 | 0 | { |
531 | 0 | case '\n': |
532 | 0 | *d++ = '\\'; |
533 | 0 | *d++ = 'n'; |
534 | 0 | break; |
535 | 0 | case '\r': |
536 | 0 | *d++ = '\\'; |
537 | 0 | *d++ = 'r'; |
538 | 0 | break; |
539 | 0 | case '\t': |
540 | 0 | *d++ = '\\'; |
541 | 0 | *d++ = 't'; |
542 | 0 | break; |
543 | 0 | case '\b': |
544 | 0 | *d++ = '\\'; |
545 | 0 | *d++ = 'b'; |
546 | 0 | break; |
547 | 0 | case '\f': |
548 | 0 | *d++ = '\\'; |
549 | 0 | *d++ = 'f'; |
550 | 0 | break; |
551 | 0 | case '(': |
552 | 0 | *d++ = '\\'; |
553 | 0 | *d++ = '('; |
554 | 0 | break; |
555 | 0 | case ')': |
556 | 0 | *d++ = '\\'; |
557 | 0 | *d++ = ')'; |
558 | 0 | break; |
559 | 0 | case '\\': |
560 | 0 | *d++ = '\\'; |
561 | 0 | *d++ = '\\'; |
562 | 0 | break; |
563 | 0 | default: |
564 | 0 | *d++ = c; |
565 | 0 | } |
566 | 0 | } |
567 | 0 | *d = ')'; |
568 | 0 | buffer->len += len; |
569 | 0 | } |
570 | | |
571 | | void |
572 | | fz_md5_buffer(fz_context *ctx, fz_buffer *buffer, unsigned char digest[16]) |
573 | 73.8k | { |
574 | 73.8k | fz_md5 state; |
575 | 73.8k | fz_md5_init(&state); |
576 | 73.8k | if (buffer) |
577 | 73.8k | fz_md5_update(&state, buffer->data, buffer->len); |
578 | 73.8k | fz_md5_final(&state, digest); |
579 | 73.8k | } |
580 | | |
581 | | #ifdef TEST_BUFFER_WRITE |
582 | | |
583 | | #define TEST_LEN 1024 |
584 | | |
585 | | void |
586 | | fz_test_buffer_write(fz_context *ctx) |
587 | | { |
588 | | fz_buffer *master = fz_new_buffer(ctx, TEST_LEN); |
589 | | fz_buffer *copy = fz_new_buffer(ctx, TEST_LEN); |
590 | | fz_stream *stm; |
591 | | int i, j, k; |
592 | | |
593 | | /* Make us a dummy buffer */ |
594 | | for (i = 0; i < TEST_LEN; i++) |
595 | | { |
596 | | master->data[i] = rand(); |
597 | | } |
598 | | master->len = TEST_LEN; |
599 | | |
600 | | /* Now copy that buffer several times, checking it for validity */ |
601 | | stm = fz_open_buffer(ctx, master); |
602 | | for (i = 0; i < 256; i++) |
603 | | { |
604 | | memset(copy->data, i, TEST_LEN); |
605 | | copy->len = 0; |
606 | | j = TEST_LEN * 8; |
607 | | do |
608 | | { |
609 | | k = (rand() & 31)+1; |
610 | | if (k > j) |
611 | | k = j; |
612 | | fz_append_bits(ctx, copy, fz_read_bits(ctx, stm, k), k); |
613 | | j -= k; |
614 | | } |
615 | | while (j); |
616 | | |
617 | | if (memcmp(copy->data, master->data, TEST_LEN) != 0) |
618 | | fprintf(stderr, "Copied buffer is different!\n"); |
619 | | fz_seek(stm, 0, 0); |
620 | | } |
621 | | fz_drop_stream(stm); |
622 | | fz_drop_buffer(ctx, master); |
623 | | fz_drop_buffer(ctx, copy); |
624 | | } |
625 | | #endif |