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