blob: 46f52b9e6666cbd687f593bcb5382bdfda4590cf [file] [log] [blame]
/*
* Copyright (C) 2009, Pino Toscano <pino@kde.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 "poppler-document.h"
#include "poppler-embedded-file.h"
#include "poppler-page.h"
#include "poppler-toc.h"
#include "poppler-document-private.h"
#include "poppler-embedded-file-private.h"
#include "poppler-private.h"
#include "poppler-toc-private.h"
#include "Catalog.h"
#include "ErrorCodes.h"
#include "GlobalParams.h"
#include "Outline.h"
#include <algorithm>
#include <memory>
using namespace poppler;
unsigned int poppler::document_private::count = 0U;
document_private::document_private(GooString *file_path, const std::string &owner_password,
const std::string &user_password)
: doc(0)
, is_locked(false)
{
GooString goo_owner_password(owner_password.c_str());
GooString goo_user_password(user_password.c_str());
doc = new PDFDoc(file_path, &goo_owner_password, &goo_user_password);
init();
}
document_private::~document_private()
{
delete_all(embedded_files);
delete doc;
if (count > 0) {
--count;
if (!count) {
delete globalParams;
globalParams = 0;
}
}
}
void document_private::init()
{
if (!count) {
globalParams = new GlobalParams();
setErrorFunction(detail::error_function);
}
count++;
}
document* document_private::check_document(document_private *doc)
{
if (doc->doc->isOk() || doc->doc->getErrorCode() == errEncrypted) {
if (doc->doc->getErrorCode() == errEncrypted) {
doc->is_locked = true;
}
return new document(*doc);
} else {
delete doc;
}
return 0;
}
document::document(document_private &dd)
: d(&dd)
{
}
document::~document()
{
delete d;
}
bool document::is_locked() const
{
return d->is_locked;
}
bool document::unlock(const std::string &owner_password, const std::string &user_password)
{
if (d->is_locked) {
document_private *newdoc = 0;
{
newdoc = new document_private(new GooString(d->doc->getFileName()),
owner_password, user_password);
}
if (!newdoc->doc->isOk()) {
delete newdoc;
} else {
delete d;
d = newdoc;
d->is_locked = false;
}
}
return d->is_locked;
}
document::page_mode_enum document::page_mode() const
{
switch (d->doc->getCatalog()->getPageMode()) {
case Catalog::pageModeNone:
return use_none;
case Catalog::pageModeOutlines:
return use_outlines;
case Catalog::pageModeThumbs:
return use_thumbs;
case Catalog::pageModeFullScreen:
return fullscreen;
case Catalog::pageModeOC:
return use_oc;
case Catalog::pageModeAttach:
return use_attach;
default:
return use_none;
}
}
document::page_layout_enum document::page_layout() const
{
switch (d->doc->getCatalog()->getPageLayout()) {
case Catalog::pageLayoutNone:
return no_layout;
case Catalog::pageLayoutSinglePage:
return single_page;
case Catalog::pageLayoutOneColumn:
return one_column;
case Catalog::pageLayoutTwoColumnLeft:
return two_column_left;
case Catalog::pageLayoutTwoColumnRight:
return two_column_right;
case Catalog::pageLayoutTwoPageLeft:
return two_page_left;
case Catalog::pageLayoutTwoPageRight:
return two_page_right;
default:
return no_layout;
}
}
void document::get_pdf_version(int *major, int *minor) const
{
if (major) {
*major = d->doc->getPDFMajorVersion();
}
if (minor) {
*minor = d->doc->getPDFMinorVersion();
}
}
std::vector<std::string> document::info_keys() const
{
if (d->is_locked) {
return std::vector<std::string>();
}
Object info;
if (!d->doc->getDocInfo(&info)->isDict()) {
info.free();
return std::vector<std::string>();
}
Dict *info_dict = info.getDict();
std::vector<std::string> keys(info_dict->getLength());
for (int i = 0; i < info_dict->getLength(); ++i) {
keys[i] = std::string(info_dict->getKey(i));
}
info.free();
return keys;
}
ustring document::info_key(const std::string &key) const
{
if (d->is_locked) {
return ustring();
}
Object info;
if (!d->doc->getDocInfo(&info)->isDict()) {
info.free();
return ustring();
}
Dict *info_dict = info.getDict();
Object obj;
ustring result;
if (info_dict->lookup(PSTR(key.c_str()), &obj)->isString()) {
result = detail::unicode_GooString_to_ustring(obj.getString());
}
obj.free();
info.free();
return result;
}
unsigned int document::info_date(const std::string &key) const
{
if (d->is_locked) {
return (unsigned int)(-1);
}
Object info;
if (!d->doc->getDocInfo(&info)->isDict()) {
info.free();
return (unsigned int)(-1);
}
Dict *info_dict = info.getDict();
Object obj;
unsigned int result = (unsigned int)(-1);
if (info_dict->lookup(PSTR(key.c_str()), &obj)->isString()) {
result = convert_date(obj.getString()->getCString());
}
obj.free();
info.free();
return result;
}
int document::pages() const
{
return d->doc->getNumPages();
}
page* document::create_page(const ustring &label) const
{
std::auto_ptr<GooString> goolabel(detail::ustring_to_unicode_GooString(label));
int index = 0;
if (!d->doc->getCatalog()->labelToIndex(goolabel.get(), &index)) {
return 0;
}
return create_page(index);
}
page* document::create_page(int index) const
{
return index >= 0 && index < d->doc->getNumPages() ? new page(d, index) : 0;
}
std::vector<font_info> document::fonts() const
{
std::vector<font_info> result;
font_iterator it(0, d);
while (it.has_next()) {
const std::vector<font_info> l = it.next();
std::copy(l.begin(), l.end(), std::back_inserter(result));
}
return result;
}
font_iterator* document::create_font_iterator(int start_page) const
{
return new font_iterator(start_page, d);
}
toc* document::create_toc() const
{
return toc_private::load_from_outline(d->doc->getOutline());
}
bool document::has_embedded_files() const
{
return d->doc->getCatalog()->numEmbeddedFiles() > 0;
}
std::vector<embedded_file *> document::embedded_files() const
{
if (d->is_locked) {
return std::vector<embedded_file *>();
}
if (d->embedded_files.empty() && d->doc->getCatalog()->numEmbeddedFiles() > 0) {
const int num = d->doc->getCatalog()->numEmbeddedFiles();
d->embedded_files.resize(num);
for (int i = 0; i < num; ++i) {
EmbFile *ef = d->doc->getCatalog()->embeddedFile(i);
d->embedded_files[i] = embedded_file_private::create(ef);
}
}
return d->embedded_files;
}
document* document::load_from_file(const std::string &file_name,
const std::string &owner_password,
const std::string &user_password)
{
document_private *doc = new document_private(
new GooString(file_name.c_str()),
owner_password, user_password);
return document_private::check_document(doc);
}