diff options
Diffstat (limited to 'Build/source/libs/poppler/poppler-src/poppler/Form.cc')
-rw-r--r-- | Build/source/libs/poppler/poppler-src/poppler/Form.cc | 651 |
1 files changed, 407 insertions, 244 deletions
diff --git a/Build/source/libs/poppler/poppler-src/poppler/Form.cc b/Build/source/libs/poppler/poppler-src/poppler/Form.cc index 8f8d14c4ebd..3c23dd3f651 100644 --- a/Build/source/libs/poppler/poppler-src/poppler/Form.cc +++ b/Build/source/libs/poppler/poppler-src/poppler/Form.cc @@ -5,7 +5,7 @@ // This file is licensed under the GPLv2 or later // // Copyright 2006-2008 Julien Rebetez <julienr@svn.gnome.org> -// Copyright 2007-2012, 2015, 2016 Albert Astals Cid <aacid@kde.org> +// Copyright 2007-2012, 2015-2017 Albert Astals Cid <aacid@kde.org> // Copyright 2007-2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org> // Copyright 2007, 2013, 2016 Adrian Johnson <ajohnson@redneon.com> // Copyright 2007 Iñigo Martínez <inigomartinez@gmail.com> @@ -17,6 +17,8 @@ // Copyright 2012 Fabio D'Urso <fabiodurso@hotmail.it> // Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com> // Copyright 2015 André Esser <bepandre@hotmail.com> +// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de> +// Copyright 2017 Bernd Kuhls <berndkuhls@hotmail.com> // //======================================================================== @@ -27,8 +29,11 @@ #endif #include <set> +#include <limits> #include <stddef.h> +#include <stdlib.h> #include <string.h> +#include <ctype.h> #include "goo/gmem.h" #include "goo/GooString.h" #include "Error.h" @@ -47,6 +52,7 @@ #include "PDFDocEncoding.h" #include "Annot.h" #include "Link.h" +#include "Lexer.h" //return a newly allocated char* containing an UTF16BE string of size length char* pdfDocEncodingToUTF16 (GooString* orig, int* length) @@ -56,8 +62,8 @@ char* pdfDocEncodingToUTF16 (GooString* orig, int* length) char *result = new char[(*length)]; char *cstring = orig->getCString(); //unicode marker - result[0] = 0xfe; - result[1] = 0xff; + result[0] = (char)0xfe; + result[1] = (char)0xff; //convert to utf16 for(int i=2,j=0; i<(*length); i+=2,j++) { Unicode u = pdfDocEncoding[(unsigned int)((unsigned char)cstring[j])]&0xffff; @@ -85,7 +91,7 @@ FormWidget::FormWidget(PDFDoc *docA, Object *aobj, unsigned num, Ref aref, FormF childNum = num; doc = docA; xref = doc->getXRef(); - aobj->copy(&obj); + obj = aobj->copy(); type = formUndef; field = fieldA; widget = NULL; @@ -95,7 +101,6 @@ FormWidget::~FormWidget() { if (widget) widget->decRefCnt(); - obj.free (); } #ifdef DEBUG_FORMS @@ -108,10 +113,8 @@ void FormWidget::createWidgetAnnotation() { if (widget) return; - Object obj1; - obj1.initRef(ref.num, ref.gen); - widget = new AnnotWidget(doc, obj.getDict(), &obj1, field); - obj1.free(); + Object obj1(ref.num, ref.gen); + widget = new AnnotWidget(doc, &obj, &obj1, field); } GBool FormWidget::inRect(double x, double y) const { @@ -178,13 +181,13 @@ FormWidgetButton::FormWidgetButton (PDFDoc *docA, Object *aobj, unsigned num, Re type = formButton; onStr = NULL; - Object obj1, obj2; - // Find the name of the ON state in the AP dictionnary // The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off // The "on" state may be stored under any other name - if (obj.dictLookup("AP", &obj1)->isDict()) { - if (obj1.dictLookup("N", &obj2)->isDict()) { + Object obj1 = obj.dictLookup("AP"); + if (obj1.isDict()) { + Object obj2 = obj1.dictLookup("N"); + if (obj2.isDict()) { for (int i = 0; i < obj2.dictGetLength(); i++) { char *key = obj2.dictGetKey(i); if (strcmp (key, "Off") != 0) { @@ -193,9 +196,7 @@ FormWidgetButton::FormWidgetButton (PDFDoc *docA, Object *aobj, unsigned num, Re } } } - obj2.free(); } - obj1.free(); } char *FormWidgetButton::getOnStr() { @@ -315,13 +316,18 @@ int FormWidgetText::getMaxLen () const return parent()->getMaxLen (); } -void FormWidgetText::setContent(GooString* new_content) +double FormWidgetText::getTextFontSize() { - if (isReadOnly()) { - error(errInternal, -1, "FormWidgetText::setContentCopy called on a read only field\n"); - return; - } + return parent()->getTextFontSize(); +} +void FormWidgetText::setTextFontSize(int fontSize) +{ + parent()->setTextFontSize(fontSize); +} + +void FormWidgetText::setContent(GooString* new_content) +{ parent()->setContentCopy(new_content); } @@ -351,30 +357,18 @@ bool FormWidgetChoice::_checkRange (int i) void FormWidgetChoice::select (int i) { - if (isReadOnly()) { - error(errInternal, -1, "FormWidgetChoice::select called on a read only field\n"); - return; - } if (!_checkRange(i)) return; parent()->select(i); } void FormWidgetChoice::toggle (int i) { - if (isReadOnly()) { - error(errInternal, -1, "FormWidgetChoice::toggle called on a read only field\n"); - return; - } if (!_checkRange(i)) return; parent()->toggle(i); } void FormWidgetChoice::deselectAll () { - if (isReadOnly()) { - error(errInternal, -1, "FormWidgetChoice::deselectAll called on a read only field\n"); - return; - } parent()->deselectAll(); } @@ -401,10 +395,6 @@ bool FormWidgetChoice::isSelected (int i) void FormWidgetChoice::setEditChoice (GooString* new_content) { - if (isReadOnly()) { - error(errInternal, -1, "FormWidgetText::setEditChoice called on a read only field\n"); - return; - } if (!hasEdit()) { error(errInternal, -1, "FormFieldChoice::setEditChoice : trying to edit an non-editable choice\n"); return; @@ -464,9 +454,148 @@ FormWidgetSignature::FormWidgetSignature(PDFDoc *docA, Object *aobj, unsigned nu type = formSignature; } -SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation) +SignatureInfo *FormWidgetSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime) +{ + return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation, validationTime); +} + +std::vector<Goffset> FormWidgetSignature::getSignedRangeBounds() +{ + Object* obj = static_cast<FormFieldSignature*>(field)->getByteRange(); + std::vector<Goffset> range_vec; + if (obj->isArray()) + { + if (obj->arrayGetLength() == 4) + { + for (int i = 0; i < 2; ++i) + { + Object offsetObj(obj->arrayGet(2*i)); + Object lenObj(obj->arrayGet(2*i+1)); + if (offsetObj.isIntOrInt64() && lenObj.isIntOrInt64()) + { + Goffset offset = offsetObj.getIntOrInt64(); + Goffset len = lenObj.getIntOrInt64(); + range_vec.push_back(offset); + range_vec.push_back(offset+len); + } + } + } + } + return range_vec; +} + +GooString* FormWidgetSignature::getCheckedSignature(Goffset *checkedFileSize) { - return static_cast<FormFieldSignature*>(field)->validateSignature(doVerifyCert, forceRevalidation); + Goffset start = 0; + Goffset end = 0; + const std::vector<Goffset> ranges = getSignedRangeBounds(); + if (ranges.size() == 4) + { + start = ranges[1]; + end = ranges[2]; + } + if (end >= start+6) + { + BaseStream* stream = doc->getBaseStream(); + *checkedFileSize = stream->getLength(); + Goffset len = end-start; + stream->setPos(end-1); + int c2 = stream->lookChar(); + stream->setPos(start); + int c1 = stream->getChar(); + // PDF signatures are first ASN1 DER, then hex encoded PKCS#7 structures, + // possibly padded with 0 characters and enclosed in '<' and '>'. + // The ASN1 DER encoding of a PKCS#7 structure must start with the tag 0x30 + // for SEQUENCE. The next byte must be 0x80 for ASN1 DER indefinite length + // encoding or (0x80 + n) for ASN1 DER definite length encoding + // where n is the number of subsequent "length bytes" which big-endian + // encode the length of the content of the SEQUENCE following them. + if (len <= std::numeric_limits<int>::max() && *checkedFileSize > end && c1 == '<' && c2 == '>') + { + GooString gstr; + ++start; + --end; + len = end-start; + Goffset pos = 0; + do + { + c1 = stream->getChar(); + if (c1 == EOF) + return nullptr; + gstr.append(static_cast<char>(c1)); + } while (++pos < len); + if (gstr.getChar(0) == '3' && gstr.getChar(1) == '0') + { + if (gstr.getChar(2) == '8' && gstr.getChar(3) == '0') + { + // ASN1 DER indefinite length encoding: + // We only check that all characters up to the enclosing '>' + // are hex characters and that there are two hex encoded 0 bytes + // just before the enclosing '>' marking the end of the indefinite + // length encoding. + int paddingCount = 0; + while (gstr.getChar(len-1) == '0' && gstr.getChar(len-2) == '0') + { + ++paddingCount; + len -= 2; + } + if (paddingCount < 2 || len%2 == 1) + len = 0; + } + else if (gstr.getChar(2) == '8') + { + // ASN1 DER definite length encoding: + // We calculate the length of the following bytes from the length bytes and + // check that after the length bytes and the following calculated number of + // bytes all bytes up to the enclosing '>' character are hex encoded 0 bytes. + int lenBytes = gstr.getChar(3) - '0'; + if (lenBytes > 0 && lenBytes <= 4) + { + int sigLen = 0; + for (int i = 0; i < 2*lenBytes; ++i) + { + sigLen <<= 4; + char c = gstr.getChar(i+4); + if (isdigit(c)) + sigLen += c - '0'; + else if (isxdigit(c) && c >= 'a') + sigLen += c - 'a' + 10; + else if (isxdigit(c) && c >= 'A') + sigLen += c - 'A' + 10; + else + { + len = 0; + break; + } + } + if (sigLen > 0 && 2*(sigLen+lenBytes) <= len-4) + { + for (int i = 2*(sigLen+lenBytes)+4; i < len; ++i) + { + if (gstr.getChar(i) != '0') + { + len = 0; + break; + } + } + } + else + len = 0; + } + } + for (int i = 0; i < len; ++i) + { + if (!isxdigit(gstr.getChar(i))) + len = 0; + } + if (len > 0) + { + return new GooString(&gstr, 0, len); + } + } + } + } + return nullptr; } void FormWidgetSignature::updateWidgetAppearance() @@ -483,7 +612,7 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par { doc = docA; xref = doc->getXRef(); - aobj->copy(&obj); + obj = aobj->copy(); Dict* dict = obj.getDict(); ref.num = ref.gen = 0; type = ty; @@ -500,76 +629,65 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par ref = aref; - Object obj1; //childs - if (dict->lookup("Kids", &obj1)->isArray()) { + Object obj1 = dict->lookup("Kids"); + if (obj1.isArray()) { // Load children for (int i = 0 ; i < obj1.arrayGetLength(); i++) { - Object childRef, childObj; - - if (!obj1.arrayGetNF(i, &childRef)->isRef()) { + Object childRef = obj1.arrayGetNF(i); + if (!childRef.isRef()) { error (errSyntaxError, -1, "Invalid form field renference"); - childRef.free(); continue; } - if (!obj1.arrayGet(i, &childObj)->isDict()) { + Object childObj = obj1.arrayGet(i); + if (!childObj.isDict()) { error (errSyntaxError, -1, "Form field child is not a dictionary"); - childObj.free(); - childRef.free(); continue; } const Ref ref = childRef.getRef(); if (usedParents->find(ref.num) == usedParents->end()) { - Object obj2, obj3; // Field child: it could be a form field or a widget or composed dict - if (childObj.dictLookupNF("Parent", &obj2)->isRef() || childObj.dictLookup("Parent", &obj3)->isDict()) { + Object obj2 = childObj.dictLookupNF("Parent"); + Object obj3 = childObj.dictLookup("Parent"); + if (obj2.isRef() || obj3.isDict()) { // Child is a form field or composed dict // We create the field, if it's composed // it will create the widget as a child std::set<int> usedParentsAux = *usedParents; usedParentsAux.insert(ref.num); - obj2.free(); - obj3.free(); if (terminal) { error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n"); - childObj.free(); - childRef.free(); continue; } numChildren++; children = (FormField**)greallocn(children, numChildren, sizeof(FormField*)); children[numChildren - 1] = Form::createFieldFromDict(&childObj, doc, ref, this, &usedParentsAux); - } else if (childObj.dictLookup("Subtype", &obj2)->isName("Widget")) { - // Child is a widget annotation - if (!terminal && numChildren > 0) { - error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n"); - obj2.free(); - obj3.free(); - childObj.free(); - childRef.free(); - continue; - } - _createWidget(&childObj, ref); - } - obj2.free(); - obj3.free(); + } else { + obj2 = childObj.dictLookup("Subtype"); + if (obj2.isName("Widget")) { + // Child is a widget annotation + if (!terminal && numChildren > 0) { + error(errSyntaxWarning, -1, "Field can't have both Widget AND Field as kids\n"); + continue; + } + _createWidget(&childObj, ref); + } + } } - childObj.free(); - childRef.free(); } } else { // No children, if it's a composed dict, create the child widget - obj1.free(); - if (dict->lookup("Subtype", &obj1)->isName("Widget")) + obj1 = dict->lookup("Subtype"); + if (obj1.isName("Widget")) _createWidget(&obj, ref); } - obj1.free(); //flags - if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + obj1 = Form::fieldLookup(dict, "Ff"); + if (obj1.isInt()) { int flags = obj1.getInt(); if (flags & 0x1) { // 1 -> ReadOnly readOnly = true; @@ -581,39 +699,38 @@ FormField::FormField(PDFDoc *docA, Object *aobj, const Ref& aref, FormField *par //TODO } } - obj1.free(); // Variable Text - if (Form::fieldLookup(dict, "DA", &obj1)->isString()) + obj1 = Form::fieldLookup(dict, "DA"); + if (obj1.isString()) defaultAppearance = obj1.getString()->copy(); - obj1.free(); - if (Form::fieldLookup(dict, "Q", &obj1)->isInt()) { + obj1 = Form::fieldLookup(dict, "Q"); + if (obj1.isInt()) { quadding = static_cast<VariableTextQuadding>(obj1.getInt()); hasQuadding = gTrue; } - obj1.free(); - if (dict->lookup("T", &obj1)->isString()) { + obj1 = dict->lookup("T"); + if (obj1.isString()) { partialName = obj1.getString()->copy(); } else { partialName = NULL; } - obj1.free(); - if (dict->lookup("TU", &obj1)->isString()) { + obj1 = dict->lookup("TU"); + if (obj1.isString()) { alternateUiName = obj1.getString()->copy(); } else { alternateUiName = NULL; } - obj1.free(); - if(dict->lookup("TM", &obj1)->isString()) { + obj1 = dict->lookup("TM"); + if(obj1.isString()) { mappingName = obj1.getString()->copy(); } else { mappingName = NULL; } - obj1.free(); } void FormField::setPartialName(const GooString &name) @@ -621,9 +738,7 @@ void FormField::setPartialName(const GooString &name) delete partialName; partialName = name.copy(); - Object obj1; - obj1.initString(name.copy()); - obj.getDict()->set("T", &obj1); + obj.getDict()->set("T", Object(name.copy())); xref->setModifiedObject(&obj, ref); } @@ -640,7 +755,6 @@ FormField::~FormField() delete widgets[i]; gfree (widgets); } - obj.free(); delete defaultAppearance; delete partialName; @@ -710,7 +824,6 @@ void FormField::_createWidget (Object *obj, Ref aref) default: error(errSyntaxWarning, -1, "SubType on non-terminal field, invalid document?"); numChildren--; - terminal = false; } } @@ -732,7 +845,7 @@ FormWidget* FormField::findWidgetByRef (Ref aref) } GooString* FormField::getFullyQualifiedName() { - Object obj1, obj2; + Object obj1; Object parent; GooString *parent_name; GooString *full_name; @@ -743,9 +856,10 @@ GooString* FormField::getFullyQualifiedName() { full_name = new GooString(); - obj.copy(&obj1); - while (obj1.dictLookup("Parent", &parent)->isDict()) { - if (parent.dictLookup("T", &obj2)->isString()) { + obj1 = obj.copy(); + while (parent = obj1.dictLookup("Parent"), parent.isDict()) { + Object obj2 = parent.dictLookup("T"); + if (obj2.isString()) { parent_name = obj2.getString(); if (unicode_encoded) { @@ -768,14 +882,9 @@ GooString* FormField::getFullyQualifiedName() { full_name->insert(0, parent_name); } } - obj2.free(); } - obj1.free(); - parent.copy(&obj1); - parent.free(); + obj1 = parent.copy(); } - obj1.free(); - parent.free(); if (partialName) { if (unicode_encoded) { @@ -811,8 +920,7 @@ GooString* FormField::getFullyQualifiedName() { } if (unicode_encoded) { - full_name->insert(0, 0xff); - full_name->insert(0, 0xfe); + full_name->prependUnicodeMarker(); } fullyQualifiedName = full_name; @@ -842,11 +950,11 @@ FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, For noAllOff = false; siblings = NULL; numSiblings = 0; - appearanceState.initNull(); + appearanceState.setToNull(); - Object obj1; - btype = formButtonCheck; - if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + btype = formButtonCheck; + Object obj1 = Form::fieldLookup(dict, "Ff"); + if (obj1.isInt()) { int flags = obj1.getInt(); if (flags & 0x10000) { // 17 -> push button @@ -865,7 +973,7 @@ FormFieldButton::FormFieldButton(PDFDoc *docA, Object *aobj, const Ref& ref, For if (btype != formButtonPush) { // Even though V is inheritable we are interested in the value of this // field, if not present it's probably because it's a button in a set. - dict->lookup("V", &appearanceState); + appearanceState = dict->lookup("V"); } } @@ -924,11 +1032,6 @@ void FormFieldButton::fillChildrenSiblingsID() GBool FormFieldButton::setState(char *state) { - if (readOnly) { - error(errInternal, -1, "FormFieldButton::setState called on a readOnly field\n"); - return gFalse; - } - // A check button could behave as a radio button // when it's in a set of more than 1 buttons if (btype != formButtonRadio && btype != formButtonCheck) @@ -994,19 +1097,13 @@ GBool FormFieldButton::getState(char *state) { } void FormFieldButton::updateState(char *state) { - Object obj1; - - appearanceState.free(); - appearanceState.initName(state); - - appearanceState.copy(&obj1); - obj.getDict()->set("V", &obj1); + appearanceState = Object(objName, state); + obj.getDict()->set("V", appearanceState.copy()); xref->setModifiedObject(&obj, ref); } FormFieldButton::~FormFieldButton() { - appearanceState.free(); if (siblings) gfree(siblings); } @@ -1023,7 +1120,8 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false; maxLen = 0; - if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + obj1 = Form::fieldLookup(dict, "Ff"); + if (obj1.isInt()) { int flags = obj1.getInt(); if (flags & 0x1000) // 13 -> Multiline multiline = true; @@ -1040,14 +1138,14 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie if (flags & 0x2000000)// 26 -> RichText richText = true; } - obj1.free(); - if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) { + obj1 = Form::fieldLookup(dict, "MaxLen"); + if (obj1.isInt()) { maxLen = obj1.getInt(); } - obj1.free(); - if (Form::fieldLookup(dict, "V", &obj1)->isString()) { + obj1 = Form::fieldLookup(dict, "V"); + if (obj1.isString()) { if (obj1.getString()->hasUnicodeMarker()) { if (obj1.getString()->getLength() > 2) content = obj1.getString()->copy(); @@ -1059,7 +1157,6 @@ FormFieldText::FormFieldText(PDFDoc *docA, Object *aobj, const Ref& ref, FormFie delete [] tmp_str; } } - obj1.free(); } #ifdef DEBUG_FORMS @@ -1086,14 +1183,11 @@ void FormFieldText::setContentCopy (GooString* new_content) //append the unicode marker <FE FF> if needed if (!content->hasUnicodeMarker()) { - content->insert(0, 0xff); - content->insert(0, 0xfe); + content->prependUnicodeMarker(); } } - Object obj1; - obj1.initString(content ? content->copy() : new GooString("")); - obj.getDict()->set("V", &obj1); + obj.getDict()->set("V", Object(content ? content->copy() : new GooString(""))); xref->setModifiedObject(&obj, ref); updateChildrenAppearance(); } @@ -1103,6 +1197,87 @@ FormFieldText::~FormFieldText() delete content; } +double FormFieldText::getTextFontSize() +{ + GooList* daToks = new GooList(); + int idx = parseDA(daToks); + double fontSize = -1; + if (idx >= 0) { + char* p = nullptr; + fontSize = strtod(static_cast<GooString*>(daToks->get(idx))->getCString(), &p); + if (!p || *p) + fontSize = -1; + } + deleteGooList(daToks, GooString); + return fontSize; +} + +void FormFieldText::setTextFontSize(int fontSize) +{ + if (fontSize > 0 && obj.isDict()) { + GooList* daToks = new GooList(); + int idx = parseDA(daToks); + if (idx == -1) { + error(errSyntaxError, -1, "FormFieldText:: invalid DA object\n"); + deleteGooList(daToks, GooString); + return; + } + if (defaultAppearance) + delete defaultAppearance; + defaultAppearance = new GooString; + for (int i = 0; i < daToks->getLength(); ++i) { + if (i > 0) + defaultAppearance->append(' '); + if (i == idx) { + defaultAppearance->appendf("{0:d}", fontSize); + } else { + defaultAppearance->append(static_cast<GooString*>(daToks->get(i))); + } + } + deleteGooList(daToks, GooString); + obj.dictSet("DA", Object(defaultAppearance->copy())); + xref->setModifiedObject(&obj, ref); + updateChildrenAppearance(); + } +} + +int FormFieldText::tokenizeDA(GooString* da, GooList* daToks, const char* searchTok) +{ + int idx = -1; + if(da && daToks) { + int i = 0; + int j = 0; + while (i < da->getLength()) { + while (i < da->getLength() && Lexer::isSpace(da->getChar(i))) { + ++i; + } + if (i < da->getLength()) { + for (j = i + 1; j < da->getLength() && !Lexer::isSpace(da->getChar(j)); ++j) { + } + GooString* tok = new GooString(da, i, j - i); + if (searchTok && !tok->cmp(searchTok)) + idx = daToks->getLength(); + daToks->append(tok); + i = j; + } + } + } + return idx; +} + +int FormFieldText::parseDA(GooList* daToks) +{ + int idx = -1; + if (obj.isDict()) { + Object objDA(obj.dictLookup("DA")); + if (objDA.isString()) { + GooString* da = objDA.getString(); + idx = tokenizeDA(da, daToks, "Tf") - 1; + } + } + return idx; +} + //------------------------------------------------------------------------ // FormFieldChoice @@ -1120,7 +1295,8 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false; - if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) { + obj1 = Form::fieldLookup(dict, "Ff"); + if (obj1.isInt()) { int flags = obj1.getInt(); if (flags & 0x20000) // 18 -> Combo combo = true; @@ -1133,67 +1309,62 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For if (flags & 0x4000000) // 27 -> CommitOnSelChange doCommitOnSelChange = true; } - obj1.free(); - if (dict->lookup("TI", &obj1)->isInt()) + obj1 = dict->lookup("TI"); + if (obj1.isInt()) topIdx = obj1.getInt(); - obj1.free(); - - if (dict->lookup("Opt", &obj1)->isArray()) { - Object obj2; + obj1 = dict->lookup("Opt"); + if (obj1.isArray()) { numChoices = obj1.arrayGetLength(); choices = new ChoiceOpt[numChoices]; memset(choices, 0, sizeof(ChoiceOpt) * numChoices); for (int i = 0; i < numChoices; i++) { - if (obj1.arrayGet(i, &obj2)->isString()) { + Object obj2 = obj1.arrayGet(i); + if (obj2.isString()) { choices[i].optionName = obj2.getString()->copy(); } else if (obj2.isArray()) { // [Export_value, Displayed_text] - Object obj3; - if (obj2.arrayGetLength() < 2) { error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n"); continue; } - if (obj2.arrayGet(0, &obj3)->isString()) + Object obj3 = obj2.arrayGet(0); + if (obj3.isString()) choices[i].exportVal = obj3.getString()->copy(); else error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- exported value not a string\n"); - obj3.free(); - if (obj2.arrayGet(1, &obj3)->isString()) + obj3 = obj2.arrayGet(1); + if (obj3.isString()) choices[i].optionName = obj3.getString()->copy(); else error(errSyntaxError, -1, "FormWidgetChoice:: invalid Opt entry -- choice name not a string\n"); - obj3.free(); } else { error(errSyntaxError, -1, "FormWidgetChoice:: invalid {0:d} Opt entry\n", i); } - obj2.free(); } } else { //empty choice } - obj1.free(); // Find selected items // Note: PDF specs say that /V has precedence over /I, but acroread seems to // do the opposite. We do the same. - if (Form::fieldLookup(dict, "I", &obj1)->isArray()) { + obj1 = Form::fieldLookup(dict, "I"); + if (obj1.isArray()) { for (int i = 0; i < obj1.arrayGetLength(); i++) { - Object obj2; - if (obj1.arrayGet(i, &obj2)->isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) { + Object obj2 = obj1.arrayGet(i); + if (obj2.isInt() && obj2.getInt() >= 0 && obj2.getInt() < numChoices) { choices[obj2.getInt()].selected = true; } - obj2.free(); } } else { - obj1.free(); // Note: According to PDF specs, /V should *never* contain the exportVal. // However, if /Opt is an array of (exportVal,optionName) pairs, acroread // seems to expect the exportVal instead of the optionName and so we do too. - if (Form::fieldLookup(dict, "V", &obj1)->isString()) { + obj1 = Form::fieldLookup(dict, "V"); + if (obj1.isString()) { GBool optionFound = gFalse; for (int i = 0; i < numChoices; i++) { @@ -1220,8 +1391,7 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For } else if (obj1.isArray()) { for (int i = 0; i < numChoices; i++) { for (int j = 0; j < obj1.arrayGetLength(); j++) { - Object obj2; - obj1.arrayGet(j, &obj2); + Object obj2 = obj1.arrayGet(j); GBool matches = gFalse; if (choices[i].exportVal) { @@ -1234,8 +1404,6 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For } } - obj2.free(); - if (matches) { choices[i].selected = true; break; // We've determined that this option is selected. No need to keep on scanning @@ -1244,7 +1412,6 @@ FormFieldChoice::FormFieldChoice(PDFDoc *docA, Object *aobj, const Ref& ref, For } } } - obj1.free(); } FormFieldChoice::~FormFieldChoice() @@ -1266,35 +1433,35 @@ void FormFieldChoice::print(int indent) #endif void FormFieldChoice::updateSelection() { - Object objV, objI, obj1; - objI.initNull(); + Object objV, obj1; + Object objI(objNull); if (edit && editedChoice) { // This is an editable combo-box with user-entered text - objV.initString(editedChoice->copy()); + objV = Object(editedChoice->copy()); } else { const int numSelected = getNumSelected(); // Create /I array only if multiple selection is allowed (as per PDF spec) if (multiselect) { - objI.initArray(xref); + objI = Object(new Array(xref)); } if (numSelected == 0) { // No options are selected - objV.initString(new GooString("")); + objV = Object(new GooString("")); } else if (numSelected == 1) { // Only one option is selected for (int i = 0; i < numChoices; i++) { if (choices[i].selected) { if (multiselect) { - objI.arrayAdd(obj1.initInt(i)); + objI.arrayAdd(Object(i)); } if (choices[i].exportVal) { - objV.initString(choices[i].exportVal->copy()); + objV = Object(choices[i].exportVal->copy()); } else if (choices[i].optionName) { - objV.initString(choices[i].optionName->copy()); + objV = Object(choices[i].optionName->copy()); } break; // We've just written the selected option. No need to keep on scanning @@ -1302,25 +1469,25 @@ void FormFieldChoice::updateSelection() { } } else { // More than one option is selected - objV.initArray(xref); + objV = Object(new Array(xref)); for (int i = 0; i < numChoices; i++) { if (choices[i].selected) { if (multiselect) { - objI.arrayAdd(obj1.initInt(i)); + objI.arrayAdd(Object(i)); } if (choices[i].exportVal) { - objV.arrayAdd(obj1.initString(choices[i].exportVal->copy())); + objV.arrayAdd(Object(choices[i].exportVal->copy())); } else if (choices[i].optionName) { - objV.arrayAdd(obj1.initString(choices[i].optionName->copy())); + objV.arrayAdd(Object(choices[i].optionName->copy())); } } } } } - obj.getDict()->set("V", &objV); - obj.getDict()->set("I", &objI); + obj.getDict()->set("V", std::move(objV)); + obj.getDict()->set("I", std::move(objI)); xref->setModifiedObject(&obj, ref); updateChildrenAppearance(); } @@ -1373,8 +1540,7 @@ void FormFieldChoice::setEditChoice (GooString* new_content) //append the unicode marker <FE FF> if needed if (!editedChoice->hasUnicodeMarker()) { - editedChoice->insert(0, 0xff); - editedChoice->insert(0, 0xfe); + editedChoice->prependUnicodeMarker(); } } updateSelection(); @@ -1411,7 +1577,9 @@ GooString *FormFieldChoice::getSelectedChoice() { // FormFieldSignature //------------------------------------------------------------------------ FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& ref, FormField *parent, std::set<int> *usedParents) - : FormField(docA, dict, ref, parent, usedParents, formSignature) + : FormField(docA, dict, ref, parent, usedParents, formSignature), + signature_type(adbe_pkcs7_detached), + signature(nullptr), signature_info(nullptr) { signature = NULL; @@ -1421,7 +1589,6 @@ FormFieldSignature::FormFieldSignature(PDFDoc *docA, Object *dict, const Ref& re FormFieldSignature::~FormFieldSignature() { - byte_range.free(); delete signature_info; delete signature; } @@ -1431,39 +1598,40 @@ void FormFieldSignature::parseInfo() if (!obj.isDict()) return; - Object sig_dict, contents_obj, time_of_signing, subfilterName; - // retrieve PKCS#7 - obj.dictLookup("V", &sig_dict); + Object sig_dict = obj.dictLookup("V"); if (!sig_dict.isDict()) { - sig_dict.free(); return; } - sig_dict.dictLookup("Contents", &contents_obj); + Object contents_obj = sig_dict.dictLookup("Contents"); if (contents_obj.isString()) { signature = contents_obj.getString()->copy(); } - contents_obj.free(); - sig_dict.dictLookup("ByteRange", &byte_range); + byte_range = sig_dict.dictLookup("ByteRange"); // retrieve SigningTime - sig_dict.dictLookup("M", &time_of_signing); + Object time_of_signing = sig_dict.dictLookup("M"); if (time_of_signing.isString()) { GooString *time_str = time_of_signing.getString(); signature_info->setSigningTime(dateStringToTime(time_str)); // Put this information directly in SignatureInfo object - time_of_signing.free(); } // check if subfilter is supported for signature validation, only detached signatures work for now - sig_dict.dictLookup("SubFilter", &subfilterName); - if (subfilterName.isName("adbe.pkcs7.detached") || subfilterName.isName("adbe.pkcs7.sha1")) { + Object subfilterName = sig_dict.dictLookup("SubFilter"); + if (subfilterName.isName("adbe.pkcs7.sha1")) { + signature_type = adbe_pkcs7_sha1; + signature_info->setSubFilterSupport(true); + } + else if (subfilterName.isName("adbe.pkcs7.detached")) { + signature_type = adbe_pkcs7_detached; + signature_info->setSubFilterSupport(true); + } + else if (subfilterName.isName("ETSI.CAdES.detached")) { + signature_type = ETSI_CAdES_detached; signature_info->setSubFilterSupport(true); } - - subfilterName.free(); - sig_dict.free(); } void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset block_len) @@ -1492,8 +1660,12 @@ void FormFieldSignature::hashSignedDataBlock(SignatureHandler *handler, Goffset #endif } +FormSignatureType FormWidgetSignature::signatureType() +{ + return static_cast<FormFieldSignature*>(field)->signature_type; +} -SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation) +SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime) { #ifdef ENABLE_NSS3 if (!signature_info->isSubfilterSupported()) { @@ -1530,9 +1702,8 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for Goffset fileLength = doc->getBaseStream()->getLength(); for (int i = 0; i < arrayLen/2; i++) { - Object offsetObj, lenObj; - byte_range.arrayGet(i*2, &offsetObj); - byte_range.arrayGet(i*2+1, &lenObj); + Object offsetObj = byte_range.arrayGet(i*2); + Object lenObj = byte_range.arrayGet(i*2+1); if (!offsetObj.isIntOrInt64() || !lenObj.isIntOrInt64()) { error(errSyntaxError, 0, "Illegal values in ByteRange array"); @@ -1554,6 +1725,8 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for sig_val_state = signature_handler.validateSignature(); signature_info->setSignatureValStatus(SignatureHandler::NSS_SigTranslate(sig_val_state)); signature_info->setSignerName(signature_handler.getSignerName()); + signature_info->setSubjectDN(signature_handler.getSignerSubjectDN()); + signature_info->setHashAlgorithm(signature_handler.getHashAlgorithm()); // verify if signature contains a 'signing time' attribute if (signature_handler.getSigningTime() != 0) { @@ -1564,7 +1737,7 @@ SignatureInfo *FormFieldSignature::validateSignature(bool doVerifyCert, bool for return signature_info; } - cert_val_state = signature_handler.validateCertificate(); + cert_val_state = signature_handler.validateCertificate(validationTime); signature_info->setCertificateValStatus(SignatureHandler::NSS_CertTranslate(cert_val_state)); #endif @@ -1598,50 +1771,41 @@ Form::Form(PDFDoc *docA, Object* acroFormA) defaultAppearance = NULL; defaultResources = NULL; - acroForm->dictLookup("NeedAppearances", &obj1); + obj1 = acroForm->dictLookup("NeedAppearances"); needAppearances = (obj1.isBool() && obj1.getBool()); - obj1.free(); - if (acroForm->dictLookup("DA", &obj1)->isString()) + obj1 = acroForm->dictLookup("DA"); + if (obj1.isString()) defaultAppearance = obj1.getString()->copy(); - obj1.free(); - if (acroForm->dictLookup("Q", &obj1)->isInt()) + obj1 = acroForm->dictLookup("Q"); + if (obj1.isInt()) quadding = static_cast<VariableTextQuadding>(obj1.getInt()); - obj1.free(); - acroForm->dictLookup("DR", &resDict); + resDict = acroForm->dictLookup("DR"); if (resDict.isDict()) { // At a minimum, this dictionary shall contain a Font entry - if (resDict.dictLookup("Font", &obj1)->isDict()) + obj1 = resDict.dictLookup("Font"); + if (obj1.isDict()) defaultResources = new GfxResources(xref, resDict.getDict(), NULL); - obj1.free(); } if (!defaultResources) { - resDict.free(); - resDict.initNull(); + resDict.setToNull(); } - acroForm->dictLookup("Fields", &obj1); + obj1 = acroForm->dictLookup("Fields"); if (obj1.isArray()) { Array *array = obj1.getArray(); - Object obj2; - for(int i=0; i<array->getLength(); i++) { - Object oref; - array->get(i, &obj2); - array->getNF(i, &oref); + Object obj2 = array->get(i); + Object oref = array->getNF(i); if (!oref.isRef()) { error(errSyntaxWarning, -1, "Direct object in rootFields"); - obj2.free(); - oref.free(); continue; } if (!obj2.isDict()) { error(errSyntaxWarning, -1, "Reference in Fields array to an invalid or non existent object"); - obj2.free(); - oref.free(); continue; } @@ -1653,13 +1817,24 @@ Form::Form(PDFDoc *docA, Object* acroFormA) std::set<int> usedParents; rootFields[numFields++] = createFieldFromDict (&obj2, doc, oref.getRef(), NULL, &usedParents); - obj2.free(); - oref.free(); } } else { error(errSyntaxError, -1, "Can't get Fields array\n"); } - obj1.free (); + + obj1 = acroForm->dictLookup("CO"); + if (obj1.isArray()) { + Array *array = obj1.getArray(); + calculateOrder.reserve(array->getLength()); + for(int i=0; i<array->getLength(); i++) { + Object oref = array->getNF(i); + if (!oref.isRef()) { + error(errSyntaxWarning, -1, "Direct object in CO"); + continue; + } + calculateOrder.push_back(oref.getRef()); + } + } #ifdef DEBUG_FORMS for (int i = 0; i < numFields; i++) @@ -1674,54 +1849,43 @@ Form::~Form() { gfree (rootFields); delete defaultAppearance; delete defaultResources; - resDict.free(); } // Look up an inheritable field dictionary entry. -static Object *fieldLookup(Dict *field, const char *key, Object *obj, std::set<int> *usedParents) { - Dict *dict; - Object parent; - - dict = field; - if (!dict->lookup(key, obj)->isNull()) { +static Object fieldLookup(Dict *field, const char *key, std::set<int> *usedParents) { + Dict *dict = field; + Object obj = dict->lookup(key); + if (!obj.isNull()) { return obj; } - obj->free(); - dict->lookupNF("Parent", &parent); + Object parent = dict->lookupNF("Parent"); if (parent.isRef()) { const Ref ref = parent.getRef(); if (usedParents->find(ref.num) == usedParents->end()) { usedParents->insert(ref.num); - Object obj2; - parent.fetch(dict->getXRef(), &obj2); + Object obj2 = parent.fetch(dict->getXRef()); if (obj2.isDict()) { - fieldLookup(obj2.getDict(), key, obj, usedParents); - } else { - obj->initNull(); + return fieldLookup(obj2.getDict(), key, usedParents); } - obj2.free(); } } else if (parent.isDict()) { - fieldLookup(parent.getDict(), key, obj, usedParents); - } else { - obj->initNull(); + return fieldLookup(parent.getDict(), key, usedParents); } - parent.free(); - return obj; + return Object(objNull); } -Object *Form::fieldLookup(Dict *field, const char *key, Object *obj) { +Object Form::fieldLookup(Dict *field, const char *key) { std::set<int> usedParents; - return ::fieldLookup(field, key, obj, &usedParents); + return ::fieldLookup(field, key, &usedParents); } FormField *Form::createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& pref, FormField *parent, std::set<int> *usedParents) { - Object obj2; FormField *field; - if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) { + Object obj2 = Form::fieldLookup(obj->getDict (), "FT"); + if (obj2.isName("Btn")) { field = new FormFieldButton(docA, obj, pref, parent, usedParents); } else if (obj2.isName("Tx")) { field = new FormFieldText(docA, obj, pref, parent, usedParents); @@ -1732,7 +1896,6 @@ FormField *Form::createFieldFromDict (Object* obj, PDFDoc *docA, const Ref& pref } else { //we don't have an FT entry => non-terminal field field = new FormField(docA, obj, pref, parent, usedParents); } - obj2.free(); return field; } |