| //======================================================================== |
| // |
| // Form.h |
| // |
| // This file is licensed under the GPLv2 or later |
| // |
| // Copyright 2006 Julien Rebetez <julienr@svn.gnome.org> |
| // Copyright 2007, 2008, 2011 Carlos Garcia Campos <carlosgc@gnome.org> |
| // Copyright 2007-2010, 2012, 2015-2019 Albert Astals Cid <aacid@kde.org> |
| // Copyright 2010 Mark Riedesel <mark@klowner.com> |
| // Copyright 2011 Pino Toscano <pino@kde.org> |
| // Copyright 2012 Fabio D'Urso <fabiodurso@hotmail.it> |
| // Copyright 2013 Adrian Johnson <ajohnson@redneon.com> |
| // Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com> |
| // Copyright 2015 André Esser <bepandre@hotmail.com> |
| // Copyright 2017 Roland Hieber <r.hieber@pengutronix.de> |
| // Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de> |
| // Copyright 2018 Andre Heinecke <aheinecke@intevation.de> |
| // Copyright 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich |
| // Copyright 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com> |
| // Copyright 2019 Oliver Sander <oliver.sander@tu-dresden.de> |
| // Copyright 2019 João Netto <joaonetto901@gmail.com> |
| // |
| //======================================================================== |
| |
| #ifndef FORM_H |
| #define FORM_H |
| |
| #include "Object.h" |
| #include "Annot.h" |
| |
| #include <time.h> |
| |
| #include <set> |
| #include <vector> |
| |
| class GooString; |
| class Array; |
| class Dict; |
| class Annot; |
| class AnnotWidget; |
| class Annots; |
| class LinkAction; |
| class GfxResources; |
| class PDFDoc; |
| class SignatureInfo; |
| class SignatureHandler; |
| |
| enum FormFieldType { |
| formButton, |
| formText, |
| formChoice, |
| formSignature, |
| formUndef |
| }; |
| |
| enum FormButtonType { |
| formButtonCheck, |
| formButtonPush, |
| formButtonRadio |
| }; |
| |
| enum VariableTextQuadding { |
| quaddingLeftJustified, |
| quaddingCentered, |
| quaddingRightJustified |
| }; |
| |
| enum FormSignatureType { |
| adbe_pkcs7_sha1, |
| adbe_pkcs7_detached, |
| ETSI_CAdES_detached |
| }; |
| |
| class Form; |
| class FormField; |
| class FormFieldButton; |
| class FormFieldText; |
| class FormFieldSignature; |
| class FormFieldChoice; |
| |
| //------------------------------------------------------------------------ |
| // FormWidget |
| // A FormWidget represents the graphical part of a field and is "attached" |
| // to a page. |
| //------------------------------------------------------------------------ |
| |
| class FormWidget { |
| public: |
| virtual ~FormWidget(); |
| |
| // Check if point is inside the field bounding rect |
| bool inRect(double x, double y) const; |
| |
| // Get the field bounding rect |
| void getRect(double *x1, double *y1, double *x2, double *y2) const; |
| |
| unsigned getID () { return ID; } |
| void setID (unsigned int i) { ID=i; } |
| |
| FormField *getField () { return field; } |
| FormFieldType getType() { return type; } |
| |
| Object* getObj() { return &obj; } |
| Ref getRef() { return ref; } |
| |
| void setChildNum (unsigned i) { childNum = i; } |
| unsigned getChildNum () { return childNum; } |
| |
| const GooString *getPartialName() const; |
| void setPartialName(const GooString &name); |
| const GooString *getAlternateUiName() const; |
| const GooString *getMappingName() const; |
| GooString *getFullyQualifiedName(); |
| |
| bool isModified () const; |
| |
| bool isReadOnly() const; |
| void setReadOnly(bool value); |
| |
| LinkAction *getActivationAction(); // The caller should not delete the result |
| LinkAction *getAdditionalAction(Annot::FormAdditionalActionsType type); // The caller should delete the result |
| bool setAdditionalAction(Annot::FormAdditionalActionsType t, const GooString &js); |
| |
| // return the unique ID corresponding to pageNum/fieldNum |
| static int encodeID (unsigned pageNum, unsigned fieldNum); |
| // decode id and retrieve pageNum and fieldNum |
| static void decodeID (unsigned id, unsigned* pageNum, unsigned* fieldNum); |
| |
| void createWidgetAnnotation(); |
| AnnotWidget *getWidgetAnnotation() const { return widget; } |
| |
| virtual void updateWidgetAppearance() = 0; |
| |
| void print(int indent = 0); |
| |
| protected: |
| FormWidget(PDFDoc *docA, Object *aobj, unsigned num, Ref aref, FormField *fieldA); |
| |
| AnnotWidget *widget; |
| FormField* field; |
| FormFieldType type; |
| Object obj; |
| Ref ref; |
| PDFDoc *doc; |
| XRef *xref; |
| |
| //index of this field in the parent's child list |
| unsigned childNum; |
| |
| /* |
| Field ID is an (unsigned) integer, calculated as follow : |
| the first sizeof/2 bits are the field number, relative to the page |
| the last sizeof/2 bits are the page number |
| [page number | field number] |
| (encoding) id = (pageNum << 4*sizeof(unsigned)) + fieldNum; |
| (decoding) pageNum = id >> 4*sizeof(unsigned); fieldNum = (id << 4*sizeof(unsigned)) >> 4*sizeof(unsigned); |
| */ |
| unsigned ID; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormWidgetButton |
| //------------------------------------------------------------------------ |
| |
| class FormWidgetButton: public FormWidget { |
| public: |
| FormWidgetButton(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p); |
| ~FormWidgetButton (); |
| |
| FormButtonType getButtonType() const; |
| |
| void setState (bool state); |
| bool getState () const; |
| |
| const char* getOnStr() const; |
| void setAppearanceState(const char *state); |
| void updateWidgetAppearance() override; |
| |
| protected: |
| FormFieldButton *parent() const; |
| GooString *onStr; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormWidgetText |
| //------------------------------------------------------------------------ |
| |
| class FormWidgetText: public FormWidget { |
| public: |
| FormWidgetText(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p); |
| //return the field's content (UTF16BE) |
| const GooString* getContent() const; |
| |
| //expects a UTF16BE string |
| void setContent(const GooString* new_content); |
| //sets the text inside the field appearance stream |
| void setAppearanceContent(const GooString* new_content); |
| |
| void updateWidgetAppearance() override; |
| |
| bool isMultiline () const; |
| bool isPassword () const; |
| bool isFileSelect () const; |
| bool noSpellCheck () const; |
| bool noScroll () const; |
| bool isComb () const; |
| bool isRichText () const; |
| int getMaxLen () const; |
| //return the font size of the field's text |
| double getTextFontSize(); |
| //set the font size of the field's text (currently only integer values) |
| void setTextFontSize(int fontSize); |
| |
| protected: |
| FormFieldText *parent() const; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormWidgetChoice |
| //------------------------------------------------------------------------ |
| |
| class FormWidgetChoice: public FormWidget { |
| public: |
| FormWidgetChoice(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p); |
| ~FormWidgetChoice(); |
| |
| int getNumChoices() const; |
| //return the display name of the i-th choice (UTF16BE) |
| const GooString* getChoice(int i) const; |
| //select the i-th choice |
| void select (int i); |
| |
| //toggle selection of the i-th choice |
| void toggle (int i); |
| |
| //deselect everything |
| void deselectAll (); |
| |
| //except a UTF16BE string |
| //only work for editable combo box, set the user-entered text as the current choice |
| void setEditChoice(const GooString* new_content); |
| |
| const GooString* getEditChoice () const; |
| |
| void updateWidgetAppearance() override; |
| bool isSelected (int i) const; |
| |
| bool isCombo () const; |
| bool hasEdit () const; |
| bool isMultiSelect () const; |
| bool noSpellCheck () const; |
| bool commitOnSelChange () const; |
| bool isListBox () const; |
| protected: |
| bool _checkRange (int i) const; |
| FormFieldChoice *parent() const; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormWidgetSignature |
| //------------------------------------------------------------------------ |
| |
| class FormWidgetSignature: public FormWidget { |
| public: |
| FormWidgetSignature(PDFDoc *docA, Object *dict, unsigned num, Ref ref, FormField *p); |
| void updateWidgetAppearance() override; |
| |
| FormSignatureType signatureType(); |
| // Use -1 for now as validationTime |
| SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime); |
| |
| // returns a list with the boundaries of the signed ranges |
| // the elements of the list are of type Goffset |
| std::vector<Goffset> getSignedRangeBounds(); |
| |
| // checks the length encoding of the signature and returns the hex encoded signature |
| // if the check passed (and the checked file size as output parameter in checkedFileSize) |
| // otherwise a nullptr is returned |
| GooString* getCheckedSignature(Goffset *checkedFileSize); |
| |
| const GooString *getSignature() const; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormField |
| // A FormField implements the logical side of a field and is "attached" to |
| // the Catalog. This is an internal class and client applications should |
| // only interact with FormWidgets. |
| //------------------------------------------------------------------------ |
| |
| class FormField { |
| public: |
| FormField(PDFDoc *docA, Object &&aobj, const Ref aref, FormField *parent, std::set<int> *usedParents, FormFieldType t=formUndef); |
| |
| virtual ~FormField(); |
| |
| // Accessors. |
| FormFieldType getType() const { return type; } |
| Object* getObj() { return &obj; } |
| Ref getRef() { return ref; } |
| |
| void setReadOnly (bool b); |
| bool isReadOnly () const { return readOnly; } |
| |
| GooString* getDefaultAppearance() const { return defaultAppearance; } |
| bool hasTextQuadding() const { return hasQuadding; } |
| VariableTextQuadding getTextQuadding() const { return quadding; } |
| |
| const GooString *getPartialName() const { return partialName; } |
| void setPartialName(const GooString &name); |
| const GooString *getAlternateUiName() const { return alternateUiName; } |
| const GooString *getMappingName() const { return mappingName; } |
| GooString *getFullyQualifiedName(); |
| |
| FormWidget* findWidgetByRef (Ref aref); |
| int getNumWidgets() { return terminal ? numChildren : 0; } |
| FormWidget *getWidget(int i) { return terminal ? widgets[i] : nullptr; } |
| |
| // only implemented in FormFieldButton |
| virtual void fillChildrenSiblingsID (); |
| |
| void createWidgetAnnotations(); |
| |
| void printTree(int indent = 0); |
| virtual void print(int indent = 0); |
| |
| protected: |
| void _createWidget (Object *obj, Ref aref); |
| void createChildren(std::set<int> *usedParents); |
| void updateChildrenAppearance(); |
| |
| FormFieldType type; // field type |
| Ref ref; |
| bool terminal; |
| Object obj; |
| PDFDoc *doc; |
| XRef *xref; |
| FormField **children; |
| FormField *parent; |
| int numChildren; |
| FormWidget **widgets; |
| bool readOnly; |
| |
| GooString *partialName; // T field |
| GooString *alternateUiName; // TU field |
| GooString *mappingName; // TM field |
| GooString *fullyQualifiedName; |
| |
| // Variable Text |
| GooString *defaultAppearance; |
| bool hasQuadding; |
| VariableTextQuadding quadding; |
| |
| private: |
| FormField() {} |
| }; |
| |
| |
| //------------------------------------------------------------------------ |
| // FormFieldButton |
| //------------------------------------------------------------------------ |
| |
| class FormFieldButton: public FormField { |
| public: |
| FormFieldButton(PDFDoc *docA, Object &&dict, const Ref ref, FormField *parent, std::set<int> *usedParents); |
| |
| FormButtonType getButtonType () const { return btype; } |
| |
| bool noToggleToOff () const { return noAllOff; } |
| |
| // returns true if the state modification is accepted |
| bool setState (const char *state); |
| bool getState(const char *state) const; |
| |
| const char *getAppearanceState() const { return appearanceState.isName() ? appearanceState.getName() : nullptr; } |
| |
| void fillChildrenSiblingsID () override; |
| |
| void setNumSiblings (int num); |
| void setSibling (int i, FormFieldButton *id) { siblings[i] = id; } |
| |
| //For radio buttons, return the fields of the other radio buttons in the same group |
| FormFieldButton* getSibling (int i) const { return siblings[i]; } |
| int getNumSiblings () const { return numSiblings; } |
| |
| void print(int indent) override; |
| |
| ~FormFieldButton(); |
| protected: |
| void updateState(const char *state); |
| |
| FormFieldButton** siblings; // IDs of dependent buttons (each button of a radio field has all the others buttons |
| // of the same field in this array) |
| int numSiblings; |
| |
| FormButtonType btype; |
| int size; |
| int active_child; //only used for combo box |
| bool noAllOff; |
| Object appearanceState; // V |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormFieldText |
| //------------------------------------------------------------------------ |
| |
| class FormFieldText: public FormField { |
| public: |
| FormFieldText(PDFDoc *docA, Object &&dict, const Ref ref, FormField *parent, std::set<int> *usedParents); |
| |
| const GooString* getContent () const { return content; } |
| const GooString* getAppearanceContent () const { return internalContent ? internalContent : content; } |
| void setContentCopy (const GooString* new_content); |
| void setAppearanceContentCopy (const GooString* new_content); |
| ~FormFieldText(); |
| |
| bool isMultiline () const { return multiline; } |
| bool isPassword () const { return password; } |
| bool isFileSelect () const { return fileSelect; } |
| bool noSpellCheck () const { return doNotSpellCheck; } |
| bool noScroll () const { return doNotScroll; } |
| bool isComb () const { return comb; } |
| bool isRichText () const { return richText; } |
| |
| int getMaxLen () const { return maxLen; } |
| |
| //return the font size of the field's text |
| double getTextFontSize(); |
| //set the font size of the field's text (currently only integer values) |
| void setTextFontSize(int fontSize); |
| |
| void print(int indent) override; |
| |
| static int tokenizeDA(const GooString* daString, std::vector<GooString*>* daToks, const char* searchTok); |
| |
| protected: |
| int parseDA(std::vector<GooString*>* daToks); |
| |
| GooString* content; |
| GooString* internalContent; |
| bool multiline; |
| bool password; |
| bool fileSelect; |
| bool doNotSpellCheck; |
| bool doNotScroll; |
| bool comb; |
| bool richText; |
| int maxLen; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormFieldChoice |
| //------------------------------------------------------------------------ |
| |
| class FormFieldChoice: public FormField { |
| public: |
| FormFieldChoice(PDFDoc *docA, Object &&aobj, const Ref ref, FormField *parent, std::set<int> *usedParents); |
| |
| ~FormFieldChoice(); |
| |
| int getNumChoices() const { return numChoices; } |
| const GooString* getChoice(int i) const { return choices ? choices[i].optionName : nullptr; } |
| const GooString* getExportVal (int i) const { return choices ? choices[i].exportVal : nullptr; } |
| // For multi-select choices it returns the first one |
| const GooString* getSelectedChoice() const; |
| |
| //select the i-th choice |
| void select (int i); |
| |
| //toggle selection of the i-th choice |
| void toggle (int i); |
| |
| //deselect everything |
| void deselectAll (); |
| |
| //only work for editable combo box, set the user-entered text as the current choice |
| void setEditChoice(const GooString* new_content); |
| |
| const GooString* getEditChoice () const; |
| |
| bool isSelected (int i) const { return choices[i].selected; } |
| |
| int getNumSelected (); |
| |
| bool isCombo () const { return combo; } |
| bool hasEdit () const { return edit; } |
| bool isMultiSelect () const { return multiselect; } |
| bool noSpellCheck () const { return doNotSpellCheck; } |
| bool commitOnSelChange () const { return doCommitOnSelChange; } |
| bool isListBox () const { return !combo; } |
| |
| int getTopIndex() const { return topIdx; } |
| |
| void print(int indent) override; |
| |
| protected: |
| void unselectAll(); |
| void updateSelection(); |
| |
| bool combo; |
| bool edit; |
| bool multiselect; |
| bool doNotSpellCheck; |
| bool doCommitOnSelChange; |
| |
| struct ChoiceOpt { |
| GooString* exportVal; //the export value ("internal" name) |
| GooString* optionName; //displayed name |
| bool selected; //if this choice is selected |
| }; |
| |
| int numChoices; |
| ChoiceOpt* choices; |
| GooString* editedChoice; |
| int topIdx; // TI |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormFieldSignature |
| //------------------------------------------------------------------------ |
| |
| class FormFieldSignature: public FormField { |
| friend class FormWidgetSignature; |
| public: |
| FormFieldSignature(PDFDoc *docA, Object &&dict, const Ref ref, FormField *parent, std::set<int> *usedParents); |
| |
| // Use -1 for now as validationTime |
| SignatureInfo *validateSignature(bool doVerifyCert, bool forceRevalidation, time_t validationTime); |
| |
| ~FormFieldSignature(); |
| Object* getByteRange() { return &byte_range; } |
| const GooString* getSignature() const { return signature; } |
| |
| private: |
| void parseInfo(); |
| void hashSignedDataBlock(SignatureHandler *handler, Goffset block_len); |
| |
| FormSignatureType signature_type; |
| Object byte_range; |
| GooString *signature; |
| SignatureInfo *signature_info; |
| |
| void print(int indent) override; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // Form |
| // This class handle the document-wide part of Form (things in the acroForm |
| // Catalog entry). |
| //------------------------------------------------------------------------ |
| |
| class Form { |
| public: |
| Form(PDFDoc *docA, Object* acroForm); |
| |
| ~Form(); |
| |
| Form(const Form &) = delete; |
| Form& operator=(const Form &) = delete; |
| |
| // Look up an inheritable field dictionary entry. |
| static Object fieldLookup(Dict *field, const char *key); |
| |
| /* Creates a new Field of the type specified in obj's dict. |
| used in Form::Form and FormField::FormField */ |
| static FormField *createFieldFromDict (Object &&obj, PDFDoc *docA, const Ref aref, FormField *parent, std::set<int> *usedParents); |
| |
| Object *getObj () const { return acroForm; } |
| bool getNeedAppearances () const { return needAppearances; } |
| int getNumFields() const { return numFields; } |
| FormField* getRootField(int i) const { return rootFields[i]; } |
| const GooString* getDefaultAppearance() const { return defaultAppearance; } |
| VariableTextQuadding getTextQuadding() const { return quadding; } |
| GfxResources* getDefaultResources() const { return defaultResources; } |
| Object* getDefaultResourcesObj() { return &resDict; } |
| |
| FormWidget* findWidgetByRef (Ref aref); |
| |
| void postWidgetsLoad(); |
| |
| const std::vector<Ref> &getCalculateOrder() const { return calculateOrder; } |
| |
| private: |
| FormField** rootFields; |
| int numFields; |
| int size; |
| PDFDoc *doc; |
| XRef* xref; |
| Object *acroForm; |
| bool needAppearances; |
| GfxResources *defaultResources; |
| Object resDict; |
| std::vector<Ref> calculateOrder; |
| |
| // Variable Text |
| GooString *defaultAppearance; |
| VariableTextQuadding quadding; |
| }; |
| |
| //------------------------------------------------------------------------ |
| // FormPageWidgets |
| //------------------------------------------------------------------------ |
| |
| class FormPageWidgets { |
| public: |
| FormPageWidgets (Annots* annots, unsigned int page, Form *form); |
| ~FormPageWidgets(); |
| |
| FormPageWidgets(const FormPageWidgets &) = delete; |
| FormPageWidgets& operator=(const FormPageWidgets &) = delete; |
| |
| int getNumWidgets() const { return numWidgets; } |
| FormWidget* getWidget(int i) const { return widgets[i]; } |
| |
| private: |
| FormWidget** widgets; |
| int numWidgets; |
| int size; |
| }; |
| |
| #endif |
| |