Commit 1d1c8175 authored by Carlos Garcia Campos's avatar Carlos Garcia Campos

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.
parent b477443e
......@@ -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
......
......@@ -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
......
/* poppler-cached-file-loader.h: glib interface to poppler
*
* Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
*
* 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;
}
/* poppler-cached-file-loader.h: glib interface to poppler
*
* Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
*
* 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__ */
......@@ -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)
......
......@@ -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);
......
/* poppler-input-stream.cc: glib interface to poppler
*
* Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
*
* 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;
}
/* poppler-input-stream.h: glib interface to poppler
*
* Copyright (C) 2012 Carlos Garcia Campos <carlosgc@gnome.org>
*
* 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__ */
......@@ -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>
......@@ -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
......
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
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment