00001 // Copyright (c) 1998-2014 by Tech Soft 3D, Inc. 00002 // 00003 // The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., 00004 // and considered a trade secret as defined under civil and criminal statutes. 00005 // Tech Soft 3D, Inc. shall pursue its civil and criminal remedies in the event of 00006 // unauthorized use or misappropriation of its trade secrets. Use of this information 00007 // by anyone other than authorized employees of Tech Soft 3D, Inc. is granted only under 00008 // a written non-disclosure agreement, expressly prescribing the scope and manner of such use. 00009 00010 #if 1 00011 00012 #ifndef _EZPDF_H 00013 #define _EZPDF_H 00014 00015 #include <locale> 00016 #include <iostream> 00017 #include <fstream> 00018 #include <sstream> 00019 #include <iomanip> 00020 #include <map> 00021 #include <vector> 00022 #include <string> 00023 #include <cstdlib> 00024 #include <assert.h> 00025 #include "zlib.h" 00026 #include "utf_utils.h" 00027 00028 #ifdef H_PACK_8 00029 #pragma pack(push) 00030 #pragma pack(8) 00031 #endif 00032 00033 namespace ezpdf 00034 { 00035 using namespace std; 00036 00037 int const EZPDF_BUFFER_SIZE = 1024*64; 00038 00039 class File; 00040 class Dict; 00041 class Array; 00042 00043 namespace common { 00044 bool LittleEndian(){ 00045 unsigned short lebom = 0xfffe; 00046 unsigned char const * const first_byte = (unsigned char const * const)&lebom; 00047 return *first_byte == 0xfe; 00048 } 00049 00050 void escape_char(ostream & out, char const c) 00051 { 00052 if(c == '\\' || c == '(' || c == ')') 00053 out << '\\'; 00054 } 00055 } 00056 00057 using namespace common; 00058 00059 void write_string(ostream & out, wstring const & s) 00060 { 00061 H_UTF16 utf16(s.c_str()); 00062 /* Write out big endian UTF16 BOM. */ 00063 out << '(' << (char)-2 << (char)-1; 00064 utf16_char const * next = utf16.encodedText(); 00065 while(*next != 0){ 00066 char const upper = (char)((*next >> 8) & 0xff); 00067 escape_char(out, upper); 00068 out << upper; 00069 00070 char const lower = (char)(*next & 0xff); 00071 escape_char(out, lower); 00072 out << lower; 00073 00074 ++next; 00075 } 00076 out << ')'; 00077 } 00078 00079 void write_string(ostream & out, string const & s) 00080 { 00081 out << '('; 00082 char const * next = s.c_str(); 00083 while(*next != 0){ 00084 escape_char(out, *next); 00085 out << *next; 00086 ++next; 00087 } 00088 out << ')'; 00089 } 00090 00091 00092 00093 class BaseObject 00094 { 00095 public: 00096 BaseObject () 00097 { 00098 }; 00099 00100 virtual ~ BaseObject () 00101 { 00102 }; 00103 00104 friend class File; 00105 friend class Dict; 00106 friend class Array; 00107 00108 private: 00109 virtual void release () 00110 { 00111 }; 00112 00113 virtual bool managed () const 00114 { 00115 return false; 00116 }; 00117 00118 virtual void write (ostream & out) const = 0; 00119 virtual BaseObject *clone () const = 0; 00120 }; 00121 00122 class Boolean:public BaseObject 00123 { 00124 private: 00125 bool m_bool; 00126 00127 void write (ostream & out) const 00128 { 00129 out << (m_bool ? "true" : "false"); 00130 }; 00131 00132 void release () 00133 { 00134 delete this; 00135 }; 00136 00137 BaseObject *clone () const 00138 { 00139 return static_cast < BaseObject * >(new Boolean (m_bool)); 00140 }; 00141 00142 public: 00143 friend class Dict; 00144 00145 Boolean (bool b):m_bool (b) 00146 { 00147 }; 00148 00149 operator bool () const 00150 { 00151 return m_bool; 00152 }; 00153 }; 00154 00155 class Int:public BaseObject 00156 { 00157 private: 00158 long m_int; 00159 00160 void write (ostream & out) const 00161 { 00162 out << m_int; 00163 }; 00164 00165 void release () 00166 { 00167 delete this; 00168 }; 00169 00170 BaseObject *clone () const 00171 { 00172 return static_cast < BaseObject * >(new Int (m_int)); 00173 }; 00174 00175 public: 00176 friend class Dict; 00177 00178 Int (long i):m_int (i) 00179 { 00180 }; 00181 00182 operator int () const 00183 { 00184 return static_cast<int>(m_int); 00185 }; 00186 00187 operator long () const 00188 { 00189 return m_int; 00190 }; 00191 00192 operator size_t () const 00193 { 00194 return static_cast<size_t>(m_int); 00195 }; 00196 }; 00197 00198 class Float:public BaseObject 00199 { 00200 private: 00201 double m_float; 00202 00203 void write (ostream & out) const 00204 { 00205 out << fixed << setprecision(6) << m_float; 00206 }; 00207 00208 void release () 00209 { 00210 delete this; 00211 }; 00212 00213 BaseObject *clone () const 00214 { 00215 return static_cast < BaseObject * >(new Float (m_float)); 00216 }; 00217 00218 public: 00219 friend class Dict; 00220 00221 Float (double f):m_float (f) 00222 { 00223 }; 00224 00225 operator float () const 00226 { 00227 return static_cast<float>(m_float); 00228 }; 00229 00230 operator double () const 00231 { 00232 return m_float; 00233 }; 00234 00235 }; 00236 00237 class Name:public BaseObject 00238 { 00239 private: 00240 string m_name; 00241 00242 void write (ostream & out) const 00243 { 00244 out << '/' << m_name; 00245 }; 00246 00247 void release () 00248 { 00249 delete this; 00250 }; 00251 00252 BaseObject *clone () const 00253 { 00254 return static_cast < BaseObject * >(new Name (m_name)); 00255 }; 00256 00257 public: 00258 friend class Dict; 00259 friend class Graphics; 00260 00261 Name (string const &s):m_name (s) 00262 { 00263 }; 00264 00265 Name (char const * s):m_name (s) 00266 { 00267 }; 00268 00269 bool operator < (Name const &rhs) const 00270 { 00271 return m_name < rhs.m_name; 00272 }; 00273 00274 bool operator == (Name const &rhs) const 00275 { 00276 return m_name == rhs.m_name; 00277 }; 00278 00279 bool operator != (Name const &rhs) const 00280 { 00281 return m_name != rhs.m_name; 00282 }; 00283 00284 operator string () const 00285 { 00286 return m_name; 00287 }; 00288 00289 }; 00290 00291 class WString : public BaseObject 00292 { 00293 private: 00294 wstring m_string; 00295 00296 void write (ostream & out) const 00297 { 00298 write_string(out, m_string); 00299 }; 00300 00301 void release () 00302 { 00303 delete this; 00304 }; 00305 00306 BaseObject *clone () const 00307 { 00308 return static_cast < BaseObject * >(new WString (m_string)); 00309 }; 00310 public: 00311 friend class Dict; 00312 00313 explicit WString (string const &s):m_string (H_WCS(s.c_str()).encodedText()) 00314 { 00315 }; 00316 00317 explicit WString (wstring const &s):m_string(s) 00318 { 00319 }; 00320 00321 operator wstring () const 00322 { 00323 return m_string; 00324 }; 00325 00326 }; 00327 00328 class String : public BaseObject 00329 { 00330 private: 00331 string m_string; 00332 00333 void write (ostream & out) const 00334 { 00335 write_string(out, m_string); 00336 }; 00337 00338 void release () 00339 { 00340 delete this; 00341 }; 00342 00343 BaseObject *clone () const 00344 { 00345 return static_cast < BaseObject * >(new String (m_string)); 00346 }; 00347 public: 00348 friend class Dict; 00349 00350 explicit String (string const &s):m_string (s) 00351 { 00352 }; 00353 00354 operator string () const 00355 { 00356 return m_string; 00357 }; 00358 00359 }; 00360 00361 00362 00363 class Graphics 00364 { 00365 private: 00366 stringstream m_stream; 00367 00368 void Font(Name const & font_name, double const points) { 00369 font_name.write(m_stream); 00370 m_stream << ' ' << points << " Tf" << endl; 00371 }; 00372 00373 public: 00374 00375 /***************************** 00376 * PDF Drawing commands 00377 **************************** 00378 00379 * B - Fill and stroke the path using nonzero winding number rule 00380 * B* - Fill and stroke the path using even-odd rule 00381 * b - Close, fill and stroke the path using nonzero winding number rule 00382 * b* - Close, fill and stroke the path using even-odd rule 00383 * c - curve 00384 * cs - color space 00385 * d - dash pattern 00386 * f - fill path using nonzero winding number rule 00387 * f* - fill path using even-odd rule 00388 * h - connect last point to first point in path (complete path) 00389 * J - Line Cap 00390 * j - Line Join 00391 * l - line to (from last point in path) 00392 * m - move to (begin new path) 00393 * n - end the path without filling or stroking 00394 * Q - pop color space/clipping state on color space stack 00395 * q - push color space/clipping state on color space stack 00396 * re - rectangle 00397 * RG - set stroke color 00398 * rg _ set fill color 00399 * S - Stroke path 00400 * s - Close and stroke a path (same is "h S") 00401 * scn - something to do with face patterns 00402 * Tf - font size (in points) 00403 * W - marks the current path as the clipping path and intersects it with the current clipping path 00404 * w - line weight 00405 00406 ***************************** 00407 * PDF Drawing commands 00408 ****************************/ 00409 00410 Graphics() {}; 00411 00412 Graphics(Graphics const & g) 00413 { 00414 m_stream << g.m_stream.str(); 00415 }; 00416 00417 Graphics const operator = (Graphics const & rhs) 00418 { 00419 m_stream << rhs.m_stream.str(); 00420 return *this; 00421 }; 00422 00423 friend class Dict; 00424 00425 Graphics & Exlicit(string const & cmd) 00426 { 00427 m_stream.write(cmd.c_str(), static_cast<streamsize>(cmd.length())); 00428 m_stream << endl; 00429 return *this; 00430 }; 00431 00432 Graphics & PushGraphicsState() {m_stream << 'q' << endl;return *this;}; 00433 Graphics & PopGraphicsState() {m_stream << 'Q' << endl;return *this;}; 00434 00435 Graphics & PenPosition(double const x, double const y) 00436 { 00437 m_stream << x << ' ' << y << " m" << endl;return *this; 00438 }; 00439 00440 Graphics & MovePen(double const x, double const y) 00441 { 00442 m_stream << x << ' ' << y << " l" << endl;return *this; 00443 }; 00444 00445 Graphics & StrokeColor(double const r, double const g, double const b) 00446 { 00447 m_stream << r << ' ' << g << ' ' << b << " RG" << endl;return *this; 00448 }; 00449 00450 Graphics & FillColor(double const r, double const g, double const b) 00451 { 00452 m_stream << r << ' ' << g << ' ' << b << " rg" << endl;return *this; 00453 }; 00454 00455 Graphics & FillAndStrokeWR() {m_stream << "B" << endl;return *this;}; 00456 Graphics & FillAndStrokeEO() {m_stream << "B*" << endl;return *this;}; 00457 Graphics & CloseFillAndStrokeWR() {m_stream << "b*" << endl;return *this;}; 00458 Graphics & CloseFillAndStrokeEO() {m_stream << "b*" << endl;return *this;}; 00459 Graphics & FillWR() {m_stream << "f" << endl;return *this;}; 00460 Graphics & FillEO() {m_stream << "f*" << endl;return *this;}; 00461 Graphics & CompletePath() {m_stream << "h" << endl;return *this;}; 00462 Graphics & Stroke() {m_stream << "S" << endl;return *this;}; 00463 Graphics & CompleteAndStroke() {m_stream << "s" << endl;return *this;}; 00464 00465 Graphics & BeginText(double const x, double const y, Name const & font_name, double const points) 00466 { 00467 Font(font_name, points); 00468 m_stream << "BT " << x << ' ' << y << " Td ";return *this; 00469 }; 00470 00471 template <typename T> 00472 Graphics & InsertText(T const & text) 00473 { 00474 write_string(m_stream, text); 00475 m_stream << " Tj " << endl; 00476 return *this; 00477 } 00478 00479 Graphics & InsertText(double const x, double const y, string const & text) 00480 { 00481 m_stream << x << ' ' << y << " Td "; 00482 InsertText(text); 00483 return *this; 00484 }; 00485 00486 Graphics & InsertText(double const x, double const y, wstring const & text) 00487 { 00488 m_stream << x << ' ' << y << " Td "; 00489 InsertText(text); 00490 return *this; 00491 }; 00492 00493 Graphics & EndText() 00494 { 00495 m_stream << "ET" << endl;return *this; 00496 } 00497 00498 Graphics & InsertImageRGB(double left, double right, double bottom, double top, 00499 int const w, int const h, void const * image) 00500 { 00501 m_stream << "q " << right-left << " 0 0 " << top-bottom << ' ' << left 00502 << ' ' << bottom << " cm "; 00503 m_stream << "BI /W " << w << " /H " << h << " /CS /RGB /BPC 8 ID "; 00504 m_stream.write(static_cast<char const*>(image), static_cast<streamsize>(w*h*3)); 00505 m_stream << "EI Q" << endl;return *this; 00506 }; 00507 00508 }; 00509 00510 class Dict : public BaseObject 00511 { 00512 private: 00513 int m_id; 00514 File * m_file; 00515 stringstream *m_stream; 00516 map < Name, BaseObject * >m_items; 00517 00518 void *operator new (size_t size) 00519 { 00520 return malloc (size); 00521 }; 00522 00523 void operator delete (void *p) 00524 { 00525 free (p); 00526 }; 00527 00528 void write (ostream & out) const 00529 { 00530 out << m_id << " 0 R"; 00531 }; 00532 00533 void write_direct (ostream & out) const; 00534 void really_write (ostream & out) const; 00535 00536 bool managed () const 00537 { 00538 return true; 00539 }; 00540 00541 BaseObject *clone () const 00542 { 00543 // TODO: this isn't really a clone. 00544 return static_cast < BaseObject * >(const_cast < Dict * >(this)); 00545 }; 00546 00547 void release () 00548 { 00549 map < Name, BaseObject * >::iterator iter = m_items.begin (); 00550 while (iter != m_items.end ()) 00551 { 00552 if (!iter->second->managed ()) 00553 iter->second->release (); 00554 ++iter; 00555 } 00556 }; 00557 00558 public: 00559 friend class File; 00560 00561 Dict (File * pdf_file, int id):m_id (id), m_file (pdf_file), m_stream (0) 00562 { 00563 }; 00564 00565 ~Dict () 00566 { 00567 delete m_stream; 00568 }; 00569 00570 Array *newArray () const; 00571 Array *newArray (Name const &); 00572 template <typename T> 00573 Array *newArray (T const *, T const *) const; 00574 template <typename T> 00575 Array *newArray (Name const &, T const *, T const *); 00576 Dict *newDict () const; 00577 Dict *newDict (Name const &); 00578 00579 template <typename T1> bool get(Name const & key, Array *& value_out) 00580 { 00581 bool retval = false; 00582 map < Name, BaseObject * >::const_iterator iter = m_items.find (key); 00583 if(iter != m_items.end()) 00584 { 00585 //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS. 00586 //T1 value = dynamic_cast<T1>(iter->second); 00587 T1 value = static_cast<T1>(iter->second); 00588 if(value) 00589 { 00590 value_out = value; 00591 retval = true; 00592 } 00593 } 00594 return retval; 00595 } 00596 00597 template <typename T1> bool get(Name const & key, Dict *& value_out) 00598 { 00599 bool retval = false; 00600 map < Name, BaseObject * >::const_iterator iter = m_items.find (key); 00601 if(iter != m_items.end()) 00602 { 00603 //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS. 00604 //T1 value = dynamic_cast<T1>(iter->second); 00605 T1 value = static_cast<T1>(iter->second); 00606 if(value) 00607 { 00608 value_out = value; 00609 retval = true; 00610 } 00611 } 00612 return retval; 00613 } 00614 00615 template <typename T1, typename T2> bool get(Name const & key, T2 & value_out) const 00616 { 00617 bool retval = false; 00618 map < Name, BaseObject * >::const_iterator iter = m_items.find (key); 00619 if(iter != m_items.end()) 00620 { 00621 //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS. 00622 //T1 const * value = dynamic_cast<T1*>(iter->second); 00623 T1 const * value = static_cast<T1*>(iter->second); 00624 if(value) 00625 { 00626 value_out = *value; 00627 retval = true; 00628 } 00629 } 00630 return retval; 00631 } 00632 00633 Dict * appendStream (Graphics g) 00634 { 00635 if (!m_stream) 00636 m_stream = new stringstream(stringstream::binary | 00637 stringstream::in | 00638 stringstream::out); 00639 else 00640 *m_stream << ' '; 00641 00642 char buffer[EZPDF_BUFFER_SIZE]; 00643 g.m_stream.read (buffer, 00644 static_cast < streamsize > (EZPDF_BUFFER_SIZE)); 00645 while (g.m_stream.gcount () > 0) 00646 { 00647 m_stream->write (buffer, g.m_stream.gcount ()); 00648 g.m_stream.read (buffer, 00649 static_cast < streamsize > (EZPDF_BUFFER_SIZE)); 00650 } 00651 return this; 00652 } 00653 00654 Dict * appendStream (void const *begin, size_t size) 00655 { 00656 if (!m_stream) 00657 m_stream = new stringstream(stringstream::binary | 00658 stringstream::in | 00659 stringstream::out); 00660 m_stream->write (static_cast<char const*>(begin), static_cast<streamsize>(size)); 00661 return this; 00662 }; 00663 00664 int streamSize () const 00665 { 00666 int retval = 0; 00667 if (m_stream) 00668 retval = m_stream->tellp (); 00669 return retval; 00670 }; 00671 00672 Dict * remove (Name const &n) 00673 { 00674 map < Name, BaseObject * >::iterator iter = m_items.find (n); 00675 if(iter != m_items.end()){ 00676 if(!iter->second->managed()){ 00677 iter->second->release(); 00678 } 00679 m_items.erase(n); 00680 } 00681 return this; 00682 }; 00683 00684 Dict * insert (Name const &n, Array * value); 00685 00686 Dict * insert (Name const &n, int value) 00687 { 00688 remove(n); 00689 BaseObject *b = new Int (value); 00690 m_items.insert (make_pair (n, b)); 00691 return this; 00692 }; 00693 00694 Dict * insert (Name const &n, float value) 00695 { 00696 remove(n); 00697 BaseObject *b = new Float (value); 00698 m_items.insert (make_pair (n, b)); 00699 return this; 00700 }; 00701 00702 Dict * insert (Name const &n, double value) 00703 { 00704 remove(n); 00705 BaseObject *b = new Float (value); 00706 m_items.insert (make_pair (n, b)); 00707 return this; 00708 }; 00709 00710 Dict * insert (Name const &n, long value) 00711 { 00712 remove(n); 00713 BaseObject *b = new Int (value); 00714 m_items.insert (make_pair (n, b)); 00715 return this; 00716 }; 00717 00718 Dict * insert (Name const &n, size_t value) 00719 { 00720 remove(n); 00721 BaseObject *b = new Int (static_cast<long>(value)); 00722 m_items.insert (make_pair (n, b)); 00723 return this; 00724 }; 00725 00726 Dict * insert (Name const &n, bool value) 00727 { 00728 remove(n); 00729 BaseObject *b = new Boolean (value); 00730 m_items.insert (make_pair (n, b)); 00731 return this; 00732 }; 00733 00734 Dict * insert (Name const &n, WString const &value) 00735 { 00736 remove(n); 00737 BaseObject *b = new WString (value); 00738 m_items.insert (make_pair (n, b)); 00739 return this; 00740 }; 00741 00742 Dict * insert (Name const &n, String const &value) 00743 { 00744 remove(n); 00745 BaseObject *b = new String (value); 00746 m_items.insert (make_pair (n, b)); 00747 return this; 00748 }; 00749 00750 Dict * insert (Name const &n, Name const &value) 00751 { 00752 remove(n); 00753 BaseObject *b = new Name (value); 00754 m_items.insert (make_pair (n, b)); 00755 return this; 00756 }; 00757 00758 Dict * insert (Name const &n, Dict const * value) 00759 { 00760 remove(n); 00761 Dict * d = const_cast<Dict*>(value); 00762 m_items.insert (make_pair (n, static_cast < BaseObject * >(d))); 00763 return this; 00764 }; 00765 00766 }; 00767 00768 class Array:public BaseObject 00769 { 00770 private: 00771 vector < BaseObject * >m_items; 00772 00773 void clear () 00774 { 00775 for (unsigned int i = 0; i < m_items.size (); ++i) 00776 { 00777 if (!m_items[i]->managed ()) 00778 { 00779 m_items[i]->release (); 00780 } 00781 } 00782 m_items.clear (); 00783 }; 00784 00785 void *operator new (size_t size) 00786 { 00787 return malloc (size); 00788 }; 00789 00790 void operator delete (void *p) 00791 { 00792 free (p); 00793 }; 00794 00795 00796 BaseObject *clone () const 00797 { 00798 Array *tmp = new Array; 00799 *tmp = *this; 00800 return tmp; 00801 }; 00802 00803 void write (ostream & out) const 00804 { 00805 out << '['; 00806 if (!m_items.empty ()){ 00807 m_items[0]->write (out); 00808 for (unsigned int i = 1; i < m_items.size (); ++i) 00809 { 00810 out << ' '; 00811 m_items[i]->write (out); 00812 } 00813 } 00814 out << ']'; 00815 }; 00816 00817 void release () 00818 { 00819 clear(); 00820 }; 00821 00822 bool managed () const 00823 { 00824 return true; 00825 }; 00826 00827 ~Array () 00828 { 00829 clear (); 00830 }; 00831 00832 Array () 00833 { 00834 }; 00835 00836 Array (int const *begin, int const *end) 00837 { 00838 insert (begin, end); 00839 }; 00840 00841 Array (float const *begin, float const *end) 00842 { 00843 insert (begin, end); 00844 }; 00845 00846 Array (bool const *begin, bool const *end) 00847 { 00848 insert (begin, end); 00849 }; 00850 00851 Array (WString const *begin, WString const *end) 00852 { 00853 insert (begin, end); 00854 }; 00855 00856 Array (String const *begin, String const *end) 00857 { 00858 insert (begin, end); 00859 }; 00860 00861 Array (Name const *begin, Name const *end) 00862 { 00863 insert (begin, end); 00864 }; 00865 00866 Array (Dict ** begin, Dict ** end) 00867 { 00868 insert (begin, end); 00869 }; 00870 00871 Array (Array * begin, Array * end) 00872 { 00873 insert (begin, end); 00874 }; 00875 public: 00876 friend class File; 00877 00878 template <typename T1> bool get(unsigned int index, Dict *& value_out) 00879 { 00880 bool retval = false; 00881 if(index < m_items.size()) 00882 { 00883 BaseObject * bo = m_items[index]; 00884 //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS. 00885 //T1 value = dynamic_cast<T1>(bo); 00886 T1 value = static_cast<T1>(bo); 00887 if(value) 00888 { 00889 value_out = value; 00890 retval = true; 00891 } 00892 } 00893 return retval; 00894 } 00895 00896 template <typename T1, typename T2> bool get(unsigned int index, T2 & value_out) const 00897 { 00898 bool retval = false; 00899 if(index < m_items.size()) 00900 { 00901 BaseObject * bo = m_items[index]; 00902 //We really need to use a dynamic_cast here, but no RTTI yet in HOOPS. 00903 //T1 * value = dynamic_cast<T1*>(bo); 00904 T1 * value = static_cast<T1*>(bo); 00905 if(value) 00906 { 00907 value_out = *value; 00908 retval = true; 00909 } 00910 } 00911 return retval; 00912 } 00913 00914 size_t size () const 00915 { 00916 return m_items.size (); 00917 }; 00918 00919 void remove (unsigned int const index) 00920 { 00921 if(index < m_items.size()){ 00922 00923 if(!m_items[index]->managed()) 00924 m_items[index]->release(); 00925 00926 m_items.erase(m_items.begin() + index); 00927 } 00928 }; 00929 00930 Array & insert (int value) 00931 { 00932 m_items.push_back (new Int (value)); 00933 return *this; 00934 }; 00935 00936 Array & insert (float value) 00937 { 00938 m_items.push_back (new Float (value)); 00939 return *this; 00940 }; 00941 00942 Array & insert (double value) 00943 { 00944 m_items.push_back (new Float (value)); 00945 return *this; 00946 }; 00947 00948 Array & insert (bool value) 00949 { 00950 m_items.push_back (new Boolean (value)); 00951 return *this; 00952 }; 00953 00954 Array & insert (WString const &value) 00955 { 00956 m_items.push_back (new WString (value)); 00957 return *this; 00958 }; 00959 00960 Array & insert (String const &value) 00961 { 00962 m_items.push_back (new String (value)); 00963 return *this; 00964 }; 00965 00966 Array & insert (Name const &value) 00967 { 00968 m_items.push_back (new Name (value)); 00969 return *this; 00970 }; 00971 00972 Array & insert (Dict * value) 00973 { 00974 m_items.push_back (value); 00975 return *this; 00976 }; 00977 00978 Array & insert (Array * value) 00979 { 00980 m_items.push_back (value); 00981 return *this; 00982 }; 00983 00984 Array & insert (int const *begin, int const *end) 00985 { 00986 while (begin != end) 00987 { 00988 m_items.push_back (new Int (*begin)); 00989 ++begin; 00990 } 00991 return *this; 00992 }; 00993 00994 Array & insert (float const *begin, float const *end) 00995 { 00996 while (begin != end) 00997 { 00998 m_items.push_back (new Float (*begin)); 00999 ++begin; 01000 } 01001 return *this; 01002 }; 01003 01004 Array & insert (bool const *begin, bool const *end) 01005 { 01006 while (begin != end) 01007 { 01008 m_items.push_back (new Boolean (*begin)); 01009 ++begin; 01010 } 01011 return *this; 01012 }; 01013 01014 Array & insert (WString const *begin, WString const *end) 01015 { 01016 while (begin != end) 01017 { 01018 m_items.push_back (new WString (*begin)); 01019 ++begin; 01020 } 01021 return *this; 01022 }; 01023 01024 Array & insert (String const *begin, String const *end) 01025 { 01026 while (begin != end) 01027 { 01028 m_items.push_back (new String (*begin)); 01029 ++begin; 01030 } 01031 return *this; 01032 }; 01033 01034 Array & insert (Name const *begin, Name const *end) 01035 { 01036 while (begin != end) 01037 { 01038 m_items.push_back (new Name (*begin)); 01039 ++begin; 01040 } 01041 return *this; 01042 }; 01043 01044 Array & insert (Dict ** begin, Dict ** end) 01045 { 01046 while (begin != end) 01047 { 01048 m_items.push_back (*begin); 01049 ++begin; 01050 } 01051 return *this; 01052 }; 01053 01054 Array & insert (Array *begin, Array *end) 01055 { 01056 while (begin != end) 01057 { 01058 m_items.push_back (begin); 01059 ++begin; 01060 } 01061 return *this; 01062 }; 01063 }; 01064 01065 Dict * Dict::insert (Name const &n, Array * value) 01066 { 01067 remove(n); 01068 m_items.insert (make_pair (n, static_cast<BaseObject*>(value))); 01069 return this; 01070 }; 01071 01072 class File : public BaseObject 01073 { 01074 private: 01075 int m_object_count; 01076 mutable Dict * m_ptrailer; 01077 float m_version; 01078 map < int, long > m_xrefs; 01079 vector < Dict * > m_dictionaries; 01080 vector < Array * > m_arrays; 01081 ofstream m_out; 01082 01083 BaseObject *clone () const 01084 { 01085 return 0; 01086 }; 01087 01088 void write (ostream & out) const 01089 { 01090 out << "%PDF-" << m_version; 01091 01092 for (unsigned int i = 0; i < m_dictionaries.size (); ++i) 01093 { 01094 m_dictionaries[i]->really_write (out); 01095 } 01096 01097 out << "\n\n\n"; 01098 long xref_fpos = out.tellp (); 01099 out << "xref" << endl; 01100 out << "0 " << m_object_count << endl; 01101 01102 char cur_fill = out.fill (); 01103 out.fill ('0'); 01104 01105 for (int i = 0; i < m_object_count; ++i) 01106 { 01107 map < int, long >::const_iterator iter = m_xrefs.find (i); 01108 if (iter == m_xrefs.end ()) 01109 out << "0000000000 65535 f " << endl; 01110 else 01111 out << setw (10) << iter->second << " 00000 n " << endl; 01112 } 01113 out.fill (cur_fill); 01114 01115 m_ptrailer->insert("Size", m_object_count); 01116 out << "\n\n" << "trailer" << endl; 01117 m_ptrailer->write_direct(out); 01118 out << "\n\n\n"; 01119 01120 out << "startxref" << endl << xref_fpos << endl << "%%EOF"; 01121 01122 if(out.fail()) 01123 throw false; 01124 }; 01125 01126 void release () 01127 { 01128 }; 01129 01130 public: 01131 friend class Dict; 01132 01133 explicit File (string const & filename):m_object_count (1), m_ptrailer(0), 01134 m_version (1.7f), m_out (filename.c_str(), ios::out | ios::binary) 01135 { 01136 }; 01137 01138 explicit File (wstring const & filename):m_object_count (1), m_ptrailer(0), 01139 m_version (1.7f) 01140 { 01141 #if _MSC_VER 01142 m_out.open(filename.c_str(), ios::out | ios::binary); 01143 #else 01144 int len = wcstombs(0, filename.c_str(), 0) +1; 01145 char * tmp = new char[len]; 01146 char const * const old_loc = setlocale(LC_CTYPE, ""); 01147 wcstombs(tmp, filename.c_str(), len); 01148 setlocale(LC_CTYPE, old_loc); 01149 m_out.open(tmp, ios::out | ios::binary); 01150 delete [] tmp; 01151 #endif 01152 }; 01153 01154 ~File () 01155 { 01156 if(m_ptrailer) 01157 m_ptrailer->release (); 01158 delete m_ptrailer; 01159 01160 for (unsigned int i = 0; i < m_dictionaries.size (); ++i) 01161 { 01162 m_dictionaries[i]->release (); 01163 } 01164 01165 for (unsigned int i = 0; i < m_arrays.size(); ++i) 01166 { 01167 m_arrays[i]->release(); 01168 } 01169 01170 for (unsigned int i = 0; i < m_dictionaries.size (); ++i) 01171 { 01172 delete m_dictionaries[i]; 01173 } 01174 01175 for (unsigned int i = 0; i < m_arrays.size(); ++i) 01176 { 01177 delete m_arrays[i]; 01178 } 01179 }; 01180 01181 void close () { 01182 if(m_out.is_open()){ 01183 write(m_out); 01184 } 01185 m_out.close(); 01186 }; 01187 01188 template <typename T1> bool get(Name const & key, Dict *& value_out) 01189 { 01190 return m_ptrailer->get<T1> (key, value_out); 01191 } 01192 01193 template <typename T1, typename T2> bool get(Name const & key, T2 & value_out) const 01194 { 01195 return m_ptrailer->get<T1> (key, value_out); 01196 } 01197 01198 Array * newArray () 01199 { 01200 Array *retval = new Array; 01201 m_arrays.push_back (retval); 01202 return retval; 01203 }; 01204 01205 template <typename T> 01206 Array * newArray (T const * begin, T const * end) 01207 { 01208 Array *retval = new Array(begin, end); 01209 m_arrays.push_back (retval); 01210 return retval; 01211 } 01212 01213 Dict *newDict () 01214 { 01215 Dict *retval = new Dict (this, m_object_count++); 01216 m_dictionaries.push_back (retval); 01217 return retval; 01218 } 01219 01220 Dict *newDict (Name const & n) 01221 { 01222 Dict *retval = new Dict (this, m_object_count++); 01223 m_dictionaries.push_back (retval); 01224 if(!m_ptrailer) 01225 m_ptrailer = new Dict(this, 0); 01226 m_ptrailer->insert(n, retval); 01227 return retval; 01228 } 01229 }; 01230 01231 Array * Dict::newArray() const 01232 { 01233 return m_file->newArray(); 01234 }; 01235 01236 Array * Dict::newArray(Name const & n) 01237 { 01238 Array * retval = newArray(); 01239 insert(n, retval); 01240 return retval; 01241 }; 01242 01243 template <typename T> 01244 Array * Dict::newArray(T const * begin, T const * end) const 01245 { 01246 return m_file->newArray(begin, end); 01247 } 01248 01249 template <typename T> 01250 Array * Dict::newArray(Name const & n, T const * begin, T const * end) 01251 { 01252 Array * retval = newArray(begin, end); 01253 insert(n, retval); 01254 return retval; 01255 } 01256 01257 Dict * Dict::newDict() const 01258 { 01259 Dict *retval = new Dict (m_file, m_file->m_object_count++); 01260 m_file->m_dictionaries.push_back (retval); 01261 return retval; 01262 }; 01263 01264 Dict * Dict::newDict(Name const & n) 01265 { 01266 Dict *retval = newDict(); 01267 insert(n, retval); 01268 return retval; 01269 }; 01270 01271 void Dict::write_direct (ostream & out) const 01272 { 01273 out << "<<"; 01274 01275 map < Name, BaseObject * >::const_iterator iter = m_items.begin (); 01276 while (iter != m_items.end ()) 01277 { 01278 out << endl; 01279 iter->first.write (out); 01280 out << ' '; 01281 iter->second->write (out); 01282 ++iter; 01283 } 01284 01285 out << endl << ">>"; 01286 }; 01287 01288 void Dict::really_write (ostream & out) const 01289 { 01290 if (m_file->m_xrefs.find (m_id) == m_file->m_xrefs.end ()) 01291 { 01292 01293 out << "\n\n\n"; 01294 long dict_fpos = out.tellp (); 01295 m_file->m_xrefs.insert (make_pair (m_id, dict_fpos)); 01296 out << m_id << " 0 obj\n"; 01297 01298 write_direct(out); 01299 01300 out << endl; 01301 01302 if (m_stream) 01303 { 01304 out << "stream" << endl; 01305 char buffer[EZPDF_BUFFER_SIZE]; 01306 m_stream->read (buffer, 01307 static_cast < streamsize > (EZPDF_BUFFER_SIZE)); 01308 while (m_stream->gcount () > 0) 01309 { 01310 out.write (buffer, m_stream->gcount ()); 01311 m_stream->read (buffer, 01312 static_cast < streamsize > 01313 (EZPDF_BUFFER_SIZE)); 01314 } 01315 out << endl << "endstream" << endl; 01316 } 01317 01318 out << "endobj"; 01319 } 01320 }; 01321 01322 namespace filters { 01323 class filter { 01324 public: 01325 virtual ~filter() {}; 01326 virtual filter & read(void*, streamsize) = 0; 01327 virtual filter & write(void const *, streamsize) = 0; 01328 virtual streamsize gcount() const = 0; 01329 virtual char const * name() const = 0; 01330 }; 01331 01332 class zlib : public filter { 01333 public: 01334 zlib() : m_reading(false){ 01335 m_zstrm.zalloc = Z_NULL; 01336 m_zstrm.zfree = Z_NULL; 01337 m_zstrm.data_type = Z_ASCII; 01338 m_zstrm.next_out = 0; 01339 m_zstrm.avail_out = 0; 01340 m_zstrm.next_in = 0; 01341 m_zstrm.avail_in = 0; 01342 if(deflateInit(&m_zstrm, Z_BEST_COMPRESSION) != Z_OK){ 01343 assert(0); 01344 } 01345 }; 01346 01347 ~zlib() { 01348 deflateEnd(&m_zstrm); 01349 }; 01350 01351 filter & read(void * out, streamsize howmuch) { 01352 if(!m_reading){ 01353 char buffer[EZPDF_BUFFER_SIZE]; 01354 int rc; 01355 01356 do{ 01357 m_zstrm.next_out = (Bytef*)(&buffer[0]); 01358 m_zstrm.avail_out = EZPDF_BUFFER_SIZE; 01359 rc = deflate(&m_zstrm, Z_FINISH); 01360 01361 int have = EZPDF_BUFFER_SIZE - m_zstrm.avail_out; 01362 if(have){ 01363 m_buf.write(buffer, have); 01364 } 01365 }while(rc != Z_STREAM_END); 01366 m_reading = true; 01367 } 01368 01369 m_buf.read((char*)out, howmuch); 01370 return *this; 01371 }; 01372 01373 filter & write(void const * in, streamsize howmuch) { 01374 if(!m_reading){ 01375 m_zstrm.next_in = const_cast<Bytef*>(static_cast<Bytef const*>(in)); 01376 m_zstrm.avail_in = howmuch; 01377 01378 char buffer[EZPDF_BUFFER_SIZE]; 01379 01380 m_zstrm.next_out = (Bytef*)(&buffer[0]); 01381 m_zstrm.avail_out = EZPDF_BUFFER_SIZE; 01382 01383 while(m_zstrm.avail_in > 0){ 01384 int rc = deflate(&m_zstrm, Z_NO_FLUSH); 01385 if(rc != Z_OK) 01386 assert(0); 01387 01388 int have = EZPDF_BUFFER_SIZE - m_zstrm.avail_out; 01389 if(have){ 01390 m_buf.write(buffer, have); 01391 m_zstrm.next_out = (Bytef*)(&buffer[0]); 01392 m_zstrm.avail_out = EZPDF_BUFFER_SIZE; 01393 } 01394 } 01395 int have = EZPDF_BUFFER_SIZE - m_zstrm.avail_out; 01396 if(have){ 01397 m_buf.write(buffer, have); 01398 } 01399 } 01400 01401 return *this; 01402 }; 01403 01404 streamsize gcount() const { 01405 return m_buf.gcount(); 01406 }; 01407 01408 char const * name() const {return "FlateDecode";}; 01409 01410 private: 01411 std::stringstream m_buf; 01412 struct z_stream_s m_zstrm; 01413 bool m_reading; 01414 }; 01415 } 01416 }; 01417 01418 01419 #ifdef H_PACK_8 01420 #pragma pack(pop) 01421 #endif 01422 01423 #endif 01424 01425 #endif