Alphabetical Class Index  Class Hierarchy   File Members   Compound Members   File List  

ezpdf.h
1 // Copyright (c) 1998-2014 by Tech Soft 3D, Inc.
2 //
3 // The information contained herein is confidential and proprietary to Tech Soft 3D, Inc.,
4 // and considered a trade secret as defined under civil and criminal statutes.
5 // Tech Soft 3D, Inc. shall pursue its civil and criminal remedies in the event of
6 // unauthorized use or misappropriation of its trade secrets. Use of this information
7 // by anyone other than authorized employees of Tech Soft 3D, Inc. is granted only under
8 // a written non-disclosure agreement, expressly prescribing the scope and manner of such use.
9 
10 #if 1
11 
12 #ifndef _EZPDF_H
13 #define _EZPDF_H
14 
15 #include <locale>
16 #include <iostream>
17 #include <fstream>
18 #include <sstream>
19 #include <iomanip>
20 #include <map>
21 #include <vector>
22 #include <string>
23 #include <cstdlib>
24 #include <assert.h>
25 #include "zlib.h"
26 #include "utf_utils.h"
27 
28 #ifdef H_PACK_8
29 #pragma pack(push)
30 #pragma pack(8)
31 #endif
32 
33 namespace ezpdf
34 {
35  using namespace std;
36 
37  int const EZPDF_BUFFER_SIZE = 1024*64;
38 
39  class File;
40  class Dict;
41  class Array;
42 
43  namespace common {
44  bool LittleEndian(){
45  unsigned short lebom = 0xfffe;
46  unsigned char const * const first_byte = (unsigned char const * const)&lebom;
47  return *first_byte == 0xfe;
48  }
49 
50  void escape_char(ostream & out, char const c)
51  {
52  if(c == '\\' || c == '(' || c == ')')
53  out << '\\';
54  }
55  }
56 
57  using namespace common;
58 
59  void write_string(ostream & out, wstring const & s)
60  {
61  H_UTF16 utf16(s.c_str());
62  /* Write out big endian UTF16 BOM. */
63  out << '(' << (char)-2 << (char)-1;
64  utf16_char const * next = utf16.encodedText();
65  while(*next != 0){
66  char const upper = (char)((*next >> 8) & 0xff);
67  escape_char(out, upper);
68  out << upper;
69 
70  char const lower = (char)(*next & 0xff);
71  escape_char(out, lower);
72  out << lower;
73 
74  ++next;
75  }
76  out << ')';
77  }
78 
79  void write_string(ostream & out, string const & s)
80  {
81  out << '(';
82  char const * next = s.c_str();
83  while(*next != 0){
84  escape_char(out, *next);
85  out << *next;
86  ++next;
87  }
88  out << ')';
89  }
90 
91 
92 
93  class BaseObject
94  {
95  public:
96  BaseObject ()
97  {
98  };
99 
100  virtual ~ BaseObject ()
101  {
102  };
103 
104  friend class File;
105  friend class Dict;
106  friend class Array;
107 
108  private:
109  virtual void release ()
110  {
111  };
112 
113  virtual bool managed () const
114  {
115  return false;
116  };
117 
118  virtual void write (ostream & out) const = 0;
119  virtual BaseObject *clone () const = 0;
120  };
121 
122  class Boolean:public BaseObject
123  {
124  private:
125  bool m_bool;
126 
127  void write (ostream & out) const
128  {
129  out << (m_bool ? "true" : "false");
130  };
131 
132  void release ()
133  {
134  delete this;
135  };
136 
137  BaseObject *clone () const
138  {
139  return static_cast < BaseObject * >(new Boolean (m_bool));
140  };
141 
142  public:
143  friend class Dict;
144 
145  Boolean (bool b):m_bool (b)
146  {
147  };
148 
149  operator bool () const
150  {
151  return m_bool;
152  };
153  };
154 
155  class Int:public BaseObject
156  {
157  private:
158  long m_int;
159 
160  void write (ostream & out) const
161  {
162  out << m_int;
163  };
164 
165  void release ()
166  {
167  delete this;
168  };
169 
170  BaseObject *clone () const
171  {
172  return static_cast < BaseObject * >(new Int (m_int));
173  };
174 
175  public:
176  friend class Dict;
177 
178  Int (long i):m_int (i)
179  {
180  };
181 
182  operator int () const
183  {
184  return static_cast<int>(m_int);
185  };
186 
187  operator long () const
188  {
189  return m_int;
190  };
191 
192  operator size_t () const
193  {
194  return static_cast<size_t>(m_int);
195  };
196  };
197 
198  class Float:public BaseObject
199  {
200  private:
201  double m_float;
202 
203  void write (ostream & out) const
204  {
205  out << fixed << setprecision(6) << m_float;
206  };
207 
208  void release ()
209  {
210  delete this;
211  };
212 
213  BaseObject *clone () const
214  {
215  return static_cast < BaseObject * >(new Float (m_float));
216  };
217 
218  public:
219  friend class Dict;
220 
221  Float (double f):m_float (f)
222  {
223  };
224 
225  operator float () const
226  {
227  return static_cast<float>(m_float);
228  };
229 
230  operator double () const
231  {
232  return m_float;
233  };
234 
235  };
236 
237  class Name:public BaseObject
238  {
239  private:
240  string m_name;
241 
242  void write (ostream & out) const
243  {
244  out << '/' << m_name;
245  };
246 
247  void release ()
248  {
249  delete this;
250  };
251 
252  BaseObject *clone () const
253  {
254  return static_cast < BaseObject * >(new Name (m_name));
255  };
256 
257  public:
258  friend class Dict;
259  friend class Graphics;
260 
261  Name (string const &s):m_name (s)
262  {
263  };
264 
265  Name (char const * s):m_name (s)
266  {
267  };
268 
269  bool operator < (Name const &rhs) const
270  {
271  return m_name < rhs.m_name;
272  };
273 
274  bool operator == (Name const &rhs) const
275  {
276  return m_name == rhs.m_name;
277  };
278 
279  bool operator != (Name const &rhs) const
280  {
281  return m_name != rhs.m_name;
282  };
283 
284  operator string () const
285  {
286  return m_name;
287  };
288 
289  };
290 
291  class WString : public BaseObject
292  {
293  private:
294  wstring m_string;
295 
296  void write (ostream & out) const
297  {
298  write_string(out, m_string);
299  };
300 
301  void release ()
302  {
303  delete this;
304  };
305 
306  BaseObject *clone () const
307  {
308  return static_cast < BaseObject * >(new WString (m_string));
309  };
310  public:
311  friend class Dict;
312 
313  explicit WString (string const &s):m_string (H_WCS(s.c_str()).encodedText())
314  {
315  };
316 
317  explicit WString (wstring const &s):m_string(s)
318  {
319  };
320 
321  operator wstring () const
322  {
323  return m_string;
324  };
325 
326  };
327 
328  class String : public BaseObject
329  {
330  private:
331  string m_string;
332 
333  void write (ostream & out) const
334  {
335  write_string(out, m_string);
336  };
337 
338  void release ()
339  {
340  delete this;
341  };
342 
343  BaseObject *clone () const
344  {
345  return static_cast < BaseObject * >(new String (m_string));
346  };
347  public:
348  friend class Dict;
349 
350  explicit String (string const &s):m_string (s)
351  {
352  };
353 
354  operator string () const
355  {
356  return m_string;
357  };
358 
359  };
360 
361 
362 
363  class Graphics
364  {
365  private:
366  stringstream m_stream;
367 
368  void Font(Name const & font_name, double const points) {
369  font_name.write(m_stream);
370  m_stream << ' ' << points << " Tf" << endl;
371  };
372 
373  public:
374 
375  /*****************************
376  * PDF Drawing commands
377  ****************************
378 
379  * B - Fill and stroke the path using nonzero winding number rule
380  * B* - Fill and stroke the path using even-odd rule
381  * b - Close, fill and stroke the path using nonzero winding number rule
382  * b* - Close, fill and stroke the path using even-odd rule
383  * c - curve
384  * cs - color space
385  * d - dash pattern
386  * f - fill path using nonzero winding number rule
387  * f* - fill path using even-odd rule
388  * h - connect last point to first point in path (complete path)
389  * J - Line Cap
390  * j - Line Join
391  * l - line to (from last point in path)
392  * m - move to (begin new path)
393  * n - end the path without filling or stroking
394  * Q - pop color space/clipping state on color space stack
395  * q - push color space/clipping state on color space stack
396  * re - rectangle
397  * RG - set stroke color
398  * rg _ set fill color
399  * S - Stroke path
400  * s - Close and stroke a path (same is "h S")
401  * scn - something to do with face patterns
402  * Tf - font size (in points)
403  * W - marks the current path as the clipping path and intersects it with the current clipping path
404  * w - line weight
405 
406  *****************************
407  * PDF Drawing commands
408  ****************************/
409 
410  Graphics() {};
411 
412  Graphics(Graphics const & g)
413  {
414  m_stream << g.m_stream.str();
415  };
416 
417  Graphics const operator = (Graphics const & rhs)
418  {
419  m_stream << rhs.m_stream.str();
420  return *this;
421  };
422 
423  friend class Dict;
424 
425  Graphics & Exlicit(string const & cmd)
426  {
427  m_stream.write(cmd.c_str(), static_cast<streamsize>(cmd.length()));
428  m_stream << endl;
429  return *this;
430  };
431 
432  Graphics & PushGraphicsState() {m_stream << 'q' << endl;return *this;};
433  Graphics & PopGraphicsState() {m_stream << 'Q' << endl;return *this;};
434 
435  Graphics & PenPosition(double const x, double const y)
436  {
437  m_stream << x << ' ' << y << " m" << endl;return *this;
438  };
439 
440  Graphics & MovePen(double const x, double const y)
441  {
442  m_stream << x << ' ' << y << " l" << endl;return *this;
443  };
444 
445  Graphics & StrokeColor(double const r, double const g, double const b)
446  {
447  m_stream << r << ' ' << g << ' ' << b << " RG" << endl;return *this;
448  };
449 
450  Graphics & FillColor(double const r, double const g, double const b)
451  {
452  m_stream << r << ' ' << g << ' ' << b << " rg" << endl;return *this;
453  };
454 
455  Graphics & FillAndStrokeWR() {m_stream << "B" << endl;return *this;};
456  Graphics & FillAndStrokeEO() {m_stream << "B*" << endl;return *this;};
457  Graphics & CloseFillAndStrokeWR() {m_stream << "b*" << endl;return *this;};
458  Graphics & CloseFillAndStrokeEO() {m_stream << "b*" << endl;return *this;};
459  Graphics & FillWR() {m_stream << "f" << endl;return *this;};
460  Graphics & FillEO() {m_stream << "f*" << endl;return *this;};
461  Graphics & CompletePath() {m_stream << "h" << endl;return *this;};
462  Graphics & Stroke() {m_stream << "S" << endl;return *this;};
463  Graphics & CompleteAndStroke() {m_stream << "s" << endl;return *this;};
464 
465  Graphics & BeginText(double const x, double const y, Name const & font_name, double const points)
466  {
467  Font(font_name, points);
468  m_stream << "BT " << x << ' ' << y << " Td ";return *this;
469  };
470 
471  template <typename T>
472  Graphics & InsertText(T const & text)
473  {
474  write_string(m_stream, text);
475  m_stream << " Tj " << endl;
476  return *this;
477  }
478 
479  Graphics & InsertText(double const x, double const y, string const & text)
480  {
481  m_stream << x << ' ' << y << " Td ";
482  InsertText(text);
483  return *this;
484  };
485 
486  Graphics & InsertText(double const x, double const y, wstring const & text)
487  {
488  m_stream << x << ' ' << y << " Td ";
489  InsertText(text);
490  return *this;
491  };
492 
493  Graphics & EndText()
494  {
495  m_stream << "ET" << endl;return *this;
496  }
497 
498  Graphics & InsertImageRGB(double left, double right, double bottom, double top,
499  int const w, int const h, void const * image)
500  {
501  m_stream << "q " << right-left << " 0 0 " << top-bottom << ' ' << left
502  << ' ' << bottom << " cm ";
503  m_stream << "BI /W " << w << " /H " << h << " /CS /RGB /BPC 8 ID ";
504  m_stream.write(static_cast<char const*>(image), static_cast<streamsize>(w*h*3));
505  m_stream << "EI Q" << endl;return *this;
506  };
507 
508  };
509 
510  class Dict : public BaseObject
511  {
512  private:
513  int m_id;
514  File * m_file;
515  stringstream *m_stream;
516  map < Name, BaseObject * >m_items;
517 
518  void *operator new (size_t size)
519  {
520  return malloc (size);
521  };
522 
523  void operator delete (void *p)
524  {
525  free (p);
526  };
527 
528  void write (ostream & out) const
529  {
530  out << m_id << " 0 R";
531  };
532 
533  void write_direct (ostream & out) const;
534  void really_write (ostream & out) const;
535 
536  bool managed () const
537  {
538  return true;
539  };
540 
541  BaseObject *clone () const
542  {
543  // TODO: this isn't really a clone.
544  return static_cast < BaseObject * >(const_cast < Dict * >(this));
545  };
546 
547  void release ()
548  {
549  map < Name, BaseObject * >::iterator iter = m_items.begin ();
550  while (iter != m_items.end ())
551  {
552  if (!iter->second->managed ())
553  iter->second->release ();
554  ++iter;
555  }
556  };
557 
558  public:
559  friend class File;
560 
561  Dict (File * pdf_file, int id):m_id (id), m_file (pdf_file), m_stream (0)
562  {
563  };
564 
565  ~Dict ()
566  {
567  delete m_stream;
568  };
569 
570  Array *newArray () const;
571  Array *newArray (Name const &);
572  template <typename T>
573  Array *newArray (T const *, T const *) const;
574  template <typename T>
575  Array *newArray (Name const &, T const *, T const *);
576  Dict *newDict () const;
577  Dict *newDict (Name const &);
578 
579  template <typename T1> bool get(Name const & key, Array *& value_out)
580  {
581  bool retval = false;
582  map < Name, BaseObject * >::const_iterator iter = m_items.find (key);
583  if(iter != m_items.end())
584  {
585  //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS.
586  //T1 value = dynamic_cast<T1>(iter->second);
587  T1 value = static_cast<T1>(iter->second);
588  if(value)
589  {
590  value_out = value;
591  retval = true;
592  }
593  }
594  return retval;
595  }
596 
597  template <typename T1> bool get(Name const & key, Dict *& value_out)
598  {
599  bool retval = false;
600  map < Name, BaseObject * >::const_iterator iter = m_items.find (key);
601  if(iter != m_items.end())
602  {
603  //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS.
604  //T1 value = dynamic_cast<T1>(iter->second);
605  T1 value = static_cast<T1>(iter->second);
606  if(value)
607  {
608  value_out = value;
609  retval = true;
610  }
611  }
612  return retval;
613  }
614 
615  template <typename T1, typename T2> bool get(Name const & key, T2 & value_out) const
616  {
617  bool retval = false;
618  map < Name, BaseObject * >::const_iterator iter = m_items.find (key);
619  if(iter != m_items.end())
620  {
621  //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS.
622  //T1 const * value = dynamic_cast<T1*>(iter->second);
623  T1 const * value = static_cast<T1*>(iter->second);
624  if(value)
625  {
626  value_out = *value;
627  retval = true;
628  }
629  }
630  return retval;
631  }
632 
633  Dict * appendStream (Graphics g)
634  {
635  if (!m_stream)
636  m_stream = new stringstream(stringstream::binary |
637  stringstream::in |
638  stringstream::out);
639  else
640  *m_stream << ' ';
641 
642  char buffer[EZPDF_BUFFER_SIZE];
643  g.m_stream.read (buffer,
644  static_cast < streamsize > (EZPDF_BUFFER_SIZE));
645  while (g.m_stream.gcount () > 0)
646  {
647  m_stream->write (buffer, g.m_stream.gcount ());
648  g.m_stream.read (buffer,
649  static_cast < streamsize > (EZPDF_BUFFER_SIZE));
650  }
651  return this;
652  }
653 
654  Dict * appendStream (void const *begin, size_t size)
655  {
656  if (!m_stream)
657  m_stream = new stringstream(stringstream::binary |
658  stringstream::in |
659  stringstream::out);
660  m_stream->write (static_cast<char const*>(begin), static_cast<streamsize>(size));
661  return this;
662  };
663 
664  int streamSize () const
665  {
666  int retval = 0;
667  if (m_stream)
668  retval = m_stream->tellp ();
669  return retval;
670  };
671 
672  Dict * remove (Name const &n)
673  {
674  map < Name, BaseObject * >::iterator iter = m_items.find (n);
675  if(iter != m_items.end()){
676  if(!iter->second->managed()){
677  iter->second->release();
678  }
679  m_items.erase(n);
680  }
681  return this;
682  };
683 
684  Dict * insert (Name const &n, Array * value);
685 
686  Dict * insert (Name const &n, int value)
687  {
688  remove(n);
689  BaseObject *b = new Int (value);
690  m_items.insert (make_pair (n, b));
691  return this;
692  };
693 
694  Dict * insert (Name const &n, float value)
695  {
696  remove(n);
697  BaseObject *b = new Float (value);
698  m_items.insert (make_pair (n, b));
699  return this;
700  };
701 
702  Dict * insert (Name const &n, double value)
703  {
704  remove(n);
705  BaseObject *b = new Float (value);
706  m_items.insert (make_pair (n, b));
707  return this;
708  };
709 
710  Dict * insert (Name const &n, long value)
711  {
712  remove(n);
713  BaseObject *b = new Int (value);
714  m_items.insert (make_pair (n, b));
715  return this;
716  };
717 
718  Dict * insert (Name const &n, size_t value)
719  {
720  remove(n);
721  BaseObject *b = new Int (static_cast<long>(value));
722  m_items.insert (make_pair (n, b));
723  return this;
724  };
725 
726  Dict * insert (Name const &n, bool value)
727  {
728  remove(n);
729  BaseObject *b = new Boolean (value);
730  m_items.insert (make_pair (n, b));
731  return this;
732  };
733 
734  Dict * insert (Name const &n, WString const &value)
735  {
736  remove(n);
737  BaseObject *b = new WString (value);
738  m_items.insert (make_pair (n, b));
739  return this;
740  };
741 
742  Dict * insert (Name const &n, String const &value)
743  {
744  remove(n);
745  BaseObject *b = new String (value);
746  m_items.insert (make_pair (n, b));
747  return this;
748  };
749 
750  Dict * insert (Name const &n, Name const &value)
751  {
752  remove(n);
753  BaseObject *b = new Name (value);
754  m_items.insert (make_pair (n, b));
755  return this;
756  };
757 
758  Dict * insert (Name const &n, Dict const * value)
759  {
760  remove(n);
761  Dict * d = const_cast<Dict*>(value);
762  m_items.insert (make_pair (n, static_cast < BaseObject * >(d)));
763  return this;
764  };
765 
766  };
767 
768  class Array:public BaseObject
769  {
770  private:
771  vector < BaseObject * >m_items;
772 
773  void clear ()
774  {
775  for (unsigned int i = 0; i < m_items.size (); ++i)
776  {
777  if (!m_items[i]->managed ())
778  {
779  m_items[i]->release ();
780  }
781  }
782  m_items.clear ();
783  };
784 
785  void *operator new (size_t size)
786  {
787  return malloc (size);
788  };
789 
790  void operator delete (void *p)
791  {
792  free (p);
793  };
794 
795 
796  BaseObject *clone () const
797  {
798  Array *tmp = new Array;
799  *tmp = *this;
800  return tmp;
801  };
802 
803  void write (ostream & out) const
804  {
805  out << '[';
806  if (!m_items.empty ()){
807  m_items[0]->write (out);
808  for (unsigned int i = 1; i < m_items.size (); ++i)
809  {
810  out << ' ';
811  m_items[i]->write (out);
812  }
813  }
814  out << ']';
815  };
816 
817  void release ()
818  {
819  clear();
820  };
821 
822  bool managed () const
823  {
824  return true;
825  };
826 
827  ~Array ()
828  {
829  clear ();
830  };
831 
832  Array ()
833  {
834  };
835 
836  Array (int const *begin, int const *end)
837  {
838  insert (begin, end);
839  };
840 
841  Array (float const *begin, float const *end)
842  {
843  insert (begin, end);
844  };
845 
846  Array (bool const *begin, bool const *end)
847  {
848  insert (begin, end);
849  };
850 
851  Array (WString const *begin, WString const *end)
852  {
853  insert (begin, end);
854  };
855 
856  Array (String const *begin, String const *end)
857  {
858  insert (begin, end);
859  };
860 
861  Array (Name const *begin, Name const *end)
862  {
863  insert (begin, end);
864  };
865 
866  Array (Dict ** begin, Dict ** end)
867  {
868  insert (begin, end);
869  };
870 
871  Array (Array * begin, Array * end)
872  {
873  insert (begin, end);
874  };
875  public:
876  friend class File;
877 
878  template <typename T1> bool get(unsigned int index, Dict *& value_out)
879  {
880  bool retval = false;
881  if(index < m_items.size())
882  {
883  BaseObject * bo = m_items[index];
884  //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS.
885  //T1 value = dynamic_cast<T1>(bo);
886  T1 value = static_cast<T1>(bo);
887  if(value)
888  {
889  value_out = value;
890  retval = true;
891  }
892  }
893  return retval;
894  }
895 
896  template <typename T1, typename T2> bool get(unsigned int index, T2 & value_out) const
897  {
898  bool retval = false;
899  if(index < m_items.size())
900  {
901  BaseObject * bo = m_items[index];
902  //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS.
903  //T1 * value = dynamic_cast<T1*>(bo);
904  T1 * value = static_cast<T1*>(bo);
905  if(value)
906  {
907  value_out = *value;
908  retval = true;
909  }
910  }
911  return retval;
912  }
913 
914  size_t size () const
915  {
916  return m_items.size ();
917  };
918 
919  void remove (unsigned int const index)
920  {
921  if(index < m_items.size()){
922 
923  if(!m_items[index]->managed())
924  m_items[index]->release();
925 
926  m_items.erase(m_items.begin() + index);
927  }
928  };
929 
930  Array & insert (int value)
931  {
932  m_items.push_back (new Int (value));
933  return *this;
934  };
935 
936  Array & insert (float value)
937  {
938  m_items.push_back (new Float (value));
939  return *this;
940  };
941 
942  Array & insert (double value)
943  {
944  m_items.push_back (new Float (value));
945  return *this;
946  };
947 
948  Array & insert (bool value)
949  {
950  m_items.push_back (new Boolean (value));
951  return *this;
952  };
953 
954  Array & insert (WString const &value)
955  {
956  m_items.push_back (new WString (value));
957  return *this;
958  };
959 
960  Array & insert (String const &value)
961  {
962  m_items.push_back (new String (value));
963  return *this;
964  };
965 
966  Array & insert (Name const &value)
967  {
968  m_items.push_back (new Name (value));
969  return *this;
970  };
971 
972  Array & insert (Dict * value)
973  {
974  m_items.push_back (value);
975  return *this;
976  };
977 
978  Array & insert (Array * value)
979  {
980  m_items.push_back (value);
981  return *this;
982  };
983 
984  Array & insert (int const *begin, int const *end)
985  {
986  while (begin != end)
987  {
988  m_items.push_back (new Int (*begin));
989  ++begin;
990  }
991  return *this;
992  };
993 
994  Array & insert (float const *begin, float const *end)
995  {
996  while (begin != end)
997  {
998  m_items.push_back (new Float (*begin));
999  ++begin;
1000  }
1001  return *this;
1002  };
1003 
1004  Array & insert (bool const *begin, bool const *end)
1005  {
1006  while (begin != end)
1007  {
1008  m_items.push_back (new Boolean (*begin));
1009  ++begin;
1010  }
1011  return *this;
1012  };
1013 
1014  Array & insert (WString const *begin, WString const *end)
1015  {
1016  while (begin != end)
1017  {
1018  m_items.push_back (new WString (*begin));
1019  ++begin;
1020  }
1021  return *this;
1022  };
1023 
1024  Array & insert (String const *begin, String const *end)
1025  {
1026  while (begin != end)
1027  {
1028  m_items.push_back (new String (*begin));
1029  ++begin;
1030  }
1031  return *this;
1032  };
1033 
1034  Array & insert (Name const *begin, Name const *end)
1035  {
1036  while (begin != end)
1037  {
1038  m_items.push_back (new Name (*begin));
1039  ++begin;
1040  }
1041  return *this;
1042  };
1043 
1044  Array & insert (Dict ** begin, Dict ** end)
1045  {
1046  while (begin != end)
1047  {
1048  m_items.push_back (*begin);
1049  ++begin;
1050  }
1051  return *this;
1052  };
1053 
1054  Array & insert (Array *begin, Array *end)
1055  {
1056  while (begin != end)
1057  {
1058  m_items.push_back (begin);
1059  ++begin;
1060  }
1061  return *this;
1062  };
1063  };
1064 
1065  Dict * Dict::insert (Name const &n, Array * value)
1066  {
1067  remove(n);
1068  m_items.insert (make_pair (n, static_cast<BaseObject*>(value)));
1069  return this;
1070  };
1071 
1072  class File : public BaseObject
1073  {
1074  private:
1075  int m_object_count;
1076  mutable Dict * m_ptrailer;
1077  float m_version;
1078  map < int, long > m_xrefs;
1079  vector < Dict * > m_dictionaries;
1080  vector < Array * > m_arrays;
1081  ofstream m_out;
1082 
1083  BaseObject *clone () const
1084  {
1085  return 0;
1086  };
1087 
1088  void write (ostream & out) const
1089  {
1090  out << "%PDF-" << m_version;
1091 
1092  for (unsigned int i = 0; i < m_dictionaries.size (); ++i)
1093  {
1094  m_dictionaries[i]->really_write (out);
1095  }
1096 
1097  out << "\n\n\n";
1098  long xref_fpos = out.tellp ();
1099  out << "xref" << endl;
1100  out << "0 " << m_object_count << endl;
1101 
1102  char cur_fill = out.fill ();
1103  out.fill ('0');
1104 
1105  for (int i = 0; i < m_object_count; ++i)
1106  {
1107  map < int, long >::const_iterator iter = m_xrefs.find (i);
1108  if (iter == m_xrefs.end ())
1109  out << "0000000000 65535 f " << endl;
1110  else
1111  out << setw (10) << iter->second << " 00000 n " << endl;
1112  }
1113  out.fill (cur_fill);
1114 
1115  m_ptrailer->insert("Size", m_object_count);
1116  out << "\n\n" << "trailer" << endl;
1117  m_ptrailer->write_direct(out);
1118  out << "\n\n\n";
1119 
1120  out << "startxref" << endl << xref_fpos << endl << "%%EOF";
1121 
1122  if(out.fail())
1123  throw false;
1124  };
1125 
1126  void release ()
1127  {
1128  };
1129 
1130  public:
1131  friend class Dict;
1132 
1133  explicit File (string const & filename):m_object_count (1), m_ptrailer(0),
1134  m_version (1.7f), m_out (filename.c_str(), ios::out | ios::binary)
1135  {
1136  };
1137 
1138  explicit File (wstring const & filename):m_object_count (1), m_ptrailer(0),
1139  m_version (1.7f)
1140  {
1141 #if _MSC_VER
1142  m_out.open(filename.c_str(), ios::out | ios::binary);
1143 #else
1144  int len = wcstombs(0, filename.c_str(), 0) +1;
1145  char * tmp = new char[len];
1146  char const * const old_loc = setlocale(LC_CTYPE, "");
1147  wcstombs(tmp, filename.c_str(), len);
1148  setlocale(LC_CTYPE, old_loc);
1149  m_out.open(tmp, ios::out | ios::binary);
1150  delete [] tmp;
1151 #endif
1152  };
1153 
1154  ~File ()
1155  {
1156  if(m_ptrailer)
1157  m_ptrailer->release ();
1158  delete m_ptrailer;
1159 
1160  for (unsigned int i = 0; i < m_dictionaries.size (); ++i)
1161  {
1162  m_dictionaries[i]->release ();
1163  }
1164 
1165  for (unsigned int i = 0; i < m_arrays.size(); ++i)
1166  {
1167  m_arrays[i]->release();
1168  }
1169 
1170  for (unsigned int i = 0; i < m_dictionaries.size (); ++i)
1171  {
1172  delete m_dictionaries[i];
1173  }
1174 
1175  for (unsigned int i = 0; i < m_arrays.size(); ++i)
1176  {
1177  delete m_arrays[i];
1178  }
1179  };
1180 
1181  void close () {
1182  if(m_out.is_open()){
1183  write(m_out);
1184  }
1185  m_out.close();
1186  };
1187 
1188  template <typename T1> bool get(Name const & key, Dict *& value_out)
1189  {
1190  return m_ptrailer->get<T1> (key, value_out);
1191  }
1192 
1193  template <typename T1, typename T2> bool get(Name const & key, T2 & value_out) const
1194  {
1195  return m_ptrailer->get<T1> (key, value_out);
1196  }
1197 
1198  Array * newArray ()
1199  {
1200  Array *retval = new Array;
1201  m_arrays.push_back (retval);
1202  return retval;
1203  };
1204 
1205  template <typename T>
1206  Array * newArray (T const * begin, T const * end)
1207  {
1208  Array *retval = new Array(begin, end);
1209  m_arrays.push_back (retval);
1210  return retval;
1211  }
1212 
1213  Dict *newDict ()
1214  {
1215  Dict *retval = new Dict (this, m_object_count++);
1216  m_dictionaries.push_back (retval);
1217  return retval;
1218  }
1219 
1220  Dict *newDict (Name const & n)
1221  {
1222  Dict *retval = new Dict (this, m_object_count++);
1223  m_dictionaries.push_back (retval);
1224  if(!m_ptrailer)
1225  m_ptrailer = new Dict(this, 0);
1226  m_ptrailer->insert(n, retval);
1227  return retval;
1228  }
1229  };
1230 
1231  Array * Dict::newArray() const
1232  {
1233  return m_file->newArray();
1234  };
1235 
1236  Array * Dict::newArray(Name const & n)
1237  {
1238  Array * retval = newArray();
1239  insert(n, retval);
1240  return retval;
1241  };
1242 
1243  template <typename T>
1244  Array * Dict::newArray(T const * begin, T const * end) const
1245  {
1246  return m_file->newArray(begin, end);
1247  }
1248 
1249  template <typename T>
1250  Array * Dict::newArray(Name const & n, T const * begin, T const * end)
1251  {
1252  Array * retval = newArray(begin, end);
1253  insert(n, retval);
1254  return retval;
1255  }
1256 
1257  Dict * Dict::newDict() const
1258  {
1259  Dict *retval = new Dict (m_file, m_file->m_object_count++);
1260  m_file->m_dictionaries.push_back (retval);
1261  return retval;
1262  };
1263 
1264  Dict * Dict::newDict(Name const & n)
1265  {
1266  Dict *retval = newDict();
1267  insert(n, retval);
1268  return retval;
1269  };
1270 
1271  void Dict::write_direct (ostream & out) const
1272  {
1273  out << "<<";
1274 
1275  map < Name, BaseObject * >::const_iterator iter = m_items.begin ();
1276  while (iter != m_items.end ())
1277  {
1278  out << endl;
1279  iter->first.write (out);
1280  out << ' ';
1281  iter->second->write (out);
1282  ++iter;
1283  }
1284 
1285  out << endl << ">>";
1286  };
1287 
1288  void Dict::really_write (ostream & out) const
1289  {
1290  if (m_file->m_xrefs.find (m_id) == m_file->m_xrefs.end ())
1291  {
1292 
1293  out << "\n\n\n";
1294  long dict_fpos = out.tellp ();
1295  m_file->m_xrefs.insert (make_pair (m_id, dict_fpos));
1296  out << m_id << " 0 obj\n";
1297 
1298  write_direct(out);
1299 
1300  out << endl;
1301 
1302  if (m_stream)
1303  {
1304  out << "stream" << endl;
1305  char buffer[EZPDF_BUFFER_SIZE];
1306  m_stream->read (buffer,
1307  static_cast < streamsize > (EZPDF_BUFFER_SIZE));
1308  while (m_stream->gcount () > 0)
1309  {
1310  out.write (buffer, m_stream->gcount ());
1311  m_stream->read (buffer,
1312  static_cast < streamsize >
1313  (EZPDF_BUFFER_SIZE));
1314  }
1315  out << endl << "endstream" << endl;
1316  }
1317 
1318  out << "endobj";
1319  }
1320  };
1321 
1322  namespace filters {
1323  class filter {
1324  public:
1325  virtual ~filter() {};
1326  virtual filter & read(void*, streamsize) = 0;
1327  virtual filter & write(void const *, streamsize) = 0;
1328  virtual streamsize gcount() const = 0;
1329  virtual char const * name() const = 0;
1330  };
1331 
1332  class zlib : public filter {
1333  public:
1334  zlib() : m_reading(false){
1335  m_zstrm.zalloc = Z_NULL;
1336  m_zstrm.zfree = Z_NULL;
1337  m_zstrm.data_type = Z_ASCII;
1338  m_zstrm.next_out = 0;
1339  m_zstrm.avail_out = 0;
1340  m_zstrm.next_in = 0;
1341  m_zstrm.avail_in = 0;
1342  if(deflateInit(&m_zstrm, Z_BEST_COMPRESSION) != Z_OK){
1343  assert(0);
1344  }
1345  };
1346 
1347  ~zlib() {
1348  deflateEnd(&m_zstrm);
1349  };
1350 
1351  filter & read(void * out, streamsize howmuch) {
1352  if(!m_reading){
1353  char buffer[EZPDF_BUFFER_SIZE];
1354  int rc;
1355 
1356  do{
1357  m_zstrm.next_out = (Bytef*)(&buffer[0]);
1358  m_zstrm.avail_out = EZPDF_BUFFER_SIZE;
1359  rc = deflate(&m_zstrm, Z_FINISH);
1360 
1361  int have = EZPDF_BUFFER_SIZE - m_zstrm.avail_out;
1362  if(have){
1363  m_buf.write(buffer, have);
1364  }
1365  }while(rc != Z_STREAM_END);
1366  m_reading = true;
1367  }
1368 
1369  m_buf.read((char*)out, howmuch);
1370  return *this;
1371  };
1372 
1373  filter & write(void const * in, streamsize howmuch) {
1374  if(!m_reading){
1375  m_zstrm.next_in = const_cast<Bytef*>(static_cast<Bytef const*>(in));
1376  m_zstrm.avail_in = howmuch;
1377 
1378  char buffer[EZPDF_BUFFER_SIZE];
1379 
1380  m_zstrm.next_out = (Bytef*)(&buffer[0]);
1381  m_zstrm.avail_out = EZPDF_BUFFER_SIZE;
1382 
1383  while(m_zstrm.avail_in > 0){
1384  int rc = deflate(&m_zstrm, Z_NO_FLUSH);
1385  if(rc != Z_OK)
1386  assert(0);
1387 
1388  int have = EZPDF_BUFFER_SIZE - m_zstrm.avail_out;
1389  if(have){
1390  m_buf.write(buffer, have);
1391  m_zstrm.next_out = (Bytef*)(&buffer[0]);
1392  m_zstrm.avail_out = EZPDF_BUFFER_SIZE;
1393  }
1394  }
1395  int have = EZPDF_BUFFER_SIZE - m_zstrm.avail_out;
1396  if(have){
1397  m_buf.write(buffer, have);
1398  }
1399  }
1400 
1401  return *this;
1402  };
1403 
1404  streamsize gcount() const {
1405  return m_buf.gcount();
1406  };
1407 
1408  char const * name() const {return "FlateDecode";};
1409 
1410  private:
1411  std::stringstream m_buf;
1412  struct z_stream_s m_zstrm;
1413  bool m_reading;
1414  };
1415  }
1416 };
1417 
1418 
1419 #ifdef H_PACK_8
1420 #pragma pack(pop)
1421 #endif
1422 
1423 #endif
1424 
1425 #endif
Definition: ezpdf.h:198
Definition: ezpdf.h:122
Definition: ezpdf.h:1072
Definition: ezpdf.h:1323
Definition: ezpdf.h:93
Definition: ezpdf.h:328
Definition: ezpdf.h:291
Definition: ezpdf.h:363
Definition: ezpdf.h:510
Definition: ezpdf.h:237
Definition: ezpdf.h:1332
Definition: ezpdf.h:155
Definition: ezpdf.h:768