/* * 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: stateupdater.cc * Created: 06/10/2006 10:33:34 PM CET * Author: jmisutka, mjahoda * ===================================================================================== */ #ifndef _STATEUPDATER_H_ #define _STATEUPDATER_H_ // static #include "static.h" #include "pdfoperators.h" //========================================================== namespace pdfobjects { //========================================================== /** * Graphical state updater. * * Content stream is a sequence of operations which alter graphical state. We * need to obtain some information after each of these operations and xpdf code * is no suitable for this sort of things. * * If appropriate functions are defined, this mechanism could be used to display * the content stream. E.g. we update op*Update functions to call output device. */ class StateUpdater { typedef PdfOperator::BBox BBox; private: /** Maximum argument count of an operator. See pdf specfication of all operators.*/ static const size_t MAX_OPERANDS = 6; /** Maximum operator name length. See pdf specification of all operators.*/ static const size_t MAX_OPERATOR_NAMELEN = 4; public: /** * Structure representing one operator. * * It is used to find an update function, which alters graphical state * according to the operator and its operands. * * It is also used to check whether the operand count and type match the pdf specification * of an operator. It the argument number is less than zero, arbitrary * number of operands is allowed up to the absolute value of argNum. * * If the operator is a composite, endTag is the string representation of * the ending operator of the composite. */ typedef struct { char name[MAX_OPERATOR_NAMELEN]; /**< Operator name. */ int argNum; /**< Number of operator arguments. */ unsigned short types[MAX_OPERANDS]; /**< Bits represent which types are allowed. */ /** Function to execute when updating position. */ GfxState* (*update) (GfxState* , boost::shared_ptr, const boost::shared_ptr, const PdfOperator::Operands&, BBox* rc); char endTag[MAX_OPERATOR_NAMELEN]; /**< If it is a complex type, its end tag.*/ } CheckTypes; protected: /** * All known operators from pdf specification and their update functions. * * If an operator does not have any effect on graphical state, default * update function is used. * * Operator number can be either >0, zero, <0. Zero means no operands are * needed. >0 means that exact argNum of operands are needed. <0 means that * at most argNum operands are needed. */ static CheckTypes KNOWN_OPERATORS[]; // // Default update // public: static GfxState* unknownUpdate (GfxState* state, boost::shared_ptr, const boost::shared_ptr, const PdfOperator::Operands&, BBox* rc); // // Accessors // public: /** * Find operator specification. * * @param name Name of the operator. */ static const CheckTypes* findOp (const std::string& name); /** * Get end tag of an operator. * * @param name Operator name. * * @return Operator end tag. Can be empty. */ static std::string getEndTag (const std::string& name); public: /** * Update pdf operators. * * REMARK: State is not gfx changed in this function. We can not make it * const because of the xpdf code. * * @param it Iterator that will be used to traverse all operators. * @param res Graphical resources. * @param state Graphical state. * @param ftor Functor applied after each update. */ template static boost::shared_ptr updatePdfOperators (PdfOperator::Iterator it, boost::shared_ptr res, /*const*/ GfxState& state, Ftor ftor) { assert (!state.isPath()); // if isPath, state is from other ccontentstream or is bad GfxState* tmpstate = state.copy (false); assert (tmpstate); utilsPrintDbg (debug::DBG_DBG, ""); boost::shared_ptr op; BBox rc; // Init ftor ftor (res); // Init global variables xpdf::openXpdfMess (); while (!it.isEnd ()) { op = it.getCurrent(); // Get operator name std::string frst; op->getOperatorName(frst); // Get operator specification const CheckTypes* chcktp = findOp (frst); // Get operands PdfOperator::Operands ops; op->getParameters (ops); // If operator found use the function else use default if (NULL != chcktp) { // Check arguments if ( ((chcktp->argNum >= 0) && (ops.size () != (size_t)chcktp->argNum)) || ((chcktp->argNum < 0) && (ops.size () > (size_t)-chcktp->argNum)) ) { kernelPrintDbg (debug::DBG_CRIT, "Bad content stream. Incorrect parameters."); // Delete gfx state delete tmpstate; throw CObjInvalidObject (); } // Update the state tmpstate = (chcktp->update) (tmpstate, res, op, ops, &rc); }else { // Update the state tmpstate = unknownUpdate (tmpstate, res, op, ops, &rc); } assert (tmpstate); ftor (op, rc, *tmpstate); it = it.next (); } // while // Close xpdf mess xpdf::closeXpdfMess (); // If malformed content stream (missing Q) while (tmpstate->hasSaves()) tmpstate = tmpstate->restore (); // Return gfx state return boost::shared_ptr (tmpstate); } // // Helper functions // public: static GfxState* printTextUpdate (GfxState* state, const std::string& txt, BBox* rc); }; /** * Is it a simple or a composite operator. * @param chck Check type structure. * @return True if the chck is a simple operator, false otherwise. */ inline bool isSimpleOp (const StateUpdater::CheckTypes& chck) { return ('\0' == chck.endTag[0]); } //========================================================== } // namespace pdfobjects //========================================================== #endif // _STATEUPDATER_H_