Branch data Line data Source code
1 : : /* -*- mode: C -*-
2 : : *
3 : : * File: pdf-stm.c
4 : : * Date: Fri Jul 6 18:43:15 2007
5 : : *
6 : : * GNU PDF Library - Streams
7 : : *
8 : : */
9 : :
10 : : /* Copyright (C) 2007-2011 Free Software Foundation, Inc. */
11 : :
12 : : /* This program is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU General Public License as published by
14 : : * the Free Software Foundation, either version 3 of the License, or
15 : : * (at your option) any later version.
16 : : *
17 : : * This program is distributed in the hope that it will be useful,
18 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 : : * GNU General Public License for more details.
21 : : *
22 : : * You should have received a copy of the GNU General Public License
23 : : * along with this program. If not, see <http://www.gnu.org/licenses/>.
24 : : */
25 : :
26 : : #include <config.h>
27 : :
28 : : #include <unistd.h>
29 : : #include <string.h>
30 : :
31 : : #include <pdf-alloc.h>
32 : : #include <pdf-stm.h>
33 : : #include <pdf-stm-be.h>
34 : : #include <pdf-stm-be-mem.h>
35 : : #include <pdf-stm-be-cfile.h>
36 : : #include <pdf-stm-be-file.h>
37 : :
38 : : /* Forward declarations */
39 : :
40 : : static pdf_bool_t pdf_stm_init (pdf_stm_t *stm,
41 : : pdf_size_t cache_size,
42 : : enum pdf_stm_mode_e mode,
43 : : pdf_error_t **error);
44 : :
45 : : static pdf_bool_t pdf_stm_read_peek_char (pdf_stm_t *stm,
46 : : pdf_uchar_t *read_char,
47 : : pdf_bool_t peek,
48 : : pdf_error_t **error);
49 : :
50 : : /*
51 : : * Public functions
52 : : */
53 : :
54 : : pdf_stm_t *
55 : 0 : pdf_stm_cfile_new (FILE *file,
56 : : pdf_off_t offset,
57 : : pdf_size_t cache_size,
58 : : enum pdf_stm_mode_e mode,
59 : : pdf_error_t **error)
60 : : {
61 : : pdf_stm_t *stm;
62 : :
63 [ # # ]: 0 : PDF_ASSERT_POINTER_RETURN_VAL (file, NULL);
64 : : /* Note: if cache_size == 0, we'll use the default one */
65 : :
66 : : /* Allocate memory for the new stream */
67 : 0 : stm = pdf_alloc (sizeof (struct pdf_stm_s));
68 [ # # ]: 0 : if (!stm)
69 : : {
70 : 0 : pdf_set_error (error,
71 : : PDF_EDOMAIN_BASE_STM,
72 : : PDF_ENOMEM,
73 : : "not enough memory to create a stream: "
74 : : "couldn't allocate %lu bytes",
75 : : (unsigned long) sizeof (struct pdf_stm_s));
76 : 0 : return NULL;
77 : : }
78 : :
79 : : /* Initialize a file stream */
80 : 0 : stm->type = PDF_STM_FILE;
81 : 0 : stm->backend = pdf_stm_be_new_cfile (file, offset, error);
82 [ # # ]: 0 : if (!stm->backend)
83 : : {
84 : 0 : pdf_stm_destroy (stm);
85 : 0 : return NULL;
86 : : }
87 : :
88 : : /* Initialize the common parts */
89 [ # # ]: 0 : if (!pdf_stm_init (stm, cache_size, mode, error))
90 : : {
91 : 0 : pdf_stm_destroy (stm);
92 : 0 : return NULL;
93 : : }
94 : 0 : return stm;
95 : : }
96 : :
97 : : pdf_stm_t *
98 : 11 : pdf_stm_file_new (pdf_fsys_file_t *file,
99 : : pdf_off_t offset,
100 : : pdf_size_t cache_size,
101 : : enum pdf_stm_mode_e mode,
102 : : pdf_error_t **error)
103 : : {
104 : : pdf_stm_t *stm;
105 : :
106 [ - + ]: 11 : PDF_ASSERT_POINTER_RETURN_VAL (file, NULL);
107 : : /* Note: if cache_size == 0, we'll use the default one */
108 : :
109 : : /* Allocate memory for the new stream */
110 : 11 : stm = pdf_alloc (sizeof (struct pdf_stm_s));
111 [ - + ]: 11 : if (!stm)
112 : : {
113 : 0 : pdf_set_error (error,
114 : : PDF_EDOMAIN_BASE_STM,
115 : : PDF_ENOMEM,
116 : : "not enough memory to create a stream: "
117 : : "couldn't allocate %lu bytes",
118 : : (unsigned long) sizeof (struct pdf_stm_s));
119 : 0 : return NULL;
120 : : }
121 : :
122 : : /* Initialize a file stream */
123 : 11 : stm->type = PDF_STM_FILE;
124 : 11 : stm->backend = pdf_stm_be_new_file (file, offset, error);
125 [ - + ]: 11 : if (!stm->backend)
126 : : {
127 : 0 : pdf_stm_destroy (stm);
128 : 0 : return NULL;
129 : : }
130 : :
131 : : /* Initialize the common parts */
132 [ - + ]: 11 : if (!pdf_stm_init (stm, cache_size, mode, error))
133 : : {
134 : 0 : pdf_stm_destroy (stm);
135 : 0 : return NULL;
136 : : }
137 : 11 : return stm;
138 : : }
139 : :
140 : : pdf_stm_t *
141 : 1284 : pdf_stm_mem_new (pdf_uchar_t *buffer,
142 : : pdf_size_t size,
143 : : pdf_size_t cache_size,
144 : : enum pdf_stm_mode_e mode,
145 : : pdf_error_t **error)
146 : : {
147 : : pdf_stm_t *stm;
148 : :
149 [ - + ]: 1284 : PDF_ASSERT_POINTER_RETURN_VAL (buffer, NULL);
150 [ - + ]: 1284 : PDF_ASSERT_RETURN_VAL (size > 0, NULL);
151 : : /* Note: if cache_size == 0, we'll use the default one */
152 : :
153 : : /* Allocate memory for the new stream */
154 : 1284 : stm = pdf_alloc (sizeof (struct pdf_stm_s));
155 [ - + ]: 1284 : if (!stm)
156 : : {
157 : 0 : pdf_set_error (error,
158 : : PDF_EDOMAIN_BASE_STM,
159 : : PDF_ENOMEM,
160 : : "not enough memory to create a stream: "
161 : : "couldn't allocate %lu bytes",
162 : : (unsigned long) sizeof (struct pdf_stm_s));
163 : 0 : return NULL;
164 : : }
165 : :
166 : : /* Initialize a memory stream */
167 : 1284 : stm->type = PDF_STM_MEM;
168 : 1284 : stm->backend = pdf_stm_be_new_mem (buffer, size, 0, error);
169 [ - + ]: 1284 : if (!stm->backend)
170 : : {
171 : 0 : pdf_stm_destroy (stm);
172 : 0 : return NULL;
173 : : }
174 : :
175 : : /* Initialize the common parts */
176 [ - + ]: 1284 : if (!pdf_stm_init (stm, cache_size, mode, error))
177 : : {
178 : 0 : pdf_stm_destroy (stm);
179 : 0 : return NULL;
180 : : }
181 : 1284 : return stm;
182 : : }
183 : :
184 : : void
185 : 1114 : pdf_stm_destroy (pdf_stm_t *stm)
186 : : {
187 : : pdf_stm_filter_t *filter;
188 : 1114 : pdf_size_t flushed_bytes = 0;
189 : :
190 : : /* Flush the cache ignoring any possible error, finishing the filters */
191 [ + + ]: 1114 : if (stm->mode == PDF_STM_WRITE)
192 : 306 : pdf_stm_flush (stm, PDF_TRUE, &flushed_bytes, NULL);
193 : :
194 : : /* Destroy the backend */
195 : 1114 : pdf_stm_be_destroy (stm->backend);
196 : :
197 : : /* Destroy the cache */
198 : 1114 : pdf_buffer_destroy (stm->cache);
199 : :
200 : : /* Destroy the filter chain */
201 : 1114 : filter = stm->filter;
202 [ + + ]: 2714 : while (filter != NULL)
203 : : {
204 : : pdf_stm_filter_t *filter_to_delete;
205 : :
206 : 1600 : filter_to_delete = filter;
207 : 1600 : filter = pdf_stm_filter_get_next (filter);
208 : 1600 : pdf_stm_filter_destroy (filter_to_delete);
209 : : }
210 : :
211 : : /* Deallocate the stm structure */
212 : 1114 : pdf_dealloc (stm);
213 : 1114 : }
214 : :
215 : : enum pdf_stm_mode_e
216 : 737 : pdf_stm_get_mode (pdf_stm_t *stm)
217 : : {
218 [ - + ]: 737 : PDF_ASSERT_POINTER_RETURN_VAL (stm, PDF_STM_UNKNOWN);
219 : :
220 : 737 : return stm->mode;
221 : : }
222 : :
223 : : pdf_bool_t
224 : 2767 : pdf_stm_read (pdf_stm_t *stm,
225 : : pdf_uchar_t *buf,
226 : : pdf_size_t bytes,
227 : : pdf_size_t *read_bytes,
228 : : pdf_error_t **error)
229 : : {
230 : : pdf_bool_t eof;
231 : :
232 [ - + ]: 2767 : PDF_ASSERT_POINTER_RETURN_VAL (stm, PDF_FALSE);
233 [ - + ]: 2767 : PDF_ASSERT_POINTER_RETURN_VAL (buf, PDF_FALSE);
234 [ - + ]: 2767 : PDF_ASSERT_RETURN_VAL (bytes > 0, PDF_FALSE);
235 : :
236 : 2767 : *read_bytes = 0;
237 : :
238 : : /* Is this a read stream? */
239 [ - + ]: 2767 : if (stm->mode != PDF_STM_READ)
240 : : {
241 : : /* Invalid operation */
242 : 0 : pdf_set_error (error,
243 : : PDF_EDOMAIN_BASE_STM,
244 : : PDF_EINVOP,
245 : : "cannot read from a write stream");
246 : 0 : return PDF_FALSE;
247 : : }
248 : :
249 : 2767 : eof = PDF_FALSE;
250 [ + + ][ + + ]: 5506 : while (*read_bytes < bytes && !eof)
251 : : {
252 : : pdf_size_t pending_bytes;
253 : : pdf_size_t to_copy_bytes;
254 : : pdf_size_t cache_size;
255 : :
256 : : /* If the cache is empty, refill it with filtered data */
257 [ + + ]: 2809 : if (pdf_buffer_eob_p (stm->cache))
258 : : {
259 : 407 : pdf_error_t *inner_error = NULL;
260 : :
261 : 407 : pdf_buffer_rewind (stm->cache);
262 : :
263 : : /* Break if apply fails */
264 [ + + ]: 407 : if (!pdf_stm_filter_apply (stm->filter,
265 : : PDF_FALSE,
266 : : &eof,
267 : : &inner_error))
268 : : {
269 : : /* Report error */
270 : 70 : pdf_propagate_error (error, inner_error);
271 : 70 : return PDF_FALSE;
272 : : }
273 : : }
274 : :
275 : : /* Read data from the cache */
276 [ - + ]: 2739 : PDF_ASSERT (stm->cache->wp >= stm->cache->rp);
277 : 2739 : pending_bytes = bytes - *read_bytes;
278 : 2739 : cache_size = stm->cache->wp - stm->cache->rp;
279 : 2739 : to_copy_bytes = PDF_MIN (pending_bytes, cache_size);
280 : :
281 : 5478 : memcpy ((buf + *read_bytes),
282 : 5478 : stm->cache->data + stm->cache->rp,
283 : : to_copy_bytes);
284 : :
285 : 2739 : *read_bytes += to_copy_bytes;
286 : 2739 : stm->cache->rp += to_copy_bytes;
287 : : }
288 : :
289 : : /* Update the sequential counter */
290 : 2697 : stm->seq_counter += *read_bytes;
291 : :
292 : : /* On EOF, we return PDF_FALSE without error */
293 [ + + ][ + + ]: 2767 : return ((eof && *read_bytes < bytes) ? PDF_FALSE : PDF_TRUE);
294 : : }
295 : :
296 : : pdf_bool_t
297 : 3032 : pdf_stm_write (pdf_stm_t *stm,
298 : : const pdf_uchar_t *buf,
299 : : pdf_size_t bytes,
300 : : pdf_size_t *written_bytes,
301 : : pdf_error_t **error)
302 : : {
303 : : pdf_stm_filter_t *tail_filter;
304 : : pdf_buffer_t *tail_buffer;
305 : 3032 : pdf_bool_t eof = PDF_FALSE;
306 : :
307 [ - + ]: 3032 : PDF_ASSERT_POINTER_RETURN_VAL (stm, PDF_FALSE);
308 [ - + ]: 3032 : PDF_ASSERT_POINTER_RETURN_VAL (buf, PDF_FALSE);
309 [ - + ]: 3032 : PDF_ASSERT_RETURN_VAL (bytes > 0, PDF_FALSE);
310 : :
311 : 3032 : *written_bytes = 0;
312 : :
313 : : /* Is this a write stream? */
314 [ - + ]: 3032 : if (stm->mode != PDF_STM_WRITE)
315 : : {
316 : : /* Invalid operation */
317 : 0 : pdf_set_error (error,
318 : : PDF_EDOMAIN_BASE_STM,
319 : : PDF_EINVOP,
320 : : "cannot write in a read stream");
321 : 0 : return PDF_FALSE;
322 : : }
323 : :
324 : 3032 : tail_filter = pdf_stm_filter_get_tail (stm->filter);
325 : 3032 : tail_buffer = pdf_stm_filter_get_in (tail_filter);
326 : :
327 [ + + ]: 6068 : while (*written_bytes < bytes)
328 : : {
329 : : pdf_size_t tail_buffer_size;
330 : : pdf_size_t to_write_bytes;
331 : : pdf_size_t pending_bytes;
332 : :
333 [ + + ][ + - ]: 3037 : if ((pdf_buffer_full_p (tail_buffer)) &&
334 : : (!pdf_buffer_eob_p (tail_buffer)))
335 : : {
336 : 5 : pdf_size_t flushed_bytes = 0;
337 : 5 : pdf_error_t *inner_error = NULL;
338 : :
339 : : /* Flush the cache */
340 [ + + ]: 5 : if (!pdf_stm_flush (stm,
341 : : PDF_FALSE,
342 : : &flushed_bytes,
343 : : &inner_error))
344 : : {
345 [ - + ]: 1 : if (inner_error)
346 : : {
347 : : /* Error flushing */
348 : 0 : pdf_propagate_error (error, inner_error);
349 : 0 : return PDF_FALSE;
350 : : }
351 : :
352 : : /* flush returned PDF_FALSE without error: EOF */
353 : 1 : eof = PDF_TRUE;
354 : 1 : break;
355 : : }
356 : :
357 : : /* No flush needed, keep on */
358 : : }
359 : :
360 : : /* Write the data into the tail buffer. Note that at this
361 : : * point the tail buffer should be empty */
362 : 3036 : tail_buffer_size = tail_buffer->size - tail_buffer->wp;
363 : 3036 : pending_bytes = bytes - *written_bytes;
364 : :
365 : 3036 : to_write_bytes = PDF_MIN (pending_bytes, tail_buffer_size);
366 : :
367 [ + - ]: 3036 : if (to_write_bytes != 0)
368 : : {
369 : 3036 : memcpy (tail_buffer->data + tail_buffer->wp,
370 : 3036 : buf + *written_bytes,
371 : : to_write_bytes);
372 : :
373 : 3036 : *written_bytes += to_write_bytes;
374 : 3036 : tail_buffer->wp += to_write_bytes;
375 : : }
376 : : }
377 : :
378 : : /* Update the sequential counter */
379 : 3032 : stm->seq_counter += *written_bytes;
380 : :
381 [ + + ][ - + ]: 3032 : return ((eof && *written_bytes < bytes) ? PDF_FALSE : PDF_TRUE);
382 : : }
383 : :
384 : : pdf_bool_t
385 : 583 : pdf_stm_flush (pdf_stm_t *stm,
386 : : pdf_bool_t finish,
387 : : pdf_size_t *flushed_bytes,
388 : : pdf_error_t **error)
389 : : {
390 : : pdf_stm_filter_t *tail_filter;
391 : : pdf_buffer_t *tail_buffer;
392 : 583 : pdf_error_t *inner_error = NULL;
393 : 583 : pdf_bool_t eof = PDF_FALSE;
394 : :
395 : : /* NOTE: NULL flushed_bytes is ALLOWED */
396 : :
397 [ - + ]: 583 : PDF_ASSERT_POINTER_RETURN_VAL (stm, -1);
398 : :
399 : : /* Is this a write stream? */
400 [ + + ]: 583 : if (stm->mode != PDF_STM_WRITE)
401 : : {
402 : : /* Invalid operation */
403 : 1 : pdf_set_error (error,
404 : : PDF_EDOMAIN_BASE_STM,
405 : : PDF_EINVOP,
406 : : "cannot write in a read stream");
407 : 1 : return PDF_FALSE;
408 : : }
409 : :
410 : : /* Apply the head filter until the filter chain gets empty */
411 : 582 : tail_filter = pdf_stm_filter_get_tail (stm->filter);
412 : 582 : tail_buffer = pdf_stm_filter_get_in (tail_filter);
413 : :
414 [ + + ]: 582 : if (flushed_bytes)
415 : 315 : *flushed_bytes = 0;
416 : :
417 : : while (PDF_TRUE)
418 : : {
419 : : pdf_size_t cache_size;
420 : : pdf_ssize_t written_bytes;
421 : : pdf_size_t tail_size;
422 : :
423 : 821 : tail_size = tail_buffer->wp - tail_buffer->rp;
424 : :
425 : : /* Break only on error */
426 [ + + ]: 821 : if (!pdf_stm_filter_apply (stm->filter, finish, &eof, &inner_error))
427 : : break;
428 : :
429 : : /* Update the number of flushed bytes */
430 [ + + ]: 681 : if (flushed_bytes)
431 : 287 : *flushed_bytes += tail_size - (tail_buffer->wp - tail_buffer->rp);
432 : :
433 : : /* Avoid false EEOF error */
434 [ + + ][ + + ]: 681 : if (eof && pdf_buffer_eob_p (stm->cache))
435 : : {
436 : 440 : eof = PDF_FALSE;
437 : 440 : pdf_buffer_rewind (tail_buffer);
438 : 440 : break;
439 : : }
440 : :
441 : : /* Write the data from the buffer cache into the backend */
442 : 241 : cache_size = stm->cache->wp - stm->cache->rp;
443 : 241 : written_bytes = pdf_stm_be_write (stm->backend,
444 : : stm->cache->data + stm->cache->rp,
445 : : cache_size,
446 : : &inner_error);
447 [ + - ]: 241 : if (written_bytes < 0)
448 : : break;
449 : :
450 [ + + ]: 241 : if (written_bytes != cache_size)
451 : : {
452 : : /* EOF, could not write all the contents of the cache buffer into
453 : : * the backend */
454 : 2 : stm->cache->rp += written_bytes;
455 : 2 : eof = PDF_TRUE;
456 : 2 : break;
457 : : }
458 : :
459 : : /* Rewind the cache */
460 : 239 : pdf_buffer_rewind (stm->cache);
461 : 239 : }
462 : :
463 : : /* Propagate error */
464 [ + + ]: 582 : if (inner_error)
465 : : {
466 : 140 : pdf_propagate_error (error, inner_error);
467 : 140 : return PDF_FALSE;
468 : : }
469 : :
470 [ + + ]: 583 : return (eof ? PDF_FALSE : PDF_TRUE);;
471 : : }
472 : :
473 : : pdf_bool_t
474 : 0 : pdf_stm_supported_filter_p (enum pdf_stm_filter_type_e filter_type)
475 : : {
476 [ # # ]: 0 : PDF_ASSERT_RETURN_VAL (filter_type >= PDF_STM_FILTER_NULL, PDF_FALSE);
477 [ # # ]: 0 : PDF_ASSERT_RETURN_VAL (filter_type < PDF_STM_FILTER_LAST, PDF_FALSE);
478 : :
479 : 0 : return pdf_stm_filter_p (filter_type);
480 : : }
481 : :
482 : : pdf_bool_t
483 : 486 : pdf_stm_install_filter (pdf_stm_t *stm,
484 : : enum pdf_stm_filter_type_e filter_type,
485 : : const pdf_hash_t *filter_params,
486 : : pdf_error_t **error)
487 : : {
488 : : pdf_stm_filter_t *filter;
489 : : enum pdf_stm_filter_mode_e filter_mode;
490 : :
491 [ - + ]: 486 : PDF_ASSERT_POINTER_RETURN_VAL (stm, PDF_FALSE);
492 : :
493 : 486 : filter_mode = (stm->mode == PDF_STM_READ ?
494 : : PDF_STM_FILTER_MODE_READ :
495 : : PDF_STM_FILTER_MODE_WRITE);
496 : :
497 : : /* Create the new filter. Note that filter_params is passed directly to the
498 : : * filter implementation creator, and that it may well be NULL. */
499 : 486 : filter = pdf_stm_filter_new (filter_type,
500 : : filter_params,
501 : 486 : stm->cache->size,
502 : : filter_mode,
503 : : error);
504 [ - + ]: 486 : if (!filter)
505 : 0 : return PDF_FALSE;
506 : :
507 : : /* Set the new filter as the new head of the filter chain */
508 : 486 : pdf_stm_filter_set_next (filter, stm->filter);
509 : 486 : pdf_stm_filter_set_out (filter, stm->cache);
510 : 486 : pdf_stm_filter_set_out (stm->filter, pdf_stm_filter_get_in (filter));
511 : 486 : stm->filter = filter;
512 : :
513 : 486 : return PDF_TRUE;
514 : : }
515 : :
516 : : pdf_bool_t
517 : 89744 : pdf_stm_read_char (pdf_stm_t *stm,
518 : : pdf_uchar_t *read_char,
519 : : pdf_error_t **error)
520 : : {
521 [ - + ]: 89744 : PDF_ASSERT_POINTER_RETURN_VAL (stm, PDF_FALSE);
522 [ - + ]: 89744 : PDF_ASSERT_POINTER_RETURN_VAL (read_char, PDF_FALSE);
523 : :
524 : 89744 : return pdf_stm_read_peek_char (stm, read_char, PDF_FALSE, error);
525 : : }
526 : :
527 : : pdf_bool_t
528 : 49685 : pdf_stm_peek_char (pdf_stm_t *stm,
529 : : pdf_uchar_t *read_char,
530 : : pdf_error_t **error)
531 : : {
532 [ - + ]: 49685 : PDF_ASSERT_POINTER_RETURN_VAL (stm, PDF_FALSE);
533 [ - + ]: 49685 : PDF_ASSERT_POINTER_RETURN_VAL (read_char, PDF_FALSE);
534 : :
535 : 49685 : return pdf_stm_read_peek_char (stm, read_char, PDF_TRUE, error);
536 : : }
537 : :
538 : : pdf_off_t
539 : 23 : pdf_stm_bseek (pdf_stm_t *stm,
540 : : pdf_off_t pos)
541 : : {
542 : : pdf_off_t cur_pos;
543 : : pdf_off_t new_pos;
544 : :
545 [ - + ]: 23 : PDF_ASSERT_POINTER_RETURN_VAL (stm, (pdf_off_t)-1);
546 : :
547 : 23 : cur_pos = pdf_stm_tell (stm);
548 : :
549 [ + + ]: 23 : if (stm->mode == PDF_STM_READ)
550 : : {
551 : : /* Discard the cache contents */
552 : 22 : pdf_buffer_rewind (stm->cache);
553 : :
554 : : /* Seek the backend */
555 : 22 : new_pos = pdf_stm_be_seek (stm->backend, pos);
556 : : }
557 : : else /* Writing stream */
558 : : {
559 : : pdf_stm_filter_t *tail_filter;
560 : : pdf_buffer_t *tail_buffer;
561 : :
562 : 1 : tail_filter = pdf_stm_filter_get_tail (stm->filter);
563 : 1 : tail_buffer = pdf_stm_filter_get_in (tail_filter);
564 : :
565 [ - + ]: 1 : if (!pdf_buffer_eob_p (tail_buffer))
566 : : {
567 : 0 : pdf_error_t *inner_error = NULL;
568 : 0 : pdf_size_t flushed_bytes = 0;
569 : :
570 : : /* Flush the stream */
571 [ # # ][ # # ]: 0 : if (!pdf_stm_flush (stm, PDF_FALSE, &flushed_bytes, &inner_error) &&
572 : 0 : inner_error)
573 : : {
574 : : /* Error flushing the stream: return the current position */
575 : 0 : pdf_error_destroy (inner_error);
576 : 0 : return cur_pos;
577 : : }
578 : : }
579 : :
580 : : /* Note that if there is an EOF condition in the backend we are
581 : : * going to loose data */
582 : 1 : pdf_buffer_rewind (tail_buffer);
583 : :
584 : : /* Seek the backend */
585 : 1 : new_pos = pdf_stm_be_seek (stm->backend, pos);
586 : : }
587 : :
588 : : /* Reset the sequential counter */
589 : 23 : stm->seq_counter = 0;
590 : :
591 : 23 : return new_pos;
592 : : }
593 : :
594 : : pdf_off_t
595 : 77 : pdf_stm_btell (pdf_stm_t *stm)
596 : : {
597 : : pdf_off_t pos;
598 : : pdf_size_t cache_size;
599 : :
600 [ - + ]: 77 : PDF_ASSERT_POINTER_RETURN_VAL (stm, (pdf_off_t)-1);
601 : :
602 [ + - ]: 77 : if (stm->mode == PDF_STM_READ)
603 : : {
604 : 77 : cache_size = stm->cache->wp - stm->cache->rp;
605 : 77 : pos = pdf_stm_be_tell (stm->backend) - cache_size;
606 : : }
607 : : else /* Writing stream */
608 : : {
609 : : pdf_stm_filter_t *tail_filter;
610 : : pdf_buffer_t *tail_buffer;
611 : :
612 : 0 : tail_filter = pdf_stm_filter_get_tail (stm->filter);
613 : 0 : tail_buffer = pdf_stm_filter_get_in (tail_filter);
614 : :
615 : 0 : cache_size = tail_buffer->wp - tail_buffer->rp;
616 : 0 : pos = pdf_stm_be_tell (stm->backend) - cache_size;
617 : : }
618 : :
619 : 77 : return pos;
620 : : }
621 : :
622 : : pdf_off_t
623 : 2540 : pdf_stm_tell (pdf_stm_t *stm)
624 : : {
625 [ - + ]: 2540 : PDF_ASSERT_POINTER_RETURN_VAL (stm, (pdf_off_t)-1);
626 : :
627 : 2540 : return stm->seq_counter;
628 : : }
629 : :
630 : : /*
631 : : * Private functions
632 : : */
633 : :
634 : : static pdf_bool_t
635 : 1295 : pdf_stm_init (pdf_stm_t *stm,
636 : : pdf_size_t cache_size,
637 : : enum pdf_stm_mode_e mode,
638 : : pdf_error_t **error)
639 : : {
640 : : /* Use the default cache size */
641 [ + + ]: 1295 : if (cache_size == 0)
642 : 1111 : cache_size = PDF_STM_DEFAULT_CACHE_SIZE;
643 : :
644 : : /* The sequential counter is initially 0 */
645 : 1295 : stm->seq_counter = 0;
646 : :
647 : 1295 : stm->filter = pdf_stm_filter_new (PDF_STM_FILTER_NULL,
648 : : NULL, /* No filter params needed */
649 : : cache_size,
650 : : (mode == PDF_STM_READ ?
651 : : PDF_STM_FILTER_MODE_READ :
652 : : PDF_STM_FILTER_MODE_WRITE),
653 : : error);
654 [ - + ]: 1295 : if (!stm->filter)
655 : 0 : return PDF_FALSE;
656 : :
657 : : /* Initialize the filter cache */
658 : 1295 : stm->cache = pdf_buffer_new (cache_size, error);
659 [ - + ]: 1295 : if (!stm->cache)
660 : 0 : return PDF_FALSE;
661 : :
662 : : /* Configure the filter */
663 : 1295 : stm->mode = mode;
664 [ + + ]: 1295 : if (stm->mode == PDF_STM_READ)
665 : : {
666 : : /* Configuration for a reading stream
667 : : *
668 : : * <cache> <--- <null-filter> <--- <backend>
669 : : */
670 : 989 : pdf_stm_filter_set_out (stm->filter, stm->cache);
671 : 989 : pdf_stm_filter_set_be (stm->filter, stm->backend);
672 : : }
673 : : else
674 : : {
675 : : /* Configuration for a writing stream
676 : : *
677 : : * <null-filter> --> <cache> --> <backend>
678 : : */
679 : 306 : pdf_stm_filter_set_out (stm->filter, stm->cache);
680 : : }
681 : :
682 : 1295 : return PDF_TRUE;
683 : : }
684 : :
685 : : static pdf_bool_t
686 : 139429 : pdf_stm_read_peek_char (pdf_stm_t *stm,
687 : : pdf_uchar_t *read_char,
688 : : pdf_bool_t peek,
689 : : pdf_error_t **error)
690 : : {
691 : : /* Is this a read stream? */
692 [ - + ]: 139429 : if (stm->mode != PDF_STM_READ)
693 : : {
694 : : /* Invalid operation */
695 : 0 : pdf_set_error (error,
696 : : PDF_EDOMAIN_BASE_STM,
697 : : PDF_EINVOP,
698 : : "cannot read from a write stream");
699 : 0 : return PDF_FALSE;
700 : : }
701 : :
702 : : /* Is the cache empty? */
703 [ + + ]: 139429 : if (pdf_buffer_eob_p (stm->cache))
704 : : {
705 : 1121 : pdf_bool_t eof = PDF_FALSE;
706 : 1121 : pdf_error_t *inner_error = NULL;
707 : :
708 : 1121 : pdf_buffer_rewind (stm->cache);
709 [ - + ]: 1121 : if (!pdf_stm_filter_apply (stm->filter,
710 : : PDF_FALSE,
711 : : &eof,
712 : : &inner_error))
713 : : {
714 : 0 : pdf_propagate_error (error, inner_error);
715 : 0 : return PDF_FALSE;
716 : : }
717 : : }
718 : :
719 : : /* If still empty, EOF */
720 [ + + ]: 139429 : if (pdf_buffer_eob_p (stm->cache))
721 : 367 : return PDF_FALSE;
722 : :
723 : : /* Read a character from the cache */
724 : 139062 : *read_char = (pdf_u32_t) stm->cache->data[stm->cache->rp];
725 : :
726 [ + + ]: 139062 : if (!peek)
727 : : {
728 : 89741 : stm->cache->rp++;
729 : 89741 : stm->seq_counter++;
730 : : }
731 : :
732 : 139429 : return PDF_TRUE;
733 : : }
734 : :
735 : : /* End of pdf_stm.c */
|