Alphabetical Class Index  Class Hierarchy   File Members   Compound Members   File List  

ezpdf.h
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