1 //========================================================================
2 //
3 // Form.cc
4 //
5 // This file is licensed under the GPLv2 or later
6 //
7 // Copyright 2006-2008 Julien Rebetez <julienr@svn.gnome.org>
8 // Copyright 2007-2010 Albert Astals Cid <aacid@kde.org>
9 // Copyright 2007-2008 Carlos Garcia Campos <carlosgc@gnome.org>
10 // Copyright 2007 Adrian Johnson <ajohnson@redneon.com>
11 // Copyright 2007 Iñigo Martínez <inigomartinez@gmail.com>
12 // Copyright 2008 Pino Toscano <pino@kde.org>
13 // Copyright 2008 Michael Vrable <mvrable@cs.ucsd.edu>
14 // Copyright 2009 Matthias Drochner <M.Drochner@fz-juelich.de>
15 // Copyright 2009 KDAB via Guillermo Amaral <gamaral@amaral.com.mx>
16 // Copyright 2010 Mark Riedesel <mark@klowner.com>
17 //
18 //========================================================================
19 
20 #include <config.h>
21 
22 #ifdef USE_GCC_PRAGMAS
23 #pragma implementation
24 #endif
25 
26 #include <set>
27 #include <stddef.h>
28 #include <string.h>
29 #include "goo/gmem.h"
30 #include "goo/GooString.h"
31 #include "Error.h"
32 #include "Object.h"
33 #include "Array.h"
34 #include "Dict.h"
35 #include "Form.h"
36 #include "XRef.h"
37 #include "PDFDocEncoding.h"
38 #include "Annot.h"
39 #include "Catalog.h"
40 
41 //return a newly allocated char* containing an UTF16BE string of size length
pdfDocEncodingToUTF16(GooString * orig,int * length)42 char* pdfDocEncodingToUTF16 (GooString* orig, int* length)
43 {
44   //double size, a unicode char takes 2 char, add 2 for the unicode marker
45   *length = 2+2*orig->getLength();
46   char *result = new char[(*length)];
47   char *cstring = orig->getCString();
48   //unicode marker
49   result[0] = 0xfe;
50   result[1] = 0xff;
51   //convert to utf16
52   for(int i=2,j=0; i<(*length); i+=2,j++) {
53     Unicode u = pdfDocEncoding[(unsigned int)((unsigned char)cstring[j])]&0xffff;
54     result[i] = (u >> 8) & 0xff;
55     result[i+1] = u & 0xff;
56   }
57   return result;
58 }
59 
60 
61 
FormWidget(XRef * xrefA,Object * aobj,unsigned num,Ref aref,FormField * fieldA)62 FormWidget::FormWidget(XRef *xrefA, Object *aobj, unsigned num, Ref aref, FormField *fieldA)
63 {
64   Object obj1, obj2;
65   ref = aref;
66   double t;
67   ID = 0;
68   defaultsLoaded = gFalse;
69   fontSize = 0.0;
70   modified = gFalse;
71   childNum = num;
72   xref = xrefA;
73   aobj->copy(&obj);
74   type = formUndef;
75   field = fieldA;
76   Dict *dict = obj.getDict();
77   fullyQualifiedName = NULL;
78 
79   if (dict->lookup("T", &obj1)->isString()) {
80     partialName = obj1.getString()->copy();
81   } else {
82     partialName = NULL;
83   }
84   obj1.free();
85 
86   if(dict->lookup("TM", &obj1)->isString()) {
87     mappingName = obj1.getString()->copy();
88   } else {
89     mappingName = NULL;
90   }
91   obj1.free();
92 
93   if (!dict->lookup("Rect", &obj1)->isArray()) {
94     error(-1, "Annotation rectangle is wrong type");
95     goto err2;
96   }
97   if (!obj1.arrayGet(0, &obj2)->isNum()) {
98     error(-1, "Bad annotation rectangle");
99     goto err1;
100   }
101   x1 = obj2.getNum();
102   obj2.free();
103   if (!obj1.arrayGet(1, &obj2)->isNum()) {
104     error(-1, "Bad annotation rectangle");
105     goto err1;
106   }
107   y1 = obj2.getNum();
108   obj2.free();
109   if (!obj1.arrayGet(2, &obj2)->isNum()) {
110     error(-1, "Bad annotation rectangle");
111     goto err1;
112   }
113   x2 = obj2.getNum();
114   obj2.free();
115   if (!obj1.arrayGet(3, &obj2)->isNum()) {
116     error(-1, "Bad annotation rectangle");
117     goto err1;
118   }
119   y2 = obj2.getNum();
120   obj2.free();
121   obj1.free();
122   //swap coords if needed
123   if (x1 > x2) {
124     t = x1;
125     x1 = x2;
126     x2 = t;
127   }
128   if (y1 > y2) {
129     t = y1;
130     y1 = y2;
131     y2 = t;
132   }
133 
134   err1:
135     obj2.free();
136   err2:
137     obj1.free();
138 }
139 
~FormWidget()140 FormWidget::~FormWidget()
141 {
142   delete partialName;
143   delete mappingName;
144   delete fullyQualifiedName;
145   obj.free ();
146 }
147 
isReadOnly() const148 bool FormWidget::isReadOnly() const
149 {
150   return field->isReadOnly();
151 }
152 
encodeID(unsigned pageNum,unsigned fieldNum)153 int FormWidget::encodeID (unsigned pageNum, unsigned fieldNum)
154 {
155   return (pageNum << 4*sizeof(unsigned)) + fieldNum;
156 }
157 
decodeID(unsigned id,unsigned * pageNum,unsigned * fieldNum)158 void FormWidget::decodeID (unsigned id, unsigned* pageNum, unsigned* fieldNum)
159 {
160   *pageNum = id >> 4*sizeof(unsigned);
161   *fieldNum = (id << 4*sizeof(unsigned)) >> 4*sizeof(unsigned);
162 }
163 
updateField(const char * key,Object * value)164 void FormWidget::updateField (const char *key, Object *value)
165 {
166   Object *obj1;
167   Ref ref1;
168   Object obj2;
169 
170   if (obj.getDict()->lookup ("FT", &obj2)->isName ()) {
171     // It's a composed (annot + field) dict
172     obj1 = &obj;
173     ref1 = ref;
174   } else {
175     // It's an annot dict, we have to modify the Field (parent) dict
176     obj1 = field->getObj ();
177     ref1 = field->getRef ();
178   }
179   obj2.free ();
180 
181   obj1->getDict ()->set (const_cast<char*>(key), value);
182   //notify the xref about the update
183   xref->setModifiedObject(obj1, ref1);
184 }
185 
getFullyQualifiedName()186 GooString* FormWidget::getFullyQualifiedName() {
187   Object obj1, obj2;
188   Object parent;
189   GooString *parent_name;
190   GooString *full_name;
191 
192   if (fullyQualifiedName)
193     return fullyQualifiedName;
194 
195   full_name = new GooString();
196 
197   obj.copy(&obj1);
198   while (obj1.dictLookup("Parent", &parent)->isDict()) {
199     if (parent.dictLookup("T", &obj2)->isString()) {
200       parent_name = obj2.getString();
201 
202       if (parent_name->hasUnicodeMarker()) {
203         parent_name->del(0, 2); // Remove the unicode BOM
204 	full_name->insert(0, "\0.", 2); // 2-byte unicode period
205       } else {
206         full_name->insert(0, '.'); // 1-byte ascii period
207       }
208 
209       full_name->insert(0, parent_name);
210       obj2.free();
211     }
212     obj1.free();
213     parent.copy(&obj1);
214     parent.free();
215   }
216   obj1.free();
217   parent.free();
218 
219   if (partialName) {
220     full_name->append(partialName);
221   } else {
222     int len = full_name->getLength();
223     // Remove the last period
224     if (len > 0)
225       full_name->del(len - 1, 1);
226   }
227 
228   fullyQualifiedName = full_name;
229   return fullyQualifiedName;
230 }
231 
FormWidgetButton(XRef * xrefA,Object * aobj,unsigned num,Ref ref,FormField * p)232 FormWidgetButton::FormWidgetButton (XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
233 	FormWidget(xrefA, aobj, num, ref, p)
234 {
235   type = formButton;
236   parent = static_cast<FormFieldButton*>(field);
237   onStr = NULL;
238   state = gFalse;
239   siblingsID = NULL;
240   numSiblingsID = 0;
241 }
242 
~FormWidgetButton()243 FormWidgetButton::~FormWidgetButton ()
244 {
245   if (siblingsID)
246     gfree(siblingsID);
247   delete onStr;
248 }
249 
getButtonType() const250 FormButtonType FormWidgetButton::getButtonType () const
251 {
252   return parent->getButtonType ();
253 }
254 
setState(GBool astate,GBool calledByParent)255 void FormWidgetButton::setState (GBool astate, GBool calledByParent)
256 {
257   //pushButtons don't have state
258   if (parent->getButtonType() == formButtonPush)
259     return;
260   //the state modification may be denied by the parent. e.g we don't want to let the user put all combo boxes to false
261   if (!calledByParent) { //avoid infinite recursion
262     modified = gTrue;
263     if (!parent->setState(childNum, astate)) {
264       return;
265     }
266   }
267   state = astate;
268 
269   //update appearance
270   char *offStr = "Off";
271   Object obj1;
272   obj1.initName(state?getOnStr():offStr);
273   updateField ("V", &obj1);
274 
275   obj1.initName(state?getOnStr():offStr);
276   //modify the Appearance State entry as well
277   obj.getDict()->set("AS", &obj1);
278   //notify the xref about the update
279   xref->setModifiedObject(&obj, ref);
280 }
281 
loadDefaults()282 void FormWidgetButton::loadDefaults ()
283 {
284   if (defaultsLoaded)
285     return;
286 
287   defaultsLoaded = gTrue;
288 
289   Dict *dict = obj.getDict();
290   Object obj1;
291 
292   //pushButtons don't have state
293   if (parent->getButtonType() != formButtonPush ){
294     //find the name of the state in the AP dictionnary (/Yes, /Off)
295     //The reference say the Off state, if it existe, _must_ be stored in the AP dict under the name /Off
296     //The "on" state may be stored under any other name
297     if (dict->lookup("AP", &obj1)->isDict()) {
298       Dict *tmpDict = obj1.getDict();
299       int length = tmpDict->getLength();
300       for(int i=0; i<length; i++) {
301         Object obj2;
302         tmpDict->getVal(i, &obj2);
303         if (obj2.isDict()) {
304           Dict *tmpDict2 = obj2.getDict();
305           int length2 = tmpDict2->getLength();
306           for(int j=0; j<length2; j++) {
307             Object obj3;
308             tmpDict2->getVal(j, &obj3);
309             char *key = tmpDict2->getKey(j);
310             if(strcmp(key, "Off")) { //if we don't have Off, we have the name of the "on" state
311 	      onStr = new GooString (key);
312             }
313             obj3.free();
314 	    if (onStr)
315 	      break;
316           }
317         } else if (obj2.isStream()) {
318           // TODO do something with str and obj3
319           Stream *str = obj2.getStream();
320           Dict *tmpDict2 = str->getDict();
321           Object obj3;
322           tmpDict2->lookup("Length", &obj3);
323           onStr = new GooString ("D");
324           obj3.free();
325         }
326         obj2.free();
327 	if (onStr)
328 	  break;
329       }
330     }
331     obj1.free();
332 
333     //We didn't found the "on" state for the button
334     if (!onStr) {
335       error(-1, "FormWidgetButton:: unable to find the on state for the button\n");
336       onStr = new GooString(""); // TODO is this the best solution?
337     }
338   }
339 
340   if (Form::fieldLookup(dict, "V", &obj1)->isName()) {
341     Object obj2;
342     if (dict->lookup("AS", &obj2)->isName(obj1.getName())) {
343       if (strcmp (obj1.getName(), "Off") != 0) {
344         setState(gTrue);
345       }
346     }
347     obj2.free();
348   } else if (obj1.isArray()) { //handle the case where we have multiple choices
349     error(-1, "FormWidgetButton:: multiple choice isn't supported yet\n");
350   }
351   obj1.free();
352 }
353 
getState()354 GBool FormWidgetButton::getState ()
355 {
356   return state;
357 }
358 
setNumSiblingsID(int i)359 void FormWidgetButton::setNumSiblingsID (int i)
360 {
361   numSiblingsID = i;
362   siblingsID = (unsigned*)greallocn(siblingsID, numSiblingsID, sizeof(unsigned));
363 }
364 
365 
FormWidgetText(XRef * xrefA,Object * aobj,unsigned num,Ref ref,FormField * p)366 FormWidgetText::FormWidgetText (XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
367 	FormWidget(xrefA, aobj, num, ref, p)
368 {
369   type = formText;
370   parent = static_cast<FormFieldText*>(field);
371 }
372 
loadDefaults()373 void FormWidgetText::loadDefaults ()
374 {
375   if (defaultsLoaded)
376     return;
377 
378   defaultsLoaded = gTrue;
379 
380   Dict *dict = obj.getDict();
381   Object obj1;
382 
383   if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
384     if (obj1.getString()->hasUnicodeMarker()) {
385       if (obj1.getString()->getLength() <= 2) {
386       } else {
387         parent->setContentCopy(obj1.getString());
388       }
389     } else {
390       if (obj1.getString()->getLength() > 0) {
391         //non-unicode string -- assume pdfDocEncoding and try to convert to UTF16BE
392         int tmp_length;
393         char* tmp_str = pdfDocEncodingToUTF16(obj1.getString(), &tmp_length);
394         GooString* str1 = new GooString(tmp_str, tmp_length);
395         parent->setContentCopy(str1);
396         delete str1;
397 	delete []tmp_str;
398       }
399     }
400   }
401   obj1.free();
402 
403 }
404 
getContent()405 GooString* FormWidgetText::getContent ()
406 {
407   return parent->getContent();
408 }
409 
getContentCopy()410 GooString* FormWidgetText::getContentCopy ()
411 {
412   return parent->getContentCopy();
413 }
414 
isMultiline() const415 bool FormWidgetText::isMultiline () const
416 {
417   return parent->isMultiline();
418 }
419 
isPassword() const420 bool FormWidgetText::isPassword () const
421 {
422   return parent->isPassword();
423 }
424 
isFileSelect() const425 bool FormWidgetText::isFileSelect () const
426 {
427   return parent->isFileSelect();
428 }
429 
noSpellCheck() const430 bool FormWidgetText::noSpellCheck () const
431 {
432   return parent->noSpellCheck();
433 }
434 
noScroll() const435 bool FormWidgetText::noScroll () const
436 {
437   return parent->noScroll();
438 }
439 
isComb() const440 bool FormWidgetText::isComb () const
441 {
442   return parent->isComb();
443 }
444 
isRichText() const445 bool FormWidgetText::isRichText () const
446 {
447   return parent->isRichText();
448 }
449 
getMaxLen() const450 int FormWidgetText::getMaxLen () const
451 {
452   return parent->getMaxLen ();
453 }
454 
setContent(GooString * new_content)455 void FormWidgetText::setContent(GooString* new_content)
456 {
457   if (isReadOnly()) {
458     error(-1, "FormWidgetText::setContentCopy called on a read only field\n");
459     return;
460   }
461 
462   modified = gTrue;
463   if (new_content == NULL) {
464     parent->setContentCopy(NULL);
465   } else {
466     //append the unicode marker <FE FF> if needed
467     if (!new_content->hasUnicodeMarker()) {
468       new_content->insert(0, 0xff);
469       new_content->insert(0, 0xfe);
470     }
471 
472     GooString *cont = new GooString(new_content);
473     parent->setContentCopy(cont);
474 
475     Object obj1;
476     obj1.initString(cont);
477     updateField ("V", &obj1);
478   }
479 }
480 
FormWidgetChoice(XRef * xrefA,Object * aobj,unsigned num,Ref ref,FormField * p)481 FormWidgetChoice::FormWidgetChoice(XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
482 	FormWidget(xrefA, aobj, num, ref, p)
483 {
484   type = formChoice;
485   parent = static_cast<FormFieldChoice*>(field);
486 }
487 
loadDefaults()488 void FormWidgetChoice::loadDefaults ()
489 {
490   if (defaultsLoaded)
491     return;
492 
493   defaultsLoaded = gTrue;
494 
495   Dict *dict = obj.getDict();
496   Object obj1;
497   if (dict->lookup("Opt", &obj1)->isArray()) {
498     Object obj2;
499     parent->_setNumChoices(obj1.arrayGetLength());
500     parent->_createChoicesTab();
501     for(int i=0; i<parent->getNumChoices(); i++) {
502       obj1.arrayGet(i, &obj2);
503       if(obj2.isString()) {
504         parent->_setChoiceExportVal(i, obj2.getString()->copy());
505         parent->_setChoiceOptionName(i, obj2.getString()->copy());
506       } else if (obj2.isArray()) { // [Export_value, Displayed_text]
507         Object obj3,obj4;
508         if (obj2.arrayGetLength() < 2) {
509           error(-1, "FormWidgetChoice:: invalid Opt entry -- array's length < 2\n");
510           parent->_setChoiceExportVal(i, new GooString(""));
511           parent->_setChoiceOptionName(i, new GooString(""));
512           continue;
513         }
514         obj2.arrayGet(0, &obj3);
515         obj2.arrayGet(1, &obj4);
516         parent->_setChoiceExportVal(i, obj3.getString()->copy());
517         parent->_setChoiceOptionName(i, obj4.getString()->copy());
518         obj3.free();
519         obj4.free();
520       } else {
521         error(-1, "FormWidgetChoice:: invalid %d Opt entry\n", i);
522         parent->_setChoiceExportVal(i, new GooString(""));
523         parent->_setChoiceOptionName(i, new GooString(""));
524       }
525       obj2.free();
526     }
527   } else {
528     //empty choice
529   }
530   obj1.free();
531 
532   bool* tmpCurrentChoice = new bool[parent->getNumChoices()];
533   memset(tmpCurrentChoice, 0, sizeof(bool)*parent->getNumChoices());
534 
535   //find default choice
536   if (Form::fieldLookup(dict, "V", &obj1)->isString()) {
537     for(int i=0; i<parent->getNumChoices(); i++) {
538       if (parent->getChoice(i)->cmp(obj1.getString()) == 0) {
539         tmpCurrentChoice[i] = true;
540         break;
541       }
542     }
543   } else if (obj1.isArray()) {
544     for(int i=0; i<obj1.arrayGetLength(); i++) {
545       Object obj2;
546       obj1.arrayGet(i, &obj2);
547       for(int j=0; j<parent->getNumChoices(); j++) {
548         if (parent->getChoice(j)->cmp(obj2.getString()) == 0) {
549           tmpCurrentChoice[i] = true;
550         }
551       }
552 
553       obj2.free();
554     }
555   }
556   obj1.free();
557 
558   //convert choice's human readable strings to UTF16
559   //and update the /Opt dict entry to reflect this change
560 #ifdef UPDATE_OPT
561   Object *objOpt = new Object();
562   objOpt->initArray(xref);
563 #endif
564   for(int i=0; i<parent->getNumChoices(); i++) {
565         if (parent->getChoice(i)->hasUnicodeMarker()) { //string already in UTF16, do nothing
566 
567         } else { //string in pdfdocencoding, convert to UTF16
568           int len;
569           char* buffer = pdfDocEncodingToUTF16(parent->getChoice(i), &len);
570           parent->getChoice(i)->Set(buffer, len);
571           delete [] buffer;
572         }
573         #ifdef UPDATE_OPT
574         Object *obj2 = new Object();
575         obj2->initString(choices[i]);
576         objOpt->getArray()->add(obj2);
577         #endif
578   }
579   //set default choice now that we have UTF16 strings
580   for (int i=0; i<parent->getNumChoices(); i++) {
581     if (tmpCurrentChoice[i])
582       parent->select(i);
583   }
584 #ifdef UPDATE_OPT
585   updateField ("Opt", objOpt);
586 #endif
587   delete [] tmpCurrentChoice;
588 }
589 
~FormWidgetChoice()590 FormWidgetChoice::~FormWidgetChoice()
591 {
592 }
593 
_updateV()594 void FormWidgetChoice::_updateV ()
595 {
596   Object obj1;
597   //this is an editable combo-box with user-entered text
598   if (hasEdit() && parent->getEditChoice()) {
599     obj1.initString(new GooString(parent->getEditChoice()));
600   } else {
601     int numSelected = parent->getNumSelected();
602     if (numSelected == 0) {
603       obj1.initString(new GooString(""));
604     } else if (numSelected == 1) {
605       for(int i=0; i<parent->getNumChoices(); i++) {
606         if (parent->isSelected(i)) {
607           obj1.initString(new GooString(parent->getChoice(i)));
608           break;
609         }
610       }
611     } else {
612       obj1.initArray(xref);
613       for(int i=0; i<parent->getNumChoices(); i++) {
614         if (parent->isSelected(i)) {
615           Object obj2;
616           obj2.initString(new GooString(parent->getChoice(i)));
617           obj1.arrayAdd(&obj2);
618         }
619       }
620     }
621   }
622   updateField ("V", &obj1);
623   modified = gTrue;
624 }
625 
_checkRange(int i)626 bool FormWidgetChoice::_checkRange (int i)
627 {
628   if (i < 0 || i >= parent->getNumChoices()) {
629     error(-1, "FormWidgetChoice::_checkRange i out of range : %i", i);
630     return false;
631   }
632   return true;
633 }
634 
select(int i)635 void FormWidgetChoice::select (int i)
636 {
637   if (isReadOnly()) {
638     error(-1, "FormWidgetChoice::select called on a read only field\n");
639     return;
640   }
641   if (!_checkRange(i)) return;
642   modified = gTrue;
643   parent->select(i);
644   _updateV();
645 }
646 
toggle(int i)647 void FormWidgetChoice::toggle (int i)
648 {
649   if (isReadOnly()) {
650     error(-1, "FormWidgetChoice::toggle called on a read only field\n");
651     return;
652   }
653   if (!_checkRange(i)) return;
654   modified = gTrue;
655   parent->toggle(i);
656   _updateV();
657 }
658 
deselectAll()659 void FormWidgetChoice::deselectAll ()
660 {
661   if (isReadOnly()) {
662     error(-1, "FormWidgetChoice::deselectAll called on a read only field\n");
663     return;
664   }
665   modified = gTrue;
666   parent->deselectAll();
667   _updateV();
668 }
669 
getEditChoice()670 GooString* FormWidgetChoice::getEditChoice ()
671 {
672   if (!hasEdit()) {
673     error(-1, "FormFieldChoice::getEditChoice called on a non-editable choice\n");
674     return NULL;
675   }
676   return parent->getEditChoice();
677 }
678 
isSelected(int i)679 bool FormWidgetChoice::isSelected (int i)
680 {
681   if (!_checkRange(i)) return false;
682   return parent->isSelected(i);
683 }
684 
setEditChoice(GooString * new_content)685 void FormWidgetChoice::setEditChoice (GooString* new_content)
686 {
687   if (isReadOnly()) {
688     error(-1, "FormWidgetText::setEditChoice called on a read only field\n");
689     return;
690   }
691   if (!hasEdit()) {
692     error(-1, "FormFieldChoice::setEditChoice : trying to edit an non-editable choice\n");
693     return;
694   }
695 
696   modified = gTrue;
697   if (new_content == NULL) {
698     parent->setEditChoice(NULL);
699   } else {
700     //append the unicode marker <FE FF> if needed
701     if (!new_content->hasUnicodeMarker()) {
702       new_content->insert(0, 0xff);
703       new_content->insert(0, 0xfe);
704     }
705     parent->setEditChoice(new_content);
706   }
707   _updateV();
708 }
709 
getNumChoices()710 int FormWidgetChoice::getNumChoices()
711 {
712   return parent->getNumChoices();
713 }
714 
getChoice(int i)715 GooString* FormWidgetChoice::getChoice(int i)
716 {
717   return parent->getChoice(i);
718 }
719 
isCombo() const720 bool FormWidgetChoice::isCombo () const
721 {
722   return parent->isCombo();
723 }
724 
hasEdit() const725 bool FormWidgetChoice::hasEdit () const
726 {
727   return parent->hasEdit();
728 }
729 
isMultiSelect() const730 bool FormWidgetChoice::isMultiSelect () const
731 {
732   return parent->isMultiSelect();
733 }
734 
noSpellCheck() const735 bool FormWidgetChoice::noSpellCheck () const
736 {
737   return parent->noSpellCheck();
738 }
739 
commitOnSelChange() const740 bool FormWidgetChoice::commitOnSelChange () const
741 {
742   return parent->commitOnSelChange();
743 }
744 
isListBox() const745 bool FormWidgetChoice::isListBox () const
746 {
747   return parent->isListBox();
748 }
749 
FormWidgetSignature(XRef * xrefA,Object * aobj,unsigned num,Ref ref,FormField * p)750 FormWidgetSignature::FormWidgetSignature(XRef *xrefA, Object *aobj, unsigned num, Ref ref, FormField *p) :
751 	FormWidget(xrefA, aobj, num, ref, p)
752 {
753   type = formSignature;
754   parent = static_cast<FormFieldSignature*>(field);
755 }
756 
757 
758 //========================================================================
759 // FormField
760 //========================================================================
761 
FormField(XRef * xrefA,Object * aobj,const Ref & aref,std::set<int> * usedParents,FormFieldType ty)762 FormField::FormField(XRef* xrefA, Object *aobj, const Ref& aref, std::set<int> *usedParents, FormFieldType ty)
763 {
764   xref = xrefA;
765   aobj->copy(&obj);
766   Dict* dict = obj.getDict();
767   ref.num = ref.gen = 0;
768   type = ty;
769   numChildren = 0;
770   children = NULL;
771   terminal = false;
772   widgets = NULL;
773   readOnly = false;
774   ref = aref;
775 
776   Object obj1;
777   //childs
778   if (dict->lookup("Kids", &obj1)->isArray()) {
779     Array *array = obj1.getArray();
780     int length = array->getLength();
781     // Load children
782     for(int i=0; i<length; i++) {
783       Object obj2,obj3;
784       array->get(i, &obj2);
785       if (!obj2.isDict ()) {
786 	      error (-1, "Reference to an invalid or non existant object");
787 	      obj2.free();
788 	      continue;
789       }
790       Object childRef;
791       array->getNF(i, &childRef);
792       if (childRef.isRef()) {
793         const Ref ref = childRef.getRef();
794         if (usedParents->find(ref.num) == usedParents->end()) {
795           //field child
796           if (dict->lookup ("FT", &obj3)->isName()) {
797             // If I'm not a generic container field and my children
798             // are widgets, create widgets for them
799             Object obj4;
800 
801             if (obj2.dictLookup("Subtype",&obj4)->isName()) {
802               _createWidget(&obj2, childRef.getRef());
803             }
804             obj4.free();
805           } else if(obj2.dictLookup("FT", &obj3)->isName() || obj2.dictLookup("Kids", &obj3)->isArray()) {
806             std::set<int> usedParentsAux = *usedParents;
807             usedParentsAux.insert(ref.num);
808             if(terminal) error(-1, "Field can't have both Widget AND Field as kids\n");
809 
810             numChildren++;
811             children = (FormField**)greallocn(children, numChildren, sizeof(FormField*));
812 
813             obj3.free();
814             children[numChildren-1] = Form::createFieldFromDict (&obj2, xrefA, childRef.getRef(), &usedParentsAux);
815           }
816           // 1 - we will handle 'collapsed' fields (field + annot in the same dict)
817           // as if the annot was in the Kids array of the field
818           else if (obj2.dictLookup("Subtype",&obj3)->isName()) {
819             _createWidget(&obj2, childRef.getRef());
820           }
821           obj3.free();
822         } else {
823           error(-1, "Found loop in FormField creation");
824         }
825       } else {
826         error(-1, "FormField child is not a Ref as expected");
827       }
828       obj2.free();
829     }
830   }
831   obj1.free();
832   // As said in 1, if this is a 'collapsed' field, behave like if we had a
833   // child annot
834   if (dict->lookup("Subtype", &obj1)->isName()) {
835     _createWidget(aobj, ref);
836   }
837   obj1.free();
838 
839   //flags
840   if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
841     int flags = obj1.getInt();
842     if (flags & 0x1) { // 1 -> ReadOnly
843       readOnly = true;
844     }
845     if (flags & 0x2) { // 2 -> Required
846       //TODO
847     }
848     if (flags & 0x4) { // 3 -> NoExport
849       //TODO
850     }
851   }
852   obj1.free();
853 }
854 
~FormField()855 FormField::~FormField()
856 {
857   if (!terminal) {
858     if(children) {
859       for (int i=0; i<numChildren; i++)
860         delete children[i];
861       gfree(children);
862     }
863   } else {
864     for (int i = 0; i < numChildren; ++i)
865       delete widgets[i];
866     gfree (widgets);
867   }
868   obj.free();
869 }
870 
loadChildrenDefaults()871 void FormField::loadChildrenDefaults ()
872 {
873   if(!terminal) {
874     for(int i=0; i<numChildren; i++) {
875       children[i]->loadChildrenDefaults();
876     }
877   } else {
878     for (int i=0; i<numChildren; i++) {
879       widgets[i]->loadDefaults();
880     }
881   }
882 }
883 
fillChildrenSiblingsID()884 void FormField::fillChildrenSiblingsID()
885 {
886   if(terminal) return;
887   for (int i=0; i<numChildren; i++) {
888     children[i]->fillChildrenSiblingsID();
889   }
890 }
891 
892 
_createWidget(Object * obj,Ref aref)893 void FormField::_createWidget (Object *obj, Ref aref)
894 {
895   terminal = true;
896   numChildren++;
897   widgets = (FormWidget**)greallocn(widgets, numChildren, sizeof(FormWidget*));
898   //ID = index in "widgets" table
899   switch (type) {
900   case formButton:
901     widgets[numChildren-1] = new FormWidgetButton(xref, obj, numChildren-1, aref, this);
902     break;
903   case formText:
904     widgets[numChildren-1] = new FormWidgetText(xref, obj, numChildren-1, aref, this);
905     break;
906   case formChoice:
907     widgets[numChildren-1] = new FormWidgetChoice(xref, obj, numChildren-1, aref, this);
908     break;
909   case formSignature:
910     widgets[numChildren-1] = new FormWidgetSignature(xref, obj, numChildren-1, aref, this);
911     break;
912   default:
913     error(-1, "SubType on non-terminal field, invalid document?");
914     numChildren--;
915     terminal = false;
916   }
917 }
918 
findWidgetByRef(Ref aref)919 FormWidget* FormField::findWidgetByRef (Ref aref)
920 {
921   if (terminal) {
922     for(int i=0; i<numChildren; i++) {
923       if (widgets[i]->getRef().num == aref.num
924           && widgets[i]->getRef().gen == aref.gen)
925         return widgets[i];
926     }
927   } else {
928     for(int i=0; i<numChildren; i++) {
929       FormWidget* result = children[i]->findWidgetByRef(aref);
930       if(result) return result;
931     }
932   }
933   return NULL;
934 }
935 
936 
937 //------------------------------------------------------------------------
938 // FormFieldButton
939 //------------------------------------------------------------------------
FormFieldButton(XRef * xrefA,Object * aobj,const Ref & ref,std::set<int> * usedParents)940 FormFieldButton::FormFieldButton(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents)
941 	: FormField(xrefA, aobj, ref, usedParents, formButton)
942 {
943   Dict* dict = obj.getDict();
944   active_child = -1;
945   noAllOff = false;
946 
947   Object obj1;
948   btype = formButtonCheck;
949   if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
950     int flags = obj1.getInt();
951 
952     if (flags & 0x10000) { // 17 -> push button
953       btype = formButtonPush;
954     } else if (flags & 0x8000) { // 16 -> radio button
955       btype = formButtonRadio;
956       if (flags & 0x4000) { // 15 -> noToggleToOff
957         noAllOff = true;
958       }
959     }
960     if (flags & 0x1000000) { // 26 -> radiosInUnison
961       error(-1, "FormFieldButton:: radiosInUnison flag unimplemented, please report a bug with a testcase\n");
962     }
963   }
964 }
965 
fillChildrenSiblingsID()966 void FormFieldButton::fillChildrenSiblingsID()
967 {
968   if (!terminal) {
969     for(int i=0; i<numChildren; i++) {
970       children[i]->fillChildrenSiblingsID();
971     }
972   } else {
973     for(int i=0; i<numChildren; i++) {
974       FormWidgetButton *btn = static_cast<FormWidgetButton*>(widgets[i]);
975       btn->setNumSiblingsID(numChildren-1);
976       for(int j=0, counter=0; j<numChildren; j++) {
977         if (i == j) continue;
978         btn->setSiblingsID(counter, widgets[j]->getID());
979         counter++;
980       }
981     }
982   }
983 }
984 
setState(int num,GBool s)985 GBool FormFieldButton::setState (int num, GBool s)
986 {
987   if (readOnly) {
988     error(-1, "FormFieldButton::setState called on a readOnly field\n");
989     return gFalse;
990   }
991 
992   // A check button could behave as a radio button
993   // when it's in a set of more than 1 buttons
994   if (btype == formButtonRadio || btype == formButtonCheck) {
995     if (!s && noAllOff)
996       return gFalse; //don't allow to set all radio to off
997 
998     if (s == gTrue) {
999       active_child = num;
1000       for(int i=0; i<numChildren; i++) {
1001         if (i==active_child) continue;
1002         static_cast<FormWidgetButton*>(widgets[i])->setState(gFalse, gTrue);
1003       }
1004 
1005       //The parent field's V entry holds a name object corresponding to the ap-
1006       //pearance state of whichever child field is currently in the on state
1007       if (active_child >= 0) {
1008         FormWidgetButton* actChild = static_cast<FormWidgetButton*>(widgets[active_child]);
1009         if (actChild->getOnStr()) {
1010           Object obj1;
1011           obj1.initName(actChild->getOnStr());
1012 	  obj.getDict()->set("V", &obj1);
1013 	  xref->setModifiedObject(&obj, ref);
1014         }
1015       }
1016     } else {
1017       active_child = -1;
1018       Object obj1;
1019       obj1.initName("Off");
1020       obj.getDict()->set("V", &obj1);
1021       xref->setModifiedObject(&obj, ref);
1022     }
1023   }
1024   return gTrue;
1025 }
1026 
~FormFieldButton()1027 FormFieldButton::~FormFieldButton()
1028 {
1029 }
1030 
1031 //------------------------------------------------------------------------
1032 // FormFieldText
1033 //------------------------------------------------------------------------
FormFieldText(XRef * xrefA,Object * aobj,const Ref & ref,std::set<int> * usedParents)1034 FormFieldText::FormFieldText(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents)
1035 	: FormField(xrefA, aobj, ref, usedParents, formText)
1036 {
1037   Dict* dict = obj.getDict();
1038   Object obj1;
1039   content = NULL;
1040   multiline = password = fileSelect = doNotSpellCheck = doNotScroll = comb = richText = false;
1041   maxLen = 0;
1042 
1043   if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
1044     int flags = obj1.getInt();
1045     if (flags & 0x1000) // 13 -> Multiline
1046       multiline = true;
1047     if (flags & 0x2000) // 14 -> Password
1048       password = true;
1049     if (flags & 0x100000) // 21 -> FileSelect
1050       fileSelect = true;
1051     if (flags & 0x400000)// 23 -> DoNotSpellCheck
1052       doNotSpellCheck = true;
1053     if (flags & 0x800000) // 24 -> DoNotScroll
1054       doNotScroll = true;
1055     if (flags & 0x1000000) // 25 -> Comb
1056       comb = true;
1057     if (flags & 0x2000000)// 26 -> RichText
1058       richText = true;
1059   }
1060   obj1.free();
1061 
1062   if (Form::fieldLookup(dict, "MaxLen", &obj1)->isInt()) {
1063     maxLen = obj1.getInt();
1064   }
1065   obj1.free();
1066 }
1067 
getContentCopy()1068 GooString* FormFieldText::getContentCopy ()
1069 {
1070   if (!content) return NULL;
1071   return new GooString(content);
1072 }
1073 
setContentCopy(GooString * new_content)1074 void FormFieldText::setContentCopy (GooString* new_content)
1075 {
1076   if(content) {
1077     delete content;
1078   }
1079   content = new_content->copy();
1080 }
1081 
~FormFieldText()1082 FormFieldText::~FormFieldText()
1083 {
1084   delete content;
1085 }
1086 
1087 
1088 //------------------------------------------------------------------------
1089 // FormFieldChoice
1090 //------------------------------------------------------------------------
FormFieldChoice(XRef * xrefA,Object * aobj,const Ref & ref,std::set<int> * usedParents)1091 FormFieldChoice::FormFieldChoice(XRef *xrefA, Object *aobj, const Ref& ref, std::set<int> *usedParents)
1092 	: FormField(xrefA, aobj, ref, usedParents, formChoice)
1093 {
1094   numChoices = 0;
1095   choices = NULL;
1096   editedChoice = NULL;
1097 
1098   Dict* dict = obj.getDict();
1099   Object obj1;
1100 
1101   combo = edit = multiselect = doNotSpellCheck = doCommitOnSelChange = false;
1102 
1103   if (Form::fieldLookup(dict, "Ff", &obj1)->isInt()) {
1104     int flags = obj1.getInt();
1105     if (flags & 0x20000) // 18 -> Combo
1106       combo = true;
1107     if (flags & 0x40000) // 19 -> Edit
1108       edit = true;
1109     if (flags & 0x200000) // 22 -> MultiSelect
1110       multiselect = true;
1111     if (flags & 0x400000) // 23 -> DoNotSpellCheck
1112       doNotSpellCheck = true;
1113     if (flags & 0x4000000) // 27 -> CommitOnSelChange
1114       doCommitOnSelChange = true;
1115   }
1116   obj1.free();
1117 
1118 }
1119 
~FormFieldChoice()1120 FormFieldChoice::~FormFieldChoice()
1121 {
1122   for (int i=0; i<numChoices; i++) {
1123     delete choices[i].exportVal;
1124     delete choices[i].optionName;
1125   }
1126   delete [] choices;
1127   delete editedChoice;
1128 }
1129 
deselectAll()1130 void FormFieldChoice::deselectAll ()
1131 {
1132   for(int i=0; i<numChoices; i++) {
1133     choices[i].selected = false;
1134   }
1135 }
1136 
toggle(int i)1137 void FormFieldChoice::toggle (int i)
1138 {
1139   choices[i].selected = !choices[i].selected;
1140 }
1141 
select(int i)1142 void FormFieldChoice::select (int i)
1143 {
1144   if (!multiselect)
1145     deselectAll();
1146   choices[i].selected = true;
1147 }
1148 
setEditChoice(GooString * new_content)1149 void FormFieldChoice::setEditChoice (GooString* new_content)
1150 {
1151   if (editedChoice)
1152     delete editedChoice;
1153 
1154   deselectAll();
1155 
1156   editedChoice = new_content->copy();
1157 }
1158 
getEditChoice()1159 GooString* FormFieldChoice::getEditChoice ()
1160 {
1161   return editedChoice;
1162 }
1163 
getNumSelected()1164 int FormFieldChoice::getNumSelected ()
1165 {
1166   int cnt = 0;
1167   for(int i=0; i<numChoices; i++) {
1168     if (choices[i].selected)
1169       cnt++;
1170   }
1171   return cnt;
1172 }
1173 
_createChoicesTab()1174 void FormFieldChoice::_createChoicesTab ()
1175 {
1176   choices = new ChoiceOpt[numChoices];
1177   for(int i=0; i<numChoices; i++) {
1178     choices[i].selected = false;
1179   }
1180 }
1181 
1182 //------------------------------------------------------------------------
1183 // FormFieldSignature
1184 //------------------------------------------------------------------------
FormFieldSignature(XRef * xrefA,Object * dict,const Ref & ref,std::set<int> * usedParents)1185 FormFieldSignature::FormFieldSignature(XRef *xrefA, Object *dict, const Ref& ref, std::set<int> *usedParents)
1186 	: FormField(xrefA, dict, ref, usedParents, formSignature)
1187 {
1188 }
1189 
~FormFieldSignature()1190 FormFieldSignature::~FormFieldSignature()
1191 {
1192 
1193 }
1194 
1195 //------------------------------------------------------------------------
1196 // Form
1197 //------------------------------------------------------------------------
1198 
Form(XRef * xrefA,Object * acroFormA)1199 Form::Form(XRef *xrefA, Object* acroFormA)
1200 {
1201   Object obj1;
1202 
1203   xref = xrefA;
1204   acroForm = acroFormA;
1205 
1206   size = 0;
1207   numFields = 0;
1208   rootFields = NULL;
1209 
1210   acroForm->dictLookup("NeedAppearances", &obj1);
1211   needAppearances = (obj1.isBool() && obj1.getBool());
1212   obj1.free();
1213 
1214   acroForm->dictLookup("Fields", &obj1);
1215   if (obj1.isArray()) {
1216     Array *array = obj1.getArray();
1217     Object obj2;
1218 
1219     for(int i=0; i<array->getLength(); i++) {
1220       Object oref;
1221       array->get(i, &obj2);
1222       array->getNF(i, &oref);
1223       if (!oref.isRef()) {
1224         error(-1, "Direct object in rootFields");
1225 	obj2.free();
1226 	oref.free();
1227         continue;
1228       }
1229 
1230       if (!obj2.isDict()) {
1231         error(-1, "Reference in Fields array to an invalid or non existant object");
1232 	obj2.free();
1233 	oref.free();
1234 	continue;
1235       }
1236 
1237       if (numFields >= size) {
1238         size += 16;
1239         rootFields = (FormField**)greallocn(rootFields,size,sizeof(FormField*));
1240       }
1241 
1242       std::set<int> usedParents;
1243       rootFields[numFields++] = createFieldFromDict (&obj2, xrefA, oref.getRef(), &usedParents);
1244 
1245       obj2.free();
1246       oref.free();
1247     }
1248   } else {
1249     error(-1, "Can't get Fields array\n");
1250   }
1251   obj1.free ();
1252 }
1253 
~Form()1254 Form::~Form() {
1255   int i;
1256   for(i = 0; i< numFields; ++i)
1257     delete rootFields[i];
1258   gfree (rootFields);
1259 }
1260 
1261 // Look up an inheritable field dictionary entry.
fieldLookup(Dict * field,char * key,Object * obj,std::set<int> * usedParents)1262 static Object *fieldLookup(Dict *field, char *key, Object *obj, std::set<int> *usedParents) {
1263   Dict *dict;
1264   Object parent;
1265 
1266   dict = field;
1267   if (!dict->lookup(key, obj)->isNull()) {
1268     return obj;
1269   }
1270   obj->free();
1271   dict->lookupNF("Parent", &parent);
1272   if (parent.isRef()) {
1273     const Ref ref = parent.getRef();
1274     if (usedParents->find(ref.num) == usedParents->end()) {
1275       usedParents->insert(ref.num);
1276 
1277       Object obj2;
1278       parent.fetch(dict->getXRef(), &obj2);
1279       if (obj2.isDict()) {
1280         fieldLookup(obj2.getDict(), key, obj, usedParents);
1281       } else {
1282         obj->initNull();
1283       }
1284       obj2.free();
1285     }
1286   } else if (parent.isDict()) {
1287     fieldLookup(parent.getDict(), key, obj, usedParents);
1288   } else {
1289     obj->initNull();
1290   }
1291   parent.free();
1292   return obj;
1293 }
1294 
fieldLookup(Dict * field,char * key,Object * obj)1295 Object *Form::fieldLookup(Dict *field, char *key, Object *obj) {
1296   std::set<int> usedParents;
1297   return ::fieldLookup(field, key, obj, &usedParents);
1298 }
1299 
createFieldFromDict(Object * obj,XRef * xrefA,const Ref & pref,std::set<int> * usedParents)1300 FormField *Form::createFieldFromDict (Object* obj, XRef *xrefA, const Ref& pref, std::set<int> *usedParents)
1301 {
1302     Object obj2;
1303     FormField *field;
1304 
1305     if (Form::fieldLookup(obj->getDict (), "FT", &obj2)->isName("Btn")) {
1306       field = new FormFieldButton(xrefA, obj, pref, usedParents);
1307     } else if (obj2.isName("Tx")) {
1308       field = new FormFieldText(xrefA, obj, pref, usedParents);
1309     } else if (obj2.isName("Ch")) {
1310       field = new FormFieldChoice(xrefA, obj, pref, usedParents);
1311     } else if (obj2.isName("Sig")) {
1312       field = new FormFieldSignature(xrefA, obj, pref, usedParents);
1313     } else { //we don't have an FT entry => non-terminal field
1314       field = new FormField(xrefA, obj, pref, usedParents);
1315     }
1316     obj2.free();
1317 
1318     field->loadChildrenDefaults();
1319 
1320     return field;
1321 }
1322 
postWidgetsLoad()1323 void Form::postWidgetsLoad ()
1324 {
1325  for(int i=0; i<numFields; i++) {
1326    rootFields[i]->fillChildrenSiblingsID();
1327  }
1328 }
1329 
findWidgetByRef(Ref aref)1330 FormWidget* Form::findWidgetByRef (Ref aref)
1331 {
1332   for(int i=0; i<numFields; i++) {
1333     FormWidget *result = rootFields[i]->findWidgetByRef(aref);
1334     if(result) return result;
1335   }
1336   return NULL;
1337 }
1338 
1339 //------------------------------------------------------------------------
1340 // FormPageWidgets
1341 //------------------------------------------------------------------------
1342 
FormPageWidgets(XRef * xrefA,Object * annots,unsigned int page,Form * form)1343 FormPageWidgets::FormPageWidgets (XRef *xrefA, Object* annots, unsigned int page, Form *form)
1344 {
1345   Object obj1;
1346   numWidgets = 0;
1347   widgets = NULL;
1348   xref = xrefA;
1349   if (annots->isArray() && form) {
1350     size = annots->arrayGetLength();
1351     widgets = (FormWidget**)greallocn(widgets, size, sizeof(FormWidget*));
1352 
1353     /* For each entry in the page 'Annots' dict, try to find
1354        a matching form field */
1355     for (int i = 0; i < size; ++i) {
1356       if (!annots->arrayGetNF(i, &obj1)->isRef())  {
1357         /* Since all entry in a form field's kid dict needs to be
1358            indirect references, if this annot isn't indirect, it isn't
1359            related to a form field */
1360         obj1.free();
1361         continue;
1362       }
1363       Ref r = obj1.getRef();
1364 
1365       /* Try to find a form field which either has this Annot in its Kids entry
1366           or  is merged with this Annot */
1367       FormWidget* tmp = form->findWidgetByRef(r);
1368       if(tmp) {
1369         // We've found a corresponding form field, link it
1370         tmp->setID(FormWidget::encodeID(page, numWidgets));
1371         widgets[numWidgets++] = tmp;
1372         //create a temporary Annot to get the font size
1373         Object obj2;
1374         if (annots->arrayGet(i, &obj2)->isDict()) {
1375           Annot *ann;
1376 
1377           ann = new Annot(xref, obj2.getDict(), NULL);
1378           tmp->setFontSize(ann->getFontSize());
1379           delete ann;
1380         }
1381         obj2.free();
1382       }
1383 
1384       obj1.free();
1385     }
1386   }
1387 }
1388 
~FormPageWidgets()1389 FormPageWidgets::~FormPageWidgets()
1390 {
1391   gfree (widgets);
1392 }
1393