bool PdfDictionary::operator==( const PdfDictionary& rhs ) const { if (this == &rhs) return true; if ( m_mapKeys.size() != rhs.m_mapKeys.size() ) return false; // It's not enough to test that our internal maps are equal, because // we store variants by pointer not value. However, since a dictionary's // keys are stored in a SORTED map, and there may be only one instance of // every key, we can do lockstep iteration and compare that way. const TCIKeyMap thisIt = m_mapKeys.begin(); const TCIKeyMap thisEnd = m_mapKeys.end(); const TCIKeyMap rhsIt = rhs.m_mapKeys.begin(); const TCIKeyMap rhsEnd = rhs.m_mapKeys.end(); while ( thisIt != thisEnd && rhsIt != rhsEnd ) { if ( (*thisIt).first != (*rhsIt).first ) // Name mismatch. Since the keys are sorted that means that there's a key present // in one dictionary but not the other. return false; if ( *(*thisIt).second != *(*rhsIt).second ) // Value mismatch on same-named keys. return false; } // BOTH dictionaries must now be on their end iterators - since we checked that they were // the same size initially, we know they should run out of keys at the same time. PODOFO_RAISE_LOGIC_IF( thisIt != thisEnd || rhsIt != rhsEnd, "Dictionary compare error" ); // We didn't find any mismatches return true; }
void PdfContentsTokenizer::SetCurrentContentsStream( PdfObject* pObject ) { PODOFO_RAISE_LOGIC_IF( pObject == NULL, "Content stream object == NULL!" ); PdfStream* pStream = pObject->GetStream(); PdfBufferOutputStream stream( &m_curBuffer ); pStream->GetFilteredCopy( &stream ); m_device = PdfRefCountedInputDevice( m_curBuffer.GetBuffer(), m_curBuffer.GetSize() ); }
PdfOutputStream* PdfFilterFactory::CreateEncodeStream( const TVecFilters & filters, PdfOutputStream* pStream ) { TVecFilters::const_iterator it = filters.begin(); PODOFO_RAISE_LOGIC_IF( !filters.size(), "Cannot create an EncodeStream from an empty list of filters" ); PdfFilteredEncodeStream* pFilter = new PdfFilteredEncodeStream( pStream, *it, false ); ++it; while( it != filters.end() ) { pFilter = new PdfFilteredEncodeStream( pFilter, *it, true ); ++it; } return pFilter; }
void PdfVecObjects::InsertOneReferenceIntoVector( const PdfObject* pObj, TVecReferencePointerList* pList ) { size_t index; PODOFO_RAISE_LOGIC_IF( !m_bSorted, "PdfVecObjects must be sorted before calling PdfVecObjects::InsertOneReferenceIntoVector!" ); // we asume that pObj is a reference - no checking here because of speed std::pair<TCIVecObjects,TCIVecObjects> it = std::equal_range( m_vector.begin(), m_vector.end(), pObj, ObjectComparatorPredicate() ); if( it.first != it.second ) { // ignore this reference return; //PODOFO_RAISE_ERROR( ePdfError_NoObject ); } index = (it.first - this->begin()); (*pList)[index].push_back( const_cast<PdfReference*>(&(pObj->GetReference() )) ); }
PdfOutputStream* PdfFilterFactory::CreateDecodeStream( const TVecFilters & filters, PdfOutputStream* pStream, const PdfDictionary* pDictionary ) { TVecFilters::const_reverse_iterator it = filters.rbegin(); PODOFO_RAISE_LOGIC_IF( !filters.size(), "Cannot create an DecodeStream from an empty list of filters" ); // TODO: support arrays and indirect objects here and the short name /DP if( pDictionary && pDictionary->HasKey( "DecodeParms" ) && pDictionary->GetKey( "DecodeParms" )->IsDictionary() ) pDictionary = &(pDictionary->GetKey( "DecodeParms" )->GetDictionary()); PdfFilteredDecodeStream* pFilter = new PdfFilteredDecodeStream( pStream, *it, false, pDictionary ); ++it; while( it != filters.rend() ) { pFilter = new PdfFilteredDecodeStream( pFilter, *it, true, pDictionary ); ++it; } return pFilter; }
PdfContentsGraph::PdfContentsGraph( PdfContentsTokenizer & contentsTokenizer ) : m_graph() { EPdfContentsType t; const char * kwText; PdfVariant var; bool readToken; // Keep a count of the number of tokens read so we can report errors // more usefully. int tokenNumber = 0; // Set up the node stack and initialize the root node stack<Vertex> parentage; parentage.push( add_vertex(m_graph) ); m_graph[parentage.top()] = MakeNode(KW_RootNode,KW_RootNode); // Arguments to be associated with the next keyword found vector<PdfVariant> args; while ( ( readToken = contentsTokenizer.ReadNext(t, kwText, var) ) ) { ++tokenNumber; if (t == ePdfContentsType_Variant) { // arguments come before operators, but we want to group them up before // their operator. args.push_back(var); } else if (t == ePdfContentsType_Keyword) { const KWInfo & ki ( findKwByName(kwText) ); if (ki.kt != KT_Closing) { // We're going to need a new vertex, so make sure we have one ready. Vertex v = add_vertex( m_graph ); // Switch any waiting arguments into the new node's data. m_graph[v].first.GetArgs().swap( args ); assert(!args.size()); if (ki.kw == KW_Unknown) { // No idea what this keyword is. We have to assume it's an ordinary // one, possibly with arguments, and just push it in as a node at the // current level. assert(!m_graph[v].first.IsDefined()); m_graph[v].first.SetKw( string(kwText) ); add_edge( parentage.top(), v, m_graph ); assert( m_graph[v].first.GetKwId() == ki.kw ); assert( m_graph[v].first.GetKwString() == kwText ); } else if (ki.kt == KT_Standalone) { // Plain operator, shove it in the newly reserved vertex (which might already contain // arguments) and add an edge from the top to it. assert(ki.kw != KW_Undefined && ki.kw != KW_Unknown && ki.kw != KW_RootNode ); assert(!m_graph[v].first.IsDefined()); m_graph[v].first.SetKw( ki.kw ); add_edge( parentage.top(), v, m_graph ); assert( m_graph[v].first.GetKwId() == ki.kw ); assert( m_graph[v].first.GetKwString() == kwText ); } else if (ki.kt == KT_Opening) { PrintStack(m_graph, parentage, "OS: "); assert(ki.kw != KW_Undefined && ki.kw != KW_Unknown && ki.kw != KW_RootNode ); assert(!m_graph[v].first.IsDefined()); m_graph[v].first.SetKw( ki.kw ); // add an edge from the current top to it add_edge( parentage.top(), v, m_graph ); // and push it to the top of the parentage stack parentage.push( v ); assert( m_graph[v].first.GetKwId() == ki.kw ); assert( m_graph[v].first.GetKwString() == kwText ); PrintStack(m_graph, parentage, "OF: "); } else { assert(false); } } else if (ki.kt == KT_Closing) { // This keyword closes a context. The top of the parentage tree should // be a node whose KWInstance is the matching opening keyword. We'll check // that, then set the second KWInstance appropriately. PrintStack(m_graph, parentage, "CS: "); assert(ki.kw != KW_Undefined && ki.kw != KW_Unknown && ki.kw != KW_RootNode ); // Get a reference to the node data for the current parent NodeData & n ( m_graph[parentage.top()] ); PODOFO_RAISE_LOGIC_IF( n.second.IsDefined(), "Closing already closed group" ); // Ensure that the opening keyword therein is one that this closing keyword is // a valid match for PdfContentStreamKeyword expectedCloseKw = n.first.GetKwInfo().kwClose; // Ensure there aren't any args to the close kw assert(!args.size()); // and handle the close matching if ( ki.kw != expectedCloseKw ) { // Some PDFs, even Adobe ones, place close operators // in the wrong order. We'll do some lookahead to see // if we can fix things up before we hit a non-close // operator. if ( !closeFixup( m_graph, parentage, contentsTokenizer, ki ) ) { string err = formatMismatchError(m_graph, parentage, tokenNumber, ki.kw, expectedCloseKw); PODOFO_RAISE_ERROR_INFO( ePdfError_InvalidContentStream, err.c_str() ); } } else { n.second.SetKw( ki.kw ); // Our associated operator is now on the top of the // parentage stack. Since its scope has ended, it should // also be popped. parentage.pop(); } PrintStack(m_graph, parentage, "CF: "); } else { assert(false); } } else { assert(false); } } PODOFO_RAISE_LOGIC_IF( args.size(), "Stream ended with unconsumed arguments!" ); PODOFO_RAISE_LOGIC_IF( parentage.size() != 1, "Stream failed to close all levels" ); }