################################################################################## Copyright (C) 2006 Peter J Jones (pjones@pmade.com)## Permission is hereby granted, free of charge, to any person obtaining# a copy of this software and associated documentation files (the# "Software"), to deal in the Software without restriction, including# without limitation the rights to use, copy, modify, merge, publish,# distribute, sublicense, and/or sell copies of the Software, and to# permit persons to whom the Software is furnished to do so, subject to# the following conditions:# # The above copyright notice and this permission notice shall be# included in all copies or substantial portions of the Software.# # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.#################################################################################classPDF::Reader################################################################################# An internal PDF::Reader class that represents the Xref table in a PDF file# An Xref table is a map of object identifiers and byte offsets. Any time a particular# object needs to be found, the Xref table is used to find where it is stored in the# file.classXRef################################################################################# create a new Xref table based on the contents of the supplied PDF::Reader::Buffer objectdefinitialize(buffer)@buffer=buffer@xref={}end################################################################################# Read the xref table from the underlying buffer. If offset is specified the table# will be loaded from there, otherwise the default offset will be located and used.## Will fail silently if there is no xref table at the requested offset.defload(offset=nil)offset||=@buffer.find_first_xref_offset@buffer.seek(offset)token=@buffer.tokeniftoken=="xref"||token=="ref"load_xref_tableelseraisePDF::Reader::MalformedPDFError,"xref table not found at offset #{offset} (#{token} != xref)"endend################################################################################# Return a string containing the contents of an entire PDF object. The object is requested# by specifying a PDF::Reader::Reference object that contains the objects ID and revision# number## If the object is a stream, that is returned as welldefobject(ref,save_pos=true)returnrefunlessref.kind_of?(Reference)pos=@buffer.posifsave_posobj,stream=Parser.new(@buffer.seek(offset_for(ref)),self).object(ref.id,ref.gen)@buffer.seek(pos)ifsave_posifstreamreturnobj,streamelsereturnobjendend################################################################################# Assumes the underlying buffer is positioned at the start of an Xref table and# processes it into memory.defload_xref_tabletok_one=tok_two=nilbegin# loop over all subsections of the xref table# In a well formed PDF, the 'trailer' token will indicate# the end of the table. However we need to be careful in case # we're processing a malformed pdf that is missing the trailer.loopdotok_one,tok_two=@buffer.token,@buffer.tokeniftok_one!="trailer"&&!tok_one.match(/\d+/)raiseMalformedPDFError,"PDF malformed, missing trailer after cross reference"endbreakiftok_one=="trailer"ortok_one.nil?objid,count=tok_one.to_i,tok_two.to_icount.timesdooffset=@buffer.token.to_igeneration=@buffer.token.to_istate=@buffer.tokenstore(objid,generation,offset)ifstate=="n"objid+=1endendrescueEOFError=>eraiseMalformedPDFError,"PDF malformed, missing trailer after cross reference"endraiseMalformedPDFError,"PDF malformed, trailer should be a dictionary"unlesstok_two=="<<"trailer=Parser.new(@buffer,self).dictionaryload(trailer['Prev'].to_i)iftrailer.has_key?('Prev')trailerend################################################################################# returns the byte offset for the specified PDF object.## ref - a PDF::Reader::Reference object containing an object ID and revision numberdefoffset_for(ref)@xref[ref.id][ref.gen]end################################################################################# Stores an offset value for a particular PDF object ID and revision numberdefstore(id,gen,offset)(@xref[id]||={})[gen]||=offsetend################################################################################end################################################################################end################################################################################