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