/* * PDFedit - free program for PDF document manipulation. * Copyright (C) 2006, 2007 PDFedit team: Michal Hocko, * Miroslav Jahoda, * Jozef Misutka, * Martin Petricek * * Project is hosted on http://sourceforge.net/projects/pdfedit */ // vim:tabstop=4:shiftwidth=4:noexpandtab:textwidth=80 /* * ===================================================================================== * Filename: cobjectsimple.h * Description: Header file containing definition of simple cobjects. * Created: 01/18/2006 * Author: jmisutka (06/01/19), * * ===================================================================================== */ #ifndef _COBJECTSIMPLE_H #define _COBJECTSIMPLE_H // all basic includes #include "static.h" #include "iproperty.h" //===================================================================================== namespace pdfobjects { //===================================================================================== /** * CObjectSimple type trait. * * This is an advance c++ template technique which allows us to store * additional information that identify variable type (e.g. function type specification of a function template -- * method in a template class). * * If someone tries to use unsupported type (e.g pCmd, etc.), she should get compile error * because PropertyTraitSimple<> has no body. * * REMARK: BE CAREFUL when manipulating these ones. Small change could resulting * in an error could be very difficult to find. * * \see CDict, CArray, CObjectStream */ template struct PropertyTraitSimple; template<> struct PropertyTraitSimple { public: typedef NullType value; public: typedef NullType writeType; }; template<> struct PropertyTraitSimple { public: typedef bool value; public: typedef bool writeType; }; template<> struct PropertyTraitSimple { public: typedef int value; public: typedef int writeType; }; template<> struct PropertyTraitSimple { public: typedef double value; public: typedef double writeType; }; template<> struct PropertyTraitSimple { public: typedef std::string value; public: typedef const std::string& writeType; }; template<> struct PropertyTraitSimple { public: typedef std::string value; public: typedef const std::string& writeType; }; template<> struct PropertyTraitSimple { public: typedef IndiRef value; public: typedef const IndiRef& writeType; }; //===================================================================================== // CObjectSimple //===================================================================================== /** * Template class representing simple PDF objects from pdf specification v1.5. * * This is a very generic class representing simple objects like null, string, number etc. * Simple types only store information like string, name, number, two numbers etc. * * Other xpdf objects like objCmd can not be instantiated although the PropertyType * exists. It is because PropertyTraitSimple is not specialized for these types. * * This class does not provide default copy constructor because copying a * property could be understood either as deep copy or shallow copy. * Copying complex types could be very expensive so we have made the decision to * avoid it. */ template class CObjectSimple : noncopyable, public IProperty { public: typedef typename PropertyTraitSimple::writeType WriteType; typedef typename PropertyTraitSimple::value Value; typedef observer::BasicChangeContext BasicObserverContext; /** * Type of the property. * Static field common to all simple objects with same type. * This association allows us to get the PropertyType from object type. */ static const PropertyType type = Tp; private: /** Simple value. */ Value value; // // Constructors // public: /** * Constructor. * The object will read value from o and store it. We do NOT save any reference to o. * * @param p Pointer to pdf object. * @param o Xpdf object. * @param rf Indirect id and gen id. */ CObjectSimple (CPdf& p, Object& o, const IndiRef& rf); /** * Constructor. * The object will read value from o and store it. We do NOT save any reference to o. * * @param o Xpdf object. */ CObjectSimple (Object& o); public: /** * Public constructor. Can be used to create pdf objects. This object is created * as a standalone and does not belong to any pdf. When added to a pdf * the relation will be saved to IProperty::pdf. * * @param val Value that will this object hold. */ CObjectSimple (const Value& val = Value()); // // Cloning // protected: /** * Clone. * * Performs deep copy. * REMARK: CRef does NOT copy the referenced object just itself. * * @return Deep copy of this object. */ virtual IProperty* doClone () const; // // Get methods // public: /** * Return type of this property. * * @return Type of this property. */ virtual PropertyType getType () const {return type;} /** * Returns string representation of this object according to pdf * specification. * * @param str Output string that will hold the string representation * of current object. */ virtual void getStringRepresentation (std::string& str) const; /** * Return property value. Each property has its own return type. * * @param val Out parameter where property value will be stored. */ void getValue (Value& val) const; /** * Return property value. Each property has its own return type. * * @return Property value. */ Value getValue () const; // // Set methods // public: /** * Convert string to an object value. * \exception ObjBadValueE Thrown when we can't parse the string correctly. * * @param strO String object that will be parsed and saved to this object's value. */ void setStringRepresentation (const std::string& strO); /** * Change the value of an object. The variable type depends * on CObject type. * * We can define the best type to represent an pdf object in * PropertyTraitSimple. * * \see PropertyTraitSimple * * @param val Value that will be set. */ void setValue (WriteType val); // // Destructor // public: /** * Destructor */ ~CObjectSimple () {} // // Helper methods // public: /** * Make xpdf Object from this object. This function allocates and initializes xpdf object. * Caller has to free the xpdf Object (call Object::free and then * deallocating) * * \exception ObjBadValueE Thrown when xpdf can't parse the string representation of this * object correctly. * * @return Xpdf object representing value of this simple object. */ virtual ::Object* _makeXpdfObject () const; private: /** * Create context of a change. * * REMARK: Be carefull. Deallocate this object. * * @return Context in which a change occured. */ ObserverContext* _createContext () const { // Save original value for the context boost::shared_ptr oldValue (this->clone()); // Set original values oldValue->setPdf (this->getPdf()); oldValue->setIndiRef (this->getIndiRef()); // Create the context return new BasicObserverContext (oldValue); } /** * Indicate that the object has changed. * Notifies all observers associated with this property about the change. * * @param context Context in which a change occured. */ void _objectChanged (boost::shared_ptr context); }; // // Typedefs // typedef CObjectSimple CNull; typedef CObjectSimple CBool; typedef CObjectSimple CInt; typedef CObjectSimple CReal; typedef CObjectSimple CString; typedef CObjectSimple CName; typedef CObjectSimple CRef; //===================================================================================== /** Namespace includes all helper functions and classes.*/ namespace utils { //===================================================================================== //========================================================= // Validate functions //========================================================= /** * Make name valid. * Beginning with PDF 1.2, any character except null (character code 0) may be included in a name by writing its 2-digit hexadecimal code, preceded by the number sign character (#); see implementation notes 3 and 4 in Appendix H. This syntax is required to represent any of the delimiter or white-space characters or the number sign character itself; it is recommended but not required for characters whose codes are outside the range 33 (!) to 126 (~). The examples shown in Table 3.3 are valid literal names in PDF 1.2 and later. * @param it Start iterator. * @param end End iterator. */ template std::string makeNamePdfValid (Iter it, Iter end) { typedef std::string::value_type Item; std::string tmp; for (; it != end; ++it) { if ( '!' > (*it) || '~' < (*it)) { // Convert it to ascii Item a = (Item) (*it) >> sizeof (Item) * 4; Item b = (Item) (*it) & ((unsigned) 1 << sizeof(Item) * 4); tmp += std::string ("#") + a + b; }else tmp += *it; } return tmp; } /** * Make name valid. * Beginning with PDF 1.2, any character except null (character code 0) may be included in a name by writing its 2-digit hexadecimal code, preceded by the number sign character (#); see implementation notes 3 and 4 in Appendix H. This syntax is required to represent any of the delimiter or white-space characters or the number sign character itself; it is recommended but not required for characters whose codes are outside the range 33 (!) to 126 (~). The examples shown in Table 3.3 are valid literal names in PDF 1.2 and later. * @param str Character string. */ inline std::string makeNamePdfValid (const char* str) { return makeNamePdfValid (&str[0], &str[strlen(str)]); } /** * Make string pdf valid. * Any characters may appear in a string except unbalanced parentheses and the backslash, which must be treated specially. * * @param it Start iterator. * @param end End iterator. */ template std::string makeStringPdfValid (Iter it, Iter end) { typedef typename std::string::value_type Item; std::string tmp; for (; it != end; ++it) { if ( '\\' == (*it)) { // Escape every backslash tmp += '\\'; } else if ( '(' == (*it) || ')' == (*it)) { // Prepend \ before ( or ) tmp += '\\'; } tmp += *it; } return tmp; } /** * * Make string pdf valid. * Any characters may appear in a string except unbalanced parentheses and the backslash, which must be treated specially./ * * @param str Character string. */ inline std::string makeStringPdfValid (const char* str) { return makeStringPdfValid (&str[0], &str[strlen(str)]); } //========================================================= // Creation functions //========================================================= /** * Creates CObject* from xpdf object. * * @param pdf Pdf in which the created object will live. Parameter to CObject* constructor. * @param obj Xpdf object from which the object will be created. Parameter to CObject* constructor. * @param ref Indirect reference number of this object (or its parent). * * @return Pointer to newly created object. */ IProperty* createObjFromXpdfObj (CPdf& pdf, ::Object& obj,const IndiRef& ref); /** * Creates CObject* from xpdf object. * * @param obj Xpdf object from which the object will be created. Parameter to CObject* constructor. * * @return Pointer to newly created object. */ IProperty* createObjFromXpdfObj (::Object& obj); /** * Save real xpdf object value to val. * * @param obj Xpdf object which holds the value. * @param val Variable where the value will be stored. */ template void simpleValueFromXpdfObj (::Object& obj, T val); /** * Create xpdf Object which represents value. * * @param val Value where the value is stored. * @return Xpdf object where the value is stored. */ template Object* simpleValueToXpdfObj (T val); /** * Create xpdf object from string. * * @param str String that should represent an xpdf object. * @param xref Xref of actual pdf if any. * * @return Xpdf object whose string representation is in str. */ ::Object* xpdfObjFromString (const std::string& str, ::XRef* xref = NULL); /** * Parses string to get simple values like int, name, bool etc. * * @param str String to be parsed. * @param val Desired value. * * @throw ObjBadValueE Thrown when the string, can't be parsed correctly. */ void simpleValueFromString (const std::string& str, bool& val); void simpleValueFromString (const std::string& str, int& val); void simpleValueFromString (const std::string& str, double& val); void simpleValueFromString (const std::string& str, std::string& val); void simpleValueFromString (const std::string& str, IndiRef& val); //========================================================= // To string functions //========================================================= /** * Return simple xpdf object (null,number,string...) in string representation. * * REMARK: String can represent more different objects, so we have to distinguish among them. * This is done at compile time with use of templates, but because of this we have to * make other functions also template. * * @param val that will be converted to string. * @param str string */ template void simpleValueToString (bool val, std::string& str); /** \copydoc simpleValueToString */ template void simpleValueToString (int val,std::string& str); /** \copydoc simpleValueToString */ template void simpleValueToString (double val,std::string& str); /** \copydoc simpleValueToString */ template void simpleValueToString (const std::string& val,std::string& str); /** \copydoc simpleValueToString */ template void simpleValueToString (const NullType& val,std::string& str); /** \copydoc simpleValueToString */ template void simpleValueToString (const IndiRef& val,std::string& str); //========================================================= // From string functions //========================================================= /** * Create text representation of an indirect object from string and IndiRef. * * @param rf IndiRef. * @param val Value of an object. * @param output Output string. */ void createIndirectObjectStringFromString (const IndiRef& rf, const std::string& val, std::string& output); //========================================================= // Other functions //========================================================= /** * Free an object. We assume that all child objects (if any) * have been already freed. * * Copy & paste from Object.h * * @param obj Object to be freed. */ void freeXpdfObject (Object* obj); /** * Returns true if object has a parent. * * \exception ObjInvalidOperation Thrown when the object does not belong * to a valid pdf. * * @param ip IProperty of object. */ bool objHasParent (const IProperty& ip); /** * Returns true if object has a parent. * * \exception ObjInvalidOperation Thrown when the object does not belong * to a valid pdf. * * @param ip IProperty of object. * @param indiObj Out parameter wheren indirect object will be saved, because * finding the object can be an expensive operation. */ bool objHasParent (const IProperty& ip, boost::shared_ptr& indiObj); //========================================================= // CObject* "delegate" helper methods //========================================================= /** * If the object is a reference, fetch the "real" object * * @param ip IProperty. */ boost::shared_ptr getReferencedObject (boost::shared_ptr ip); //========================================================= // CObjectSimple "get value" helper methods //========================================================= /** * Get simple value from simple cobject. * * @param ip IProperty. * * @return Value. */ template inline Value getValueFromSimple (const boost::shared_ptr& ip) __attribute__((deprecated)); // function definition (gcc doesn't like __attribute__ in function definition template inline Value getValueFromSimple (const boost::shared_ptr& ip) { if (ItemPType == ip->getType ()) { // Cast it to the correct type and return it boost::shared_ptr item = IProperty::getSmartCObjectPtr (ip); return item->getValue (); }else { utilsPrintDbg (debug::DBG_DBG, "wanted type " << ItemPType << " got " << ip->getType ()); throw ElementBadTypeException ("getValueFromSimple"); } } /** * Get simple value from simple cobject. * * Given property must have correct type (ItemType::type). * * @param ip IProperty. * * @return Value. */ template inline typename ItemType::Value getValueFromSimple (const boost::shared_ptr& ip) { if (ItemType::type == ip->getType ()) { // Cast it to the correct type and return it boost::shared_ptr item = IProperty::getSmartCObjectPtr (ip); return item->getValue (); }else { utilsPrintDbg (debug::DBG_DBG, "wanted type " << ItemType::type << " got " << ip->getType ()); throw ElementBadTypeException ("getValueFromSimple"); } } /** Get int from ip. */ inline int getIntFromIProperty (const boost::shared_ptr& ip) {return getValueFromSimple (ip);} /** Get double from ip. */ inline double getDoubleFromIProperty (const boost::shared_ptr& ip) { return (isInt (ip)) ? getValueFromSimple (ip) : getValueFromSimple (ip); } /** Get string from ip. */ inline std::string getStringFromIProperty (const boost::shared_ptr& ip) {return getValueFromSimple (ip);} /** Get name from ip. */ inline std::string getNameFromIProperty (const boost::shared_ptr& ip) {return getValueFromSimple (ip);} //========================================================= // CObjectSimple "set value" helper methods //========================================================= /** * Set simple value. * * @param ip IProperty. * @param val Value to set. */ template inline void setValueToSimple (const boost::shared_ptr& ip, const Value& val) { if (ItemPType != ip->getType ()) { utilsPrintDbg (debug::DBG_DBG, "wanted type " << ItemPType << " got " << ip->getType ()); throw ElementBadTypeException (""); } // Cast it to the correct type and set value boost::shared_ptr item = IProperty::getSmartCObjectPtr (ip); item->setValue (val); } //===================================================================================== } /* namespace utils */ //===================================================================================== } /* namespace pdfobjects */ //===================================================================================== // // Include the actual implementation of CObject class // #include "cobjectsimpleI.h" #endif // _COBJECTSIMPLE_H