configure.ac | 10 +- glib/Makefile.am | 4 + glib/poppler-cached-file-loader.cc | 108 +++++++++++++++++++++++++++ glib/poppler-cached-file-loader.h | 44 +++++++++++ glib/poppler-document.cc | 69 +++++++++++++++++ glib/poppler-document.h | 6 + glib/poppler-input-stream.cc | 141 ++++++++++++++++++++++++++++++++++++ glib/poppler-input-stream.h | 74 ++++++++++++++++++ glib/reference/poppler-docs.sgml | 4 + glib/reference/poppler-sections.txt | 1 poppler-glib-uninstalled.pc.in | 2 poppler-glib.pc.in | 2 12 files changed, 458 insertions(+), 7 deletions(-)
New commits: commit 1d1c8175c57ebe6518f4252ab92a20286b7d4c6f Author: Carlos Garcia Campos <[email protected]> Date: Sun May 13 18:41:25 2012 +0200 glib: Add poppler_document_new_from_stream A PopplerInputStream has been added to handle GMemoryInputStream and GLocalFileInputStream, since we don't want to cache the contents in those cases. A PopplerCachedFileLoader has been added to handle all other cases. diff --git a/configure.ac b/configure.ac index 1eaa809..abd6e5f 100644 --- a/configure.ac +++ b/configure.ac @@ -531,12 +531,12 @@ if test x$enable_cairo_output = xyes; then enable_poppler_glib=$enableval, enable_poppler_glib="try") if test x$enable_poppler_glib = xyes; then - PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION) + PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION) elif test x$enable_poppler_glib = xtry; then - PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION, + PKG_CHECK_MODULES(POPPLER_GLIB, glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION, [enable_poppler_glib="yes"], [enable_poppler_glib="no" - use_glib="no (requires glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION)"]) + use_glib="no (requires glib-2.0 >= $GLIB_REQUIRED gobject-2.0 >= $GLIB_REQUIRED gio-2.0 >= $GLIB_REQUIRED cairo >= $CAIRO_VERSION)"]) fi if test x$enable_poppler_glib = xyes; then # Check for introspection @@ -644,9 +644,9 @@ AC_ARG_ENABLE(gtk-test, enable_gtk_test=$enableval, enable_gtk_test="try") if test x$enable_gtk_test = xyes; then - PKG_CHECK_MODULES(GTK_TEST, gtk+-2.0 >= 2.14 gdk-pixbuf-2.0 gthread-2.0 gio-2.0) + PKG_CHECK_MODULES(GTK_TEST, gtk+-2.0 >= 2.14 gdk-pixbuf-2.0 gthread-2.0) elif test x$enable_gtk_test = xtry; then - PKG_CHECK_MODULES(GTK_TEST, gtk+-2.0 >= 2.14 gdk-pixbuf-2.0 gthread-2.0 gio-2.0, + PKG_CHECK_MODULES(GTK_TEST, gtk+-2.0 >= 2.14 gdk-pixbuf-2.0 gthread-2.0, [enable_gtk_test="yes"], [enable_gtk_test="no"]) fi diff --git a/glib/Makefile.am b/glib/Makefile.am index 83c724f..fc5844b 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -64,6 +64,10 @@ libpoppler_glib_la_SOURCES = \ poppler-layer.cc \ poppler-media.cc \ poppler-movie.cc \ + poppler-cached-file-loader.cc \ + poppler-cached-file-loader.h \ + poppler-input-stream.cc \ + poppler-input-stream.h \ poppler.cc \ poppler-private.h diff --git a/glib/poppler-cached-file-loader.cc b/glib/poppler-cached-file-loader.cc new file mode 100644 index 0000000..bf462b6 --- /dev/null +++ b/glib/poppler-cached-file-loader.cc @@ -0,0 +1,108 @@ +/* poppler-cached-file-loader.h: glib interface to poppler + * + * Copyright (C) 2012 Carlos Garcia Campos <[email protected]> + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "poppler-cached-file-loader.h" + +PopplerCachedFileLoader::PopplerCachedFileLoader(GInputStream *inputStreamA, GCancellable *cancellableA, goffset lengthA) +{ + inputStream = (GInputStream *)g_object_ref(inputStreamA); + cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : NULL; + length = lengthA; + url = NULL; + cachedFile = NULL; +} + +PopplerCachedFileLoader::~PopplerCachedFileLoader() +{ + g_object_unref(inputStream); + if (cancellable) + g_object_unref(cancellable); +} + +size_t PopplerCachedFileLoader::init(GooString *urlA, CachedFile *cachedFileA) +{ + size_t size; + gssize bytesRead; + char buf[CachedFileChunkSize]; + + url = urlA; + cachedFile = cachedFileA; + + if (length != (goffset)-1) + return length; + + if (G_IS_FILE_INPUT_STREAM(inputStream)) { + GFileInfo *info; + + info = g_file_input_stream_query_info(G_FILE_INPUT_STREAM (inputStream), G_FILE_ATTRIBUTE_STANDARD_SIZE, cancellable, NULL); + if (!info) { + error(errInternal, -1, "Failed to get size of '{0:t}'.", urlA); + return (size_t)-1; + } + + length = g_file_info_get_size(info); + g_object_unref(info); + + return length; + } + + // Unknown stream length, read the whole stream and return the size. + CachedFileWriter writer = CachedFileWriter(cachedFile, NULL); + size = 0; + do { + bytesRead = g_input_stream_read(inputStream, buf, CachedFileChunkSize, cancellable, NULL); + if (bytesRead == -1) + break; + + writer.write(buf, bytesRead); + size += bytesRead; + } while (bytesRead > 0); + + return size; +} + +int PopplerCachedFileLoader::load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer) +{ + char buf[CachedFileChunkSize]; + gssize bytesRead; + size_t rangeBytesRead, bytesToRead, size; + + if (length == (goffset)-1) + return 0; + + size = 0; + for (size_t i = 0; i < ranges.size(); i++) { + bytesToRead = MIN(CachedFileChunkSize, ranges[i].length); + rangeBytesRead = 0; + g_seekable_seek(G_SEEKABLE(inputStream), ranges[i].offset, G_SEEK_SET, cancellable, NULL); + do { + bytesRead = g_input_stream_read(inputStream, buf, bytesToRead, cancellable, NULL); + if (bytesRead == -1) + return -1; + + writer->write(buf, bytesRead); + size += bytesRead; + rangeBytesRead += bytesRead; + bytesToRead = ranges[i].length - rangeBytesRead; + } while (bytesRead > 0 && bytesToRead > 0); + } + + return 0; +} diff --git a/glib/poppler-cached-file-loader.h b/glib/poppler-cached-file-loader.h new file mode 100644 index 0000000..3660435 --- /dev/null +++ b/glib/poppler-cached-file-loader.h @@ -0,0 +1,44 @@ +/* poppler-cached-file-loader.h: glib interface to poppler + * + * Copyright (C) 2012 Carlos Garcia Campos <[email protected]> + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __POPPLER_CACHED_FILE_LOADER_H__ +#define __POPPLER_CACHED_FILE_LOADER_H__ + +#include <gio/gio.h> +#ifndef __GI_SCANNER__ +#include <CachedFile.h> + +class PopplerCachedFileLoader: public CachedFileLoader { +public: + PopplerCachedFileLoader(GInputStream* inputStreamA, GCancellable *cancellableA, goffset lengthA = -1); + ~PopplerCachedFileLoader(); + size_t init(GooString *url, CachedFile* cachedFile); + int load(const std::vector<ByteRange> &ranges, CachedFileWriter *writer); + +private: + GInputStream *inputStream; + GCancellable *cancellable; + goffset length; + GooString *url; + CachedFile *cachedFile; +}; + +#endif /* __GI_SCANNER__ */ + +#endif /* __POPPLER_CACHED_FILE_LOADER_H__ */ diff --git a/glib/poppler-document.cc b/glib/poppler-document.cc index a78b5ec..ec56698 100644 --- a/glib/poppler-document.cc +++ b/glib/poppler-document.cc @@ -38,6 +38,8 @@ #include "poppler.h" #include "poppler-private.h" #include "poppler-enums.h" +#include "poppler-input-stream.h" +#include "poppler-cached-file-loader.h" /** * SECTION:poppler-document @@ -246,6 +248,73 @@ poppler_document_new_from_data (char *data, return _poppler_document_new_from_pdfdoc (newDoc, error); } +static inline gboolean +stream_is_memory_buffer_or_local_file (GInputStream *stream) +{ + return G_IS_MEMORY_INPUT_STREAM(stream) || + (G_IS_FILE_INPUT_STREAM(stream) && strcmp(g_type_name_from_instance((GTypeInstance*)stream), "GLocalFileInputStream") == 0); +} + +/** + * poppler_document_new_from_stream: + * @stream: a #GInputStream to read from + * @length: the stream length, or -1 if not known + * @password: (allow-none): password to unlock the file with, or %NULL + * @error: (allow-none): Return location for an error, or %NULL + * + * Creates a new #PopplerDocument reading the PDF contents from @stream. + * Note that the given #GInputStream must be seekable or %G_IO_ERROR_NOT_SUPPORTED + * will be returned. + * Possible errors include those in the #POPPLER_ERROR and #G_FILE_ERROR + * domains. + * + * Returns: (transfer full): a new #PopplerDocument, or %NULL + * + * Since: 0.22 + */ +PopplerDocument * +poppler_document_new_from_stream (GInputStream *stream, + goffset length, + const char *password, + GCancellable *cancellable, + GError **error) +{ + Object obj; + PDFDoc *newDoc; + BaseStream *str; + GooString *password_g; + + g_return_val_if_fail(G_IS_INPUT_STREAM(stream), NULL); + g_return_val_if_fail(length == (goffset)-1 || length > 0, NULL); + + if (!globalParams) { + globalParams = new GlobalParams(); + } + + if (!G_IS_SEEKABLE(stream) || !g_seekable_can_seek(G_SEEKABLE(stream))) { + g_set_error_literal(error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Stream is not seekable"); + return NULL; + } + + obj.initNull(); + if (stream_is_memory_buffer_or_local_file(stream)) { + str = new PopplerInputStream(stream, cancellable, 0, gFalse, 0, &obj); + } else { + CachedFile *cachedFile = new CachedFile(new PopplerCachedFileLoader(stream, cancellable, length), new GooString()); + str = new CachedFileStream(cachedFile, 0, gFalse, cachedFile->getLength(), &obj); + } + + password_g = NULL; + if (password != NULL) + password_g = new GooString (password); + + newDoc = new PDFDoc(str, password_g, password_g); + delete password_g; + + return _poppler_document_new_from_pdfdoc (newDoc, error); +} + static gboolean handle_save_error (int err_code, GError **error) diff --git a/glib/poppler-document.h b/glib/poppler-document.h index 7051830..7ac6672 100644 --- a/glib/poppler-document.h +++ b/glib/poppler-document.h @@ -20,6 +20,7 @@ #define __POPPLER_DOCUMENT_H__ #include <glib-object.h> +#include <gio/gio.h> #include "poppler.h" G_BEGIN_DECLS @@ -172,6 +173,11 @@ PopplerDocument *poppler_document_new_from_data (char *dat int length, const char *password, GError **error); +PopplerDocument *poppler_document_new_from_stream (GInputStream *stream, + goffset length, + const char *password, + GCancellable *cancellable, + GError **error); gboolean poppler_document_save (PopplerDocument *document, const char *uri, GError **error); diff --git a/glib/poppler-input-stream.cc b/glib/poppler-input-stream.cc new file mode 100644 index 0000000..99fcb6f --- /dev/null +++ b/glib/poppler-input-stream.cc @@ -0,0 +1,141 @@ +/* poppler-input-stream.cc: glib interface to poppler + * + * Copyright (C) 2012 Carlos Garcia Campos <[email protected]> + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "poppler-input-stream.h" + +PopplerInputStream::PopplerInputStream(GInputStream *inputStreamA, GCancellable *cancellableA, + Guint startA, GBool limitedA, Guint lengthA, Object *dictA) + : BaseStream(dictA, lengthA) +{ + inputStream = (GInputStream *)g_object_ref(inputStreamA); + cancellable = cancellableA ? (GCancellable *)g_object_ref(cancellableA) : NULL; + start = startA; + limited = limitedA; + length = lengthA; + bufPtr = bufEnd = buf; + bufPos = start; +} + +PopplerInputStream::~PopplerInputStream() +{ + close(); + g_object_unref(inputStream); + if (cancellable) + g_object_unref(cancellable); +} + +Stream *PopplerInputStream::makeSubStream(Guint startA, GBool limitedA, + Guint lengthA, Object *dictA) +{ + return new PopplerInputStream(inputStream, cancellable, startA, limitedA, lengthA, dictA); +} + +void PopplerInputStream::reset() +{ + GSeekable *seekable = G_SEEKABLE(inputStream); + + savePos = (Guint)g_seekable_tell(seekable); + g_seekable_seek(seekable, start, G_SEEK_SET, cancellable, NULL); + saved = gTrue; + bufPtr = bufEnd = buf; + bufPos = start; +} + +void PopplerInputStream::close() +{ + if (!saved) + return; + g_seekable_seek(G_SEEKABLE(inputStream), savePos, G_SEEK_SET, cancellable, NULL); + saved = gFalse; +} + +void PopplerInputStream::setPos(Guint pos, int dir) +{ + Guint size; + GSeekable *seekable = G_SEEKABLE(inputStream); + + if (dir >= 0) { + g_seekable_seek(seekable, pos, G_SEEK_SET, cancellable, NULL); + } else { + g_seekable_seek(seekable, 0, G_SEEK_END, cancellable, NULL); + size = (Guint)g_seekable_tell(seekable); + + if (pos > size) + pos = size; + + g_seekable_seek(seekable, -(goffset)pos, G_SEEK_END, cancellable, NULL); + bufPos = (Guint)g_seekable_tell(seekable); + } + bufPtr = bufEnd = buf; +} + +void PopplerInputStream::moveStart(int delta) +{ + start += delta; + bufPtr = bufEnd = buf; + bufPos = start; +} + +GBool PopplerInputStream::fillBuf() +{ + int n; + + bufPos += bufEnd - buf; + bufPtr = bufEnd = buf; + if (limited && bufPos >= start + length) { + return gFalse; + } + + if (limited && bufPos + inputStreamBufSize > start + length) { + n = start + length - bufPos; + } else { + n = inputStreamBufSize; + } + + n = g_input_stream_read(inputStream, buf, n, cancellable, NULL); + bufEnd = buf + n; + if (bufPtr >= bufEnd) { + return gFalse; + } + + return gTrue; +} + +int PopplerInputStream::getChars(int nChars, Guchar *buffer) +{ + int n, m; + + n = 0; + while (n < nChars) { + if (bufPtr >= bufEnd) { + if (!fillBuf()) { + break; + } + } + m = (int)(bufEnd - bufPtr); + if (m > nChars - n) { + m = nChars - n; + } + memcpy(buffer + n, bufPtr, m); + bufPtr += m; + n += m; + } + return n; +} diff --git a/glib/poppler-input-stream.h b/glib/poppler-input-stream.h new file mode 100644 index 0000000..0d795f4 --- /dev/null +++ b/glib/poppler-input-stream.h @@ -0,0 +1,74 @@ +/* poppler-input-stream.h: glib interface to poppler + * + * Copyright (C) 2012 Carlos Garcia Campos <[email protected]> + * + * 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 2, 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, write to the Free Software + * Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __POPPLER_INPUT_STREAM_H__ +#define __POPPLER_INPUT_STREAM_H__ + +#include <gio/gio.h> +#ifndef __GI_SCANNER__ +#include <Object.h> +#include <Stream.h> + +#define inputStreamBufSize 1024 + +class PopplerInputStream: public BaseStream { +public: + + PopplerInputStream(GInputStream *inputStream, GCancellable *cancellableA, + Guint startA, GBool limitedA, Guint lengthA, Object *dictA); + virtual ~PopplerInputStream(); + virtual Stream *makeSubStream(Guint start, GBool limited, + Guint lengthA, Object *dictA); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual void close(); + virtual int getChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); } + virtual int lookChar() + { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } + virtual int getPos() { return bufPos + (bufPtr - buf); } + virtual void setPos(Guint pos, int dir = 0); + virtual Guint getStart() { return start; } + virtual void moveStart(int delta); + + virtual int getUnfilteredChar() { return getChar(); } + virtual void unfilteredReset() { reset(); } + +private: + + GBool fillBuf(); + + virtual GBool hasGetChars() { return true; } + virtual int getChars(int nChars, Guchar *buffer); + + GInputStream *inputStream; + GCancellable *cancellable; + Guint start; + GBool limited; + char buf[inputStreamBufSize]; + char *bufPtr; + char *bufEnd; + Guint bufPos; + int savePos; + GBool saved; +}; + +#endif /* __GI_SCANNER__ */ + +#endif /* __POPPLER_INPUT_STREAM_H__ */ diff --git a/glib/reference/poppler-docs.sgml b/glib/reference/poppler-docs.sgml index d15bd18..a9d5158 100644 --- a/glib/reference/poppler-docs.sgml +++ b/glib/reference/poppler-docs.sgml @@ -54,6 +54,10 @@ <title>Index of new symbols in 0.20</title> <xi:include href="xml/api-index-0.20.xml"><xi:fallback /></xi:include> </index> + <index id="api-index-0-22"> + <title>Index of new symbols in 0.22</title> + <xi:include href="xml/api-index-0.22.xml"><xi:fallback /></xi:include> + </index> <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include> </book> diff --git a/glib/reference/poppler-sections.txt b/glib/reference/poppler-sections.txt index 5a6708b..8573051 100644 --- a/glib/reference/poppler-sections.txt +++ b/glib/reference/poppler-sections.txt @@ -115,6 +115,7 @@ PopplerViewerPreferences PopplerPermissions poppler_document_new_from_file poppler_document_new_from_data +poppler_document_new_from_stream poppler_document_save poppler_document_save_a_copy poppler_document_get_id diff --git a/poppler-glib-uninstalled.pc.in b/poppler-glib-uninstalled.pc.in index 5fcb6f2..5506c4e 100644 --- a/poppler-glib-uninstalled.pc.in +++ b/poppler-glib-uninstalled.pc.in @@ -1,7 +1,7 @@ Name: poppler-glib Description: GLib wrapper for poppler - uninstalled Version: @VERSION@ -Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@ +Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ gio-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@ Libs: ${pc_top_builddir}/${pcfiledir}/glib/libpoppler-glib.la Cflags: -I${pc_top_builddir}/${pcfiledir}/glib diff --git a/poppler-glib.pc.in b/poppler-glib.pc.in index 9ba8978..cd30feb 100644 --- a/poppler-glib.pc.in +++ b/poppler-glib.pc.in @@ -6,7 +6,7 @@ includedir=@includedir@ Name: poppler-glib Description: GLib wrapper for poppler Version: @VERSION@ -Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@ +Requires: glib-2.0 >= @GLIB_REQUIRED@ gobject-2.0 >= @GLIB_REQUIRED@ gio-2.0 >= @GLIB_REQUIRED@ cairo >= @CAIRO_VERSION@ @PC_REQUIRES_PRIVATE@ Libs: -L${libdir} -lpoppler-glib _______________________________________________ poppler mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/poppler
