Hi, After modifying the Fsys API I noticed that stream backends considered an EOF and an error as the same thing (i.e. zero-length write/read). I attach a patch to distinguish one from the other.
BTW, the pdf-stm.c file was DOS encoded so diff made a complete new file although changes were only made to the 'pdf_stm_flush()' function. -gerel ## # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: [email protected] # target_branch: file:///home/gerel/PROJECTS/libgnupdf/trunk/ # testament_sha1: 67f5d91d3a742545d61a5b4a11854d30aefd8d10 # timestamp: 2009-05-18 16:42:16 -0300 # base_revision_id: jema...@termi-20090518133647-gr5fm4bkhivb1bca # # Begin patch === modified file 'ChangeLog' --- ChangeLog 2009-05-18 13:36:47 +0000 +++ ChangeLog 2009-05-18 19:20:19 +0000 @@ -1,3 +1,13 @@ +2009-05-18 Gerardo E. Gidoni <[email protected]> + + * src/base/pdf-stm-be.c: added missing backend error conditions. + + * src/base/pdf-stm-be.h: likewise. + + * src/base/pdf-stm-filter.c: likewise. + + * src/base/pdf-stm.c: likewise. + 2009-05-18 Jose E. Marchesi <[email protected]> * doc/gnupdf.texi (Architectural limits): Typo fixed. Reported by === modified file 'src/base/pdf-stm-be.c' --- src/base/pdf-stm-be.c 2009-05-15 17:55:40 +0000 +++ src/base/pdf-stm-be.c 2009-05-18 19:20:19 +0000 @@ -1,4 +1,4 @@ -/* -*- mode: C -*- Time-stamp: "2009-05-15 13:44:30 gerel" +/* -*- mode: C -*- Time-stamp: "2009-05-18 14:38:39 gerel" * * File: pdf-stm-be.c * Date: Wed Jun 18 21:15:16 2008 @@ -9,6 +9,7 @@ #include <config.h> #include <string.h> +#include <errno.h> #include <pdf-stm-be.h> /* Forward declarations */ @@ -22,21 +23,28 @@ static pdf_off_t pdf_stm_be_mem_seek (pdf_stm_be_t be, pdf_off_t pos); static pdf_off_t pdf_stm_be_mem_tell (pdf_stm_be_t be); -static pdf_size_t pdf_stm_be_file_read (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes); -static pdf_size_t pdf_stm_be_file_write (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes); + +static pdf_status_t pdf_stm_be_file_read (pdf_stm_be_t be, + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t *read_bytes); + +static pdf_status_t pdf_stm_be_file_write (pdf_stm_be_t be, + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t *written_bytes); + static pdf_off_t pdf_stm_be_file_seek (pdf_stm_be_t be, pdf_off_t pos); static pdf_off_t pdf_stm_be_file_tell (pdf_stm_be_t be); -static pdf_size_t pdf_stm_be_cfile_read (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes); -static pdf_size_t pdf_stm_be_cfile_write (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes); +static pdf_status_t pdf_stm_be_cfile_read (pdf_stm_be_t be, + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t * read_bytes); +static pdf_status_t pdf_stm_be_cfile_write (pdf_stm_be_t be, + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t * written_bytes); static pdf_off_t pdf_stm_be_cfile_seek (pdf_stm_be_t be, pdf_off_t pos); static pdf_off_t pdf_stm_be_cfile_tell (pdf_stm_be_t be); @@ -113,86 +121,91 @@ return PDF_OK; } -pdf_size_t +pdf_status_t pdf_stm_be_read (pdf_stm_be_t be, pdf_char_t *buffer, - pdf_size_t bytes) + pdf_size_t bytes, + pdf_size_t *read_bytes) { - pdf_size_t readed_bytes; - + pdf_status_t ret = PDF_OK; switch (be->type) { case PDF_STM_BE_MEM: { - readed_bytes = pdf_stm_be_mem_read (be, - buffer, - bytes); + *read_bytes = pdf_stm_be_mem_read (be, + buffer, + bytes); break; } case PDF_STM_BE_FILE: { - readed_bytes = pdf_stm_be_file_read (be, - buffer, - bytes); + ret = pdf_stm_be_file_read (be, + buffer, + bytes, + read_bytes); break; } case PDF_STM_BE_CFILE: { - readed_bytes = pdf_stm_be_cfile_read (be, - buffer, - bytes); + ret = pdf_stm_be_cfile_read (be, + buffer, + bytes, + read_bytes); break; } default: { /* Uh oh */ - readed_bytes = 0; + *read_bytes = 0; break; } } - return readed_bytes; + return ret; } -pdf_size_t +pdf_status_t pdf_stm_be_write (pdf_stm_be_t be, pdf_char_t *buffer, - pdf_size_t bytes) + pdf_size_t bytes, + pdf_size_t *written_bytes) { - pdf_size_t written_bytes; + pdf_status_t ret = PDF_OK; switch (be->type) { case PDF_STM_BE_MEM: { - written_bytes = pdf_stm_be_mem_write (be, - buffer, - bytes); - break; - } - case PDF_STM_BE_FILE: - { - written_bytes = pdf_stm_be_file_write (be, + *written_bytes = pdf_stm_be_mem_write (be, buffer, bytes); break; } + case PDF_STM_BE_FILE: + { + ret = pdf_stm_be_file_write (be, + buffer, + bytes, + written_bytes); + break; + } case PDF_STM_BE_CFILE: { - written_bytes = pdf_stm_be_cfile_write (be, - buffer, - bytes); + ret = pdf_stm_be_cfile_write (be, + buffer, + bytes, + written_bytes); break; } default: { /* Uh oh */ - written_bytes = 0; + *written_bytes = 0; break; } } - return written_bytes; + return ret; } pdf_off_t @@ -341,12 +354,12 @@ return written_bytes; } -static pdf_size_t +static pdf_status_t pdf_stm_be_file_read (pdf_stm_be_t be, pdf_char_t *buffer, - pdf_size_t bytes) + pdf_size_t bytes, + pdf_size_t *read_bytes) { - pdf_size_t readed_bytes; pdf_size_t current_pos; pdf_status_t ret; @@ -357,34 +370,34 @@ be->data.file.pos) == PDF_ERROR) { /* Bad position */ - return 0; + return PDF_ERROR; } /* Read the requested number of bytes */ ret = pdf_fsys_file_read (be->data.file.file, buffer, bytes, - &readed_bytes); + read_bytes); /* Restore the file position and update the position of the stream */ - be->data.file.pos = be->data.file.pos + readed_bytes; + be->data.file.pos = be->data.file.pos + (*read_bytes); if (pdf_fsys_file_set_pos (be->data.file.file, current_pos) == PDF_ERROR) { /* This should not happen, but just in case */ - return 0; + return PDF_ERROR; } - return readed_bytes; + return ret; } -static pdf_size_t +static pdf_status_t pdf_stm_be_file_write (pdf_stm_be_t be, pdf_char_t *buffer, - pdf_size_t bytes) + pdf_size_t bytes, + pdf_size_t *written_bytes) { - pdf_size_t written_bytes; pdf_size_t current_pos; pdf_status_t ret; @@ -395,26 +408,26 @@ be->data.file.pos) == PDF_ERROR) { /* Bad position */ - return 0; + return PDF_ERROR; } /* Write the requested number of bytes */ ret = pdf_fsys_file_write (be->data.file.file, buffer, bytes, - &written_bytes); + written_bytes); /* Restore the file position and update the position of the stream */ - be->data.file.pos = be->data.file.pos + written_bytes; + be->data.file.pos = be->data.file.pos + (*written_bytes); if (pdf_fsys_file_set_pos (be->data.file.file, current_pos) == PDF_ERROR) { /* This should not happen, but just in case */ - return 0; + return PDF_ERROR; } - return written_bytes; + return ret; } static pdf_off_t @@ -507,34 +520,56 @@ return be->data.cfile.pos; } -static pdf_size_t +static pdf_status_t pdf_stm_be_cfile_read (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes) + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t * read_bytes) { - pdf_size_t readed_bytes; + pdf_status_t ret = PDF_OK; /* Read the requested number of bytes */ - readed_bytes = fread (buffer, - 1, bytes, - be->data.cfile.file); + *read_bytes = fread (buffer, + 1, bytes, + be->data.cfile.file); - return readed_bytes; + if (feof(be->data.cfile.file)) + { + ret = PDF_EEOF; + } + else if (ferror(be->data.cfile.file)) + { + ret = PDF_ERROR; + } + return ret; } -static pdf_size_t +static pdf_status_t pdf_stm_be_cfile_write (pdf_stm_be_t be, pdf_char_t *buffer, - pdf_size_t bytes) + pdf_size_t bytes, + pdf_size_t *written_bytes) { - pdf_size_t written_bytes; + pdf_status_t ret = PDF_OK; /* Write the requested number of bytes */ - written_bytes = fwrite (buffer, - 1, bytes, - be->data.cfile.file); + *written_bytes = fwrite (buffer, + 1, bytes, + be->data.cfile.file); - return written_bytes; + if (ferror(be->data.cfile.file)) + { + if (errno == ENOSPC) + { + ret = PDF_ENOMEM; + } + else + { + ret = PDF_ERROR; + } + } + + return ret; } /* End of pdf-stm-be.c */ === modified file 'src/base/pdf-stm-be.h' --- src/base/pdf-stm-be.h 2008-11-29 16:21:37 +0000 +++ src/base/pdf-stm-be.h 2009-05-18 19:20:19 +0000 @@ -1,4 +1,4 @@ -/* -*- mode: C -*- Time-stamp: "08/11/29 15:11:39 jemarch" +/* -*- mode: C -*- Time-stamp: "2009-05-18 13:40:59 gerel" * * File: pdf-stm-be.h * Date: Wed Jun 18 20:53:27 2008 @@ -70,12 +70,14 @@ pdf_size_t pos); pdf_status_t pdf_stm_be_destroy (pdf_stm_be_t be); -pdf_size_t pdf_stm_be_read (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes); -pdf_size_t pdf_stm_be_write (pdf_stm_be_t be, - pdf_char_t *buffer, - pdf_size_t bytes); +pdf_status_t pdf_stm_be_read (pdf_stm_be_t be, + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t *read_bytes); +pdf_status_t pdf_stm_be_write (pdf_stm_be_t be, + pdf_char_t *buffer, + pdf_size_t bytes, + pdf_size_t *written_bytes); pdf_off_t pdf_stm_be_seek (pdf_stm_be_t be, pdf_off_t pos); === modified file 'src/base/pdf-stm-filter.c' --- src/base/pdf-stm-filter.c 2009-01-12 13:30:36 +0000 +++ src/base/pdf-stm-filter.c 2009-05-18 19:20:19 +0000 @@ -1,4 +1,4 @@ -/* -*- mode: C -*- Time-stamp: "09/01/11 22:03:18 jemarch" +/* -*- mode: C -*- Time-stamp: "2009-05-18 14:25:30 gerel" * * File: pdf-stm-filter.c * Date: Thu Jun 12 22:13:31 2008 @@ -367,13 +367,18 @@ } else if (filter->backend != NULL) { - read_bytes = pdf_stm_be_read (filter->backend, - filter->in->data, - filter->in->size); - filter->in->wp = read_bytes; - if (read_bytes < filter->in->size) - { - ret = PDF_EEOF; + ret = pdf_stm_be_read (filter->backend, + filter->in->data, + filter->in->size, + &read_bytes); + + if (ret != PDF_ERROR) + { + filter->in->wp = read_bytes; + if (read_bytes < filter->in->size) + { + ret = PDF_EEOF; + } } } else === modified file 'src/base/pdf-stm.c' --- src/base/pdf-stm.c 2009-02-06 00:33:22 +0000 +++ src/base/pdf-stm.c 2009-05-18 19:42:11 +0000 @@ -1,607 +1,614 @@ -/* -*- mode: C -*- Time-stamp: "09/02/06 01:31:12 jemarch" - * - * File: pdf-stm.c - * Date: Fri Jul 6 18:43:15 2007 - * - * GNU PDF Library - Streams - * - */ - -/* Copyright (C) 2007, 2008 Free Software Foundation, Inc. */ - -/* This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include <config.h> -#include <unistd.h> -#include <string.h> - -#include <pdf-alloc.h> -#include <pdf-stm.h> - -/* Forward declarations */ - -static pdf_status_t pdf_stm_init (pdf_size_t buffer_size, - enum pdf_stm_mode_e mode, - pdf_stm_t stm); -static inline pdf_stm_t pdf_stm_alloc (void); -static inline void pdf_stm_dealloc (pdf_stm_t stm); -static pdf_status_t pdf_stm_read_peek_char (pdf_stm_t stm, pdf_char_t *c, pdf_bool_t peek_p); - -/* - * Public functions - */ - -pdf_status_t -pdf_stm_cfile_new (FILE* file, - pdf_off_t offset, - pdf_size_t cache_size, - enum pdf_stm_mode_e mode, - pdf_stm_t *stm) -{ - /* Allocate memory for the new stream */ - *stm = pdf_stm_alloc (); - - /* Initialize a file stream */ - (*stm)->type = PDF_STM_FILE; - (*stm)->backend = pdf_stm_be_new_cfile (file, - offset); - - /* Initialize the common parts */ - return pdf_stm_init (cache_size, - mode, - *stm); -} - - -pdf_status_t -pdf_stm_file_new (pdf_fsys_file_t file, - pdf_off_t offset, - pdf_size_t cache_size, - enum pdf_stm_mode_e mode, - pdf_stm_t *stm) -{ - /* Allocate memory for the new stream */ - *stm = pdf_stm_alloc (); - - /* Initialize a file stream */ - (*stm)->type = PDF_STM_FILE; - (*stm)->backend = pdf_stm_be_new_file (file, - offset); - - /* Initialize the common parts */ - return pdf_stm_init (cache_size, - mode, - *stm); -} - -pdf_status_t -pdf_stm_mem_new (pdf_char_t *buffer, - pdf_size_t size, - pdf_size_t cache_size, - enum pdf_stm_mode_e mode, - pdf_stm_t *stm) -{ - /* Allocate memory for the new stream */ - *stm = pdf_stm_alloc (); - - /* Initialize a memory stream */ - (*stm)->type = PDF_STM_MEM; - (*stm)->backend = pdf_stm_be_new_mem (buffer, - size, - 0); - - /* Initialize the common parts */ - return pdf_stm_init (cache_size, - mode, - *stm); -} - -pdf_status_t -pdf_stm_destroy (pdf_stm_t stm) -{ - pdf_stm_filter_t filter; - pdf_stm_filter_t filter_to_delete; - pdf_size_t flushed_bytes; - pdf_status_t ret; - - ret = PDF_OK; - if (stm->mode == PDF_STM_WRITE) - { - /* Flush the cache, finishing the filters */ - ret = pdf_stm_flush (stm, PDF_TRUE, &flushed_bytes); - } - - /* Destroy the backend */ - pdf_stm_be_destroy (stm->backend); - - /* Destroy the cache */ - pdf_buffer_destroy (stm->cache); - - /* Destroy the filter chain */ - filter = stm->filter; - while (filter != NULL) - { - filter_to_delete = filter; - filter = filter->next; - pdf_stm_filter_destroy (filter_to_delete); - } - - /* Deallocate the stm structure */ - pdf_stm_dealloc (stm); - - return ret; -} - -pdf_status_t -pdf_stm_read (pdf_stm_t stm, - pdf_char_t *buf, - pdf_size_t bytes, - pdf_size_t *read_bytes) -{ - pdf_size_t pending_bytes; - pdf_size_t cache_size; - pdf_size_t to_copy_bytes; - pdf_status_t ret; - - if (stm->mode != PDF_STM_READ) - { - /* Invalid operation */ - return PDF_EINVOP; - } - - ret = PDF_OK; - *read_bytes = 0; - while ((*read_bytes < bytes) && - (ret == PDF_OK)) - { - pending_bytes = bytes - *read_bytes; - - /* If the cache is empty, refill it with filtered data */ - if (pdf_buffer_eob_p (stm->cache)) - { - pdf_buffer_rewind (stm->cache); - ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE); - } - - if (ret != PDF_ERROR) - { - /* Read data from the cache */ - pending_bytes = bytes - *read_bytes; - cache_size = stm->cache->wp - stm->cache->rp; - to_copy_bytes = PDF_MIN(pending_bytes, cache_size); - - memcpy ((char *) (buf + *read_bytes), - (char *) stm->cache->data + stm->cache->rp, - to_copy_bytes); - - *read_bytes += to_copy_bytes; - stm->cache->rp += to_copy_bytes; - } - } - - if ((*read_bytes == bytes) && - (ret == PDF_EEOF)) - { - /* Avoid a false PDF_EEOF in the current operation */ - ret = PDF_OK; - } - - return ret; -} - - -pdf_status_t -pdf_stm_write (pdf_stm_t stm, - pdf_char_t *buf, - pdf_size_t bytes, - pdf_size_t *written_bytes) -{ - pdf_status_t ret; - pdf_size_t pending_bytes; - pdf_size_t to_write_bytes; - pdf_stm_filter_t tail_filter; - pdf_buffer_t tail_buffer; - pdf_size_t tail_buffer_size; - pdf_size_t flushed_bytes; - - if (stm->mode != PDF_STM_WRITE) - { - /* Invalid operation */ - return PDF_EINVOP; - } - - tail_filter = pdf_stm_filter_get_tail (stm->filter); - tail_buffer = pdf_stm_filter_get_in (tail_filter); - - ret = PDF_OK; - *written_bytes = 0; - while ((*written_bytes < bytes) && - (ret == PDF_OK)) - { - if ((pdf_buffer_full_p (tail_buffer)) && - (!pdf_buffer_eob_p (tail_buffer))) - { - /* Flush the cache */ - tail_buffer_size = tail_buffer->wp - tail_buffer->rp; - - if (pdf_stm_flush (stm, PDF_FALSE, &flushed_bytes) - == PDF_ERROR) - { - ret = PDF_ERROR; - } - else if (flushed_bytes < tail_buffer_size) - { - ret = PDF_EEOF; - } - } - - if (ret == PDF_OK) - { - /* Write the data into the tail buffer. Note that at this - point the tail buffer should be empty */ - tail_buffer_size = tail_buffer->size - tail_buffer->wp; - pending_bytes = bytes - *written_bytes; - - to_write_bytes = PDF_MIN(pending_bytes, tail_buffer_size); - - if (to_write_bytes != 0) - { - memcpy ((char *) tail_buffer->data + tail_buffer->wp, - (char *) buf + *written_bytes, - to_write_bytes); - - *written_bytes += to_write_bytes; - tail_buffer->wp += to_write_bytes; - } - } - } - - if ((*written_bytes == bytes) && - (ret == PDF_EEOF)) - { - /* Avoid a false PDF_EEOF in the current operation */ - ret = PDF_OK; - } - - - return ret; -} - -pdf_status_t -pdf_stm_flush (pdf_stm_t stm, - pdf_bool_t finish_p, - pdf_size_t *flushed_bytes) -{ - pdf_stm_filter_t tail_filter; - pdf_buffer_t tail_buffer; - pdf_status_t ret; - pdf_size_t cache_size; - pdf_size_t written_bytes; - pdf_size_t tail_size; - - if (stm->mode != PDF_STM_WRITE) - { - /* Invalid operation */ - return 0; - } - - /* Apply the head filter until the filter chain gets empty */ - tail_filter = pdf_stm_filter_get_tail (stm->filter); - tail_buffer = pdf_stm_filter_get_in (tail_filter); - *flushed_bytes = 0; - while (1) - { - tail_size = tail_buffer->wp - tail_buffer->rp; - ret = pdf_stm_filter_apply (stm->filter, finish_p); - - if (ret == PDF_ERROR) - { - /* The filter chain is in error */ - break; - } - - /* Update the number of flushed bytes */ - *flushed_bytes += tail_size - - (tail_buffer->wp - tail_buffer->rp); - - if ((ret == PDF_EEOF) - && (pdf_buffer_eob_p (stm->cache))) - { - pdf_buffer_rewind (tail_buffer); - ret = PDF_OK; - break; - } - - /* Write the data from the buffer cache into the backend */ - cache_size = stm->cache->wp - stm->cache->rp; - written_bytes = pdf_stm_be_write (stm->backend, - stm->cache->data + stm->cache->rp, - cache_size); - - if (written_bytes != cache_size) - { - /* Could not write all the contents of the cache buffer into - the backend */ - stm->cache->rp += written_bytes; - ret = PDF_EEOF; - break; - } - - /* Rewind the cache */ - pdf_buffer_rewind (stm->cache); - } - - return ret; -} - -pdf_status_t -pdf_stm_install_filter (pdf_stm_t stm, - enum pdf_stm_filter_type_e filter_type, - pdf_hash_t filter_params) -{ - pdf_status_t ret; - pdf_stm_filter_t filter; - enum pdf_stm_filter_mode_e filter_mode; - - if (stm->mode == PDF_STM_READ) - { - filter_mode = PDF_STM_FILTER_MODE_READ; - } - else - { - filter_mode = PDF_STM_FILTER_MODE_WRITE; - } - - /* Create the new filter */ - ret = pdf_stm_filter_new (filter_type, - filter_params, - stm->cache->size, - filter_mode, - &filter); - - if (filter != NULL) - { - /* Set the new filter as the new head of the filter chain */ - pdf_stm_filter_set_next (filter, stm->filter); - pdf_stm_filter_set_out (filter, stm->cache); - pdf_stm_filter_set_out (stm->filter, pdf_stm_filter_get_in (filter)); - stm->filter = filter; - } - - return ret; -} - -pdf_status_t -pdf_stm_read_char (pdf_stm_t stm, pdf_char_t *c) -{ - return pdf_stm_read_peek_char (stm, c, PDF_FALSE); -} - -pdf_status_t -pdf_stm_peek_char (pdf_stm_t stm, pdf_char_t *c) -{ - return pdf_stm_read_peek_char (stm, c, PDF_TRUE); -} - -pdf_off_t -pdf_stm_seek (pdf_stm_t stm, - pdf_off_t pos) -{ - pdf_off_t cur_pos; - pdf_off_t new_pos; - pdf_stm_filter_t tail_filter; - pdf_buffer_t tail_buffer; - pdf_size_t flushed_bytes; - - cur_pos = pdf_stm_tell (stm); - - if (stm->mode == PDF_STM_READ) - { - /* Discard the cache contents */ - pdf_buffer_rewind (stm->cache); - - /* Seek the backend */ - new_pos = pdf_stm_be_seek (stm->backend, pos); - } - else - { - /* Writing stream */ - - tail_filter = pdf_stm_filter_get_tail (stm->filter); - tail_buffer = pdf_stm_filter_get_in (tail_filter); - if (!pdf_buffer_eob_p (tail_buffer)) - { - /* Flush the stream */ - if (pdf_stm_flush (stm, PDF_FALSE, &flushed_bytes) - == PDF_ERROR) - { - /* Error flushing the stream: return the current - position */ - return cur_pos; - } - } - - /* Note that if there is an EOF condition in the backend we are - going to loose data */ - pdf_buffer_rewind (tail_buffer); - - /* Seek the backend */ - new_pos = pdf_stm_be_seek (stm->backend, pos); - } - - return new_pos; -} - -pdf_off_t -pdf_stm_tell (pdf_stm_t stm) -{ - pdf_off_t pos; - pdf_size_t cache_size; - pdf_stm_filter_t tail_filter; - pdf_buffer_t tail_buffer; - - if (stm->mode == PDF_STM_READ) - { - cache_size = stm->cache->wp - stm->cache->rp; - pos = pdf_stm_be_tell (stm->backend) + cache_size; - } - else - { - /* Writing stream */ - - tail_filter = pdf_stm_filter_get_tail (stm->filter); - tail_buffer = pdf_stm_filter_get_in (tail_filter); - - cache_size = tail_buffer->wp - tail_buffer->rp; - pos = pdf_stm_be_tell (stm->backend) + cache_size; - } - - return pos; -} - -/* - * Private functions - */ - -static pdf_status_t -pdf_stm_init (pdf_size_t cache_size, - enum pdf_stm_mode_e mode, - pdf_stm_t stm) -{ - pdf_hash_t null_filter_params; - enum pdf_stm_filter_mode_e filter_mode; - pdf_status_t ret; - - if (cache_size == 0) - { - /* Use the default cache size */ - cache_size = PDF_STM_DEFAULT_CACHE_SIZE; - } - - /* Initialize the null filter */ - pdf_hash_new (NULL, &null_filter_params); - - if (stm->mode == PDF_STM_READ) - { - filter_mode = PDF_STM_FILTER_MODE_READ; - } - else - { - filter_mode = PDF_STM_FILTER_MODE_WRITE; - } - - ret = pdf_stm_filter_new (PDF_STM_FILTER_NULL, - null_filter_params, - cache_size, - filter_mode, - &(stm->filter)); - - if (ret == PDF_OK) - { - /* Initialize the filter cache */ - stm->cache = pdf_buffer_new (cache_size); - - /* Configure the filter */ - stm->mode = mode; - if (stm->mode == PDF_STM_READ) - { - /* Configuration for a reading stream - * - * <cache> <--- <null-filter> <--- <backend> - */ - - pdf_stm_filter_set_out (stm->filter, - stm->cache); - pdf_stm_filter_set_be (stm->filter, - stm->backend); - } - else - { - /* Configuration for a writing stream - * - * <null-filter> --> <cache> --> <backend> - */ - - pdf_stm_filter_set_out (stm->filter, - stm->cache); - } - } - - return ret; -} - - -static pdf_status_t -pdf_stm_read_peek_char (pdf_stm_t stm, - pdf_char_t *c, - pdf_bool_t peek_p) -{ - pdf_status_t ret; - - /* Is this a read stream? */ - if (stm->mode != PDF_STM_READ) - { - /* Invalid operation */ - return PDF_EINVOP; - } - - /* Is the cache empty? */ - ret = PDF_OK; - if (pdf_buffer_eob_p (stm->cache)) - { - ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE); - } - - if (pdf_buffer_eob_p (stm->cache)) - { - ret = PDF_EEOF; - } - else - { - /* Read a character from the cache */ - *c = - (pdf_u32_t) stm->cache->data[stm->cache->rp]; - - if (!peek_p) - { - stm->cache->rp++; - } - - if (ret == PDF_EEOF) - { - /* Avoid a false PDF_EEOF */ - ret = PDF_OK; - } - } - - return ret; -} - -static inline pdf_stm_t -pdf_stm_alloc (void) -{ - pdf_stm_t new; - - new = pdf_alloc (sizeof(struct pdf_stm_s)); - return new; -} - -static inline void -pdf_stm_dealloc (pdf_stm_t stm) -{ - pdf_dealloc (stm); -} - -/* End of pdf_stm.c */ +/* -*- mode: C -*- Time-stamp: "2009-05-18 16:42:07 gerel" + * + * File: pdf-stm.c + * Date: Fri Jul 6 18:43:15 2007 + * + * GNU PDF Library - Streams + * + */ + +/* Copyright (C) 2007, 2008 Free Software Foundation, Inc. */ + +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <unistd.h> +#include <string.h> + +#include <pdf-alloc.h> +#include <pdf-stm.h> + +/* Forward declarations */ + +static pdf_status_t pdf_stm_init (pdf_size_t buffer_size, + enum pdf_stm_mode_e mode, + pdf_stm_t stm); +static inline pdf_stm_t pdf_stm_alloc (void); +static inline void pdf_stm_dealloc (pdf_stm_t stm); +static pdf_status_t pdf_stm_read_peek_char (pdf_stm_t stm, pdf_char_t *c, pdf_bool_t peek_p); + +/* + * Public functions + */ + +pdf_status_t +pdf_stm_cfile_new (FILE* file, + pdf_off_t offset, + pdf_size_t cache_size, + enum pdf_stm_mode_e mode, + pdf_stm_t *stm) +{ + /* Allocate memory for the new stream */ + *stm = pdf_stm_alloc (); + + /* Initialize a file stream */ + (*stm)->type = PDF_STM_FILE; + (*stm)->backend = pdf_stm_be_new_cfile (file, + offset); + + /* Initialize the common parts */ + return pdf_stm_init (cache_size, + mode, + *stm); +} + + +pdf_status_t +pdf_stm_file_new (pdf_fsys_file_t file, + pdf_off_t offset, + pdf_size_t cache_size, + enum pdf_stm_mode_e mode, + pdf_stm_t *stm) +{ + /* Allocate memory for the new stream */ + *stm = pdf_stm_alloc (); + + /* Initialize a file stream */ + (*stm)->type = PDF_STM_FILE; + (*stm)->backend = pdf_stm_be_new_file (file, + offset); + + /* Initialize the common parts */ + return pdf_stm_init (cache_size, + mode, + *stm); +} + +pdf_status_t +pdf_stm_mem_new (pdf_char_t *buffer, + pdf_size_t size, + pdf_size_t cache_size, + enum pdf_stm_mode_e mode, + pdf_stm_t *stm) +{ + /* Allocate memory for the new stream */ + *stm = pdf_stm_alloc (); + + /* Initialize a memory stream */ + (*stm)->type = PDF_STM_MEM; + (*stm)->backend = pdf_stm_be_new_mem (buffer, + size, + 0); + + /* Initialize the common parts */ + return pdf_stm_init (cache_size, + mode, + *stm); +} + +pdf_status_t +pdf_stm_destroy (pdf_stm_t stm) +{ + pdf_stm_filter_t filter; + pdf_stm_filter_t filter_to_delete; + pdf_size_t flushed_bytes; + pdf_status_t ret; + + ret = PDF_OK; + if (stm->mode == PDF_STM_WRITE) + { + /* Flush the cache, finishing the filters */ + ret = pdf_stm_flush (stm, PDF_TRUE, &flushed_bytes); + } + + /* Destroy the backend */ + pdf_stm_be_destroy (stm->backend); + + /* Destroy the cache */ + pdf_buffer_destroy (stm->cache); + + /* Destroy the filter chain */ + filter = stm->filter; + while (filter != NULL) + { + filter_to_delete = filter; + filter = filter->next; + pdf_stm_filter_destroy (filter_to_delete); + } + + /* Deallocate the stm structure */ + pdf_stm_dealloc (stm); + + return ret; +} + +pdf_status_t +pdf_stm_read (pdf_stm_t stm, + pdf_char_t *buf, + pdf_size_t bytes, + pdf_size_t *read_bytes) +{ + pdf_size_t pending_bytes; + pdf_size_t cache_size; + pdf_size_t to_copy_bytes; + pdf_status_t ret; + + if (stm->mode != PDF_STM_READ) + { + /* Invalid operation */ + return PDF_EINVOP; + } + + ret = PDF_OK; + *read_bytes = 0; + while ((*read_bytes < bytes) && + (ret == PDF_OK)) + { + pending_bytes = bytes - *read_bytes; + + /* If the cache is empty, refill it with filtered data */ + if (pdf_buffer_eob_p (stm->cache)) + { + pdf_buffer_rewind (stm->cache); + ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE); + } + + if (ret != PDF_ERROR) + { + /* Read data from the cache */ + pending_bytes = bytes - *read_bytes; + cache_size = stm->cache->wp - stm->cache->rp; + to_copy_bytes = PDF_MIN(pending_bytes, cache_size); + + memcpy ((char *) (buf + *read_bytes), + (char *) stm->cache->data + stm->cache->rp, + to_copy_bytes); + + *read_bytes += to_copy_bytes; + stm->cache->rp += to_copy_bytes; + } + } + + if ((*read_bytes == bytes) && + (ret == PDF_EEOF)) + { + /* Avoid a false PDF_EEOF in the current operation */ + ret = PDF_OK; + } + + return ret; +} + + +pdf_status_t +pdf_stm_write (pdf_stm_t stm, + pdf_char_t *buf, + pdf_size_t bytes, + pdf_size_t *written_bytes) +{ + pdf_status_t ret; + pdf_size_t pending_bytes; + pdf_size_t to_write_bytes; + pdf_stm_filter_t tail_filter; + pdf_buffer_t tail_buffer; + pdf_size_t tail_buffer_size; + pdf_size_t flushed_bytes; + + if (stm->mode != PDF_STM_WRITE) + { + /* Invalid operation */ + return PDF_EINVOP; + } + + tail_filter = pdf_stm_filter_get_tail (stm->filter); + tail_buffer = pdf_stm_filter_get_in (tail_filter); + + ret = PDF_OK; + *written_bytes = 0; + while ((*written_bytes < bytes) && + (ret == PDF_OK)) + { + if ((pdf_buffer_full_p (tail_buffer)) && + (!pdf_buffer_eob_p (tail_buffer))) + { + /* Flush the cache */ + tail_buffer_size = tail_buffer->wp - tail_buffer->rp; + + if (pdf_stm_flush (stm, PDF_FALSE, &flushed_bytes) + == PDF_ERROR) + { + ret = PDF_ERROR; + } + else if (flushed_bytes < tail_buffer_size) + { + ret = PDF_EEOF; + } + } + + if (ret == PDF_OK) + { + /* Write the data into the tail buffer. Note that at this + point the tail buffer should be empty */ + tail_buffer_size = tail_buffer->size - tail_buffer->wp; + pending_bytes = bytes - *written_bytes; + + to_write_bytes = PDF_MIN(pending_bytes, tail_buffer_size); + + if (to_write_bytes != 0) + { + memcpy ((char *) tail_buffer->data + tail_buffer->wp, + (char *) buf + *written_bytes, + to_write_bytes); + + *written_bytes += to_write_bytes; + tail_buffer->wp += to_write_bytes; + } + } + } + + if ((*written_bytes == bytes) && + (ret == PDF_EEOF)) + { + /* Avoid a false PDF_EEOF in the current operation */ + ret = PDF_OK; + } + + + return ret; +} + +pdf_status_t +pdf_stm_flush (pdf_stm_t stm, + pdf_bool_t finish_p, + pdf_size_t *flushed_bytes) +{ + pdf_stm_filter_t tail_filter; + pdf_buffer_t tail_buffer; + pdf_status_t ret; + pdf_size_t cache_size; + pdf_size_t written_bytes; + pdf_size_t tail_size; + + if (stm->mode != PDF_STM_WRITE) + { + /* Invalid operation */ + return 0; + } + + /* Apply the head filter until the filter chain gets empty */ + tail_filter = pdf_stm_filter_get_tail (stm->filter); + tail_buffer = pdf_stm_filter_get_in (tail_filter); + *flushed_bytes = 0; + while (1) + { + tail_size = tail_buffer->wp - tail_buffer->rp; + ret = pdf_stm_filter_apply (stm->filter, finish_p); + + if (ret == PDF_ERROR) + { + /* The filter chain is in error */ + break; + } + + /* Update the number of flushed bytes */ + *flushed_bytes += tail_size + - (tail_buffer->wp - tail_buffer->rp); + + if ((ret == PDF_EEOF) + && (pdf_buffer_eob_p (stm->cache))) + { + pdf_buffer_rewind (tail_buffer); + ret = PDF_OK; + break; + } + + /* Write the data from the buffer cache into the backend */ + cache_size = stm->cache->wp - stm->cache->rp; + ret = pdf_stm_be_write (stm->backend, + stm->cache->data + stm->cache->rp, + cache_size, + &written_bytes); + + if (ret == PDF_ERROR) + { + /* Error prevented us from writing */ + break; + } + + if (written_bytes != cache_size) + { + /* Could not write all the contents of the cache buffer into + the backend */ + stm->cache->rp += written_bytes; + ret = PDF_EEOF; + break; + } + + /* Rewind the cache */ + pdf_buffer_rewind (stm->cache); + } + + return ret; +} + +pdf_status_t +pdf_stm_install_filter (pdf_stm_t stm, + enum pdf_stm_filter_type_e filter_type, + pdf_hash_t filter_params) +{ + pdf_status_t ret; + pdf_stm_filter_t filter; + enum pdf_stm_filter_mode_e filter_mode; + + if (stm->mode == PDF_STM_READ) + { + filter_mode = PDF_STM_FILTER_MODE_READ; + } + else + { + filter_mode = PDF_STM_FILTER_MODE_WRITE; + } + + /* Create the new filter */ + ret = pdf_stm_filter_new (filter_type, + filter_params, + stm->cache->size, + filter_mode, + &filter); + + if (filter != NULL) + { + /* Set the new filter as the new head of the filter chain */ + pdf_stm_filter_set_next (filter, stm->filter); + pdf_stm_filter_set_out (filter, stm->cache); + pdf_stm_filter_set_out (stm->filter, pdf_stm_filter_get_in (filter)); + stm->filter = filter; + } + + return ret; +} + +pdf_status_t +pdf_stm_read_char (pdf_stm_t stm, pdf_char_t *c) +{ + return pdf_stm_read_peek_char (stm, c, PDF_FALSE); +} + +pdf_status_t +pdf_stm_peek_char (pdf_stm_t stm, pdf_char_t *c) +{ + return pdf_stm_read_peek_char (stm, c, PDF_TRUE); +} + +pdf_off_t +pdf_stm_seek (pdf_stm_t stm, + pdf_off_t pos) +{ + pdf_off_t cur_pos; + pdf_off_t new_pos; + pdf_stm_filter_t tail_filter; + pdf_buffer_t tail_buffer; + pdf_size_t flushed_bytes; + + cur_pos = pdf_stm_tell (stm); + + if (stm->mode == PDF_STM_READ) + { + /* Discard the cache contents */ + pdf_buffer_rewind (stm->cache); + + /* Seek the backend */ + new_pos = pdf_stm_be_seek (stm->backend, pos); + } + else + { + /* Writing stream */ + + tail_filter = pdf_stm_filter_get_tail (stm->filter); + tail_buffer = pdf_stm_filter_get_in (tail_filter); + if (!pdf_buffer_eob_p (tail_buffer)) + { + /* Flush the stream */ + if (pdf_stm_flush (stm, PDF_FALSE, &flushed_bytes) + == PDF_ERROR) + { + /* Error flushing the stream: return the current + position */ + return cur_pos; + } + } + + /* Note that if there is an EOF condition in the backend we are + going to loose data */ + pdf_buffer_rewind (tail_buffer); + + /* Seek the backend */ + new_pos = pdf_stm_be_seek (stm->backend, pos); + } + + return new_pos; +} + +pdf_off_t +pdf_stm_tell (pdf_stm_t stm) +{ + pdf_off_t pos; + pdf_size_t cache_size; + pdf_stm_filter_t tail_filter; + pdf_buffer_t tail_buffer; + + if (stm->mode == PDF_STM_READ) + { + cache_size = stm->cache->wp - stm->cache->rp; + pos = pdf_stm_be_tell (stm->backend) + cache_size; + } + else + { + /* Writing stream */ + + tail_filter = pdf_stm_filter_get_tail (stm->filter); + tail_buffer = pdf_stm_filter_get_in (tail_filter); + + cache_size = tail_buffer->wp - tail_buffer->rp; + pos = pdf_stm_be_tell (stm->backend) + cache_size; + } + + return pos; +} + +/* + * Private functions + */ + +static pdf_status_t +pdf_stm_init (pdf_size_t cache_size, + enum pdf_stm_mode_e mode, + pdf_stm_t stm) +{ + pdf_hash_t null_filter_params; + enum pdf_stm_filter_mode_e filter_mode; + pdf_status_t ret; + + if (cache_size == 0) + { + /* Use the default cache size */ + cache_size = PDF_STM_DEFAULT_CACHE_SIZE; + } + + /* Initialize the null filter */ + pdf_hash_new (NULL, &null_filter_params); + + if (stm->mode == PDF_STM_READ) + { + filter_mode = PDF_STM_FILTER_MODE_READ; + } + else + { + filter_mode = PDF_STM_FILTER_MODE_WRITE; + } + + ret = pdf_stm_filter_new (PDF_STM_FILTER_NULL, + null_filter_params, + cache_size, + filter_mode, + &(stm->filter)); + + if (ret == PDF_OK) + { + /* Initialize the filter cache */ + stm->cache = pdf_buffer_new (cache_size); + + /* Configure the filter */ + stm->mode = mode; + if (stm->mode == PDF_STM_READ) + { + /* Configuration for a reading stream + * + * <cache> <--- <null-filter> <--- <backend> + */ + + pdf_stm_filter_set_out (stm->filter, + stm->cache); + pdf_stm_filter_set_be (stm->filter, + stm->backend); + } + else + { + /* Configuration for a writing stream + * + * <null-filter> --> <cache> --> <backend> + */ + + pdf_stm_filter_set_out (stm->filter, + stm->cache); + } + } + + return ret; +} + + +static pdf_status_t +pdf_stm_read_peek_char (pdf_stm_t stm, + pdf_char_t *c, + pdf_bool_t peek_p) +{ + pdf_status_t ret; + + /* Is this a read stream? */ + if (stm->mode != PDF_STM_READ) + { + /* Invalid operation */ + return PDF_EINVOP; + } + + /* Is the cache empty? */ + ret = PDF_OK; + if (pdf_buffer_eob_p (stm->cache)) + { + ret = pdf_stm_filter_apply (stm->filter, PDF_FALSE); + } + + if (pdf_buffer_eob_p (stm->cache)) + { + ret = PDF_EEOF; + } + else + { + /* Read a character from the cache */ + *c = + (pdf_u32_t) stm->cache->data[stm->cache->rp]; + + if (!peek_p) + { + stm->cache->rp++; + } + + if (ret == PDF_EEOF) + { + /* Avoid a false PDF_EEOF */ + ret = PDF_OK; + } + } + + return ret; +} + +static inline pdf_stm_t +pdf_stm_alloc (void) +{ + pdf_stm_t new; + + new = pdf_alloc (sizeof(struct pdf_stm_s)); + return new; +} + +static inline void +pdf_stm_dealloc (pdf_stm_t stm) +{ + pdf_dealloc (stm); +} + +/* End of pdf_stm.c */ # Begin bundle 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 ###
