Alphabetical Class Index  Class Hierarchy   File Members   Compound Members   File List  

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