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