Class: PDF::Reader::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/pdf/reader/parser.rb

Overview

An internal PDF::Reader class that reads objects from the PDF file and converts them into useable ruby objects (hash's, arrays, true, false, etc)

Constant Summary collapse

TOKEN_STRATEGY =

Signature:

  • Proc

proc { |parser, token| Token.new(token) }
INTERNED_TOKENS =

Signature:

  • Hash[String, PDF::Reader::Token]

{}
STRATEGIES =
{
  "/"  => proc { |parser, token| parser.send(:pdf_name) },
  "<<" => proc { |parser, token| parser.send(:dictionary) },
  "["  => proc { |parser, token| parser.send(:array) },
  "("  => proc { |parser, token| parser.send(:string) },
  "<"  => proc { |parser, token| parser.send(:hex_string) },

  nil     => proc { nil },
  "true"  => proc { true },
  "false" => proc { false },
  "null"  => proc { nil },

  "obj"       => TOKEN_STRATEGY,
  "endobj"    => TOKEN_STRATEGY,
  "stream"    => TOKEN_STRATEGY,
  "endstream" => TOKEN_STRATEGY,
  ">>"        => TOKEN_STRATEGY,
  "]"         => TOKEN_STRATEGY,
  ">"         => TOKEN_STRATEGY,
  ")"         => TOKEN_STRATEGY
}

Instance Method Summary collapse

Constructor Details

#initialize(buffer, operators: {}, objects: nil, relaxed_dictionaries: false) ⇒ Parser

Create a new parser around a PDF::Reader::Buffer object

buffer - a PDF::Reader::Buffer object that contains PDF data objects - a PDF::Reader::ObjectHash object that can return objects from the PDF file operators - a hash of supported operators to read from the underlying buffer. relaxed_dictionaries - quietly skip unexpected operator tokens inside a dictionary. Useful for handling Postscript dictionaries in CMaps

Signature:

  • (

  • PDF::Reader::Buffer,

  • ?operators: Hash[String | PDF::Reader::Token, Symbol],

  • ?objects: PDF::Reader::ObjectHash?,

  • ?relaxed_dictionaries: T::Boolean

  • ) -> void



76
77
78
79
80
81
82
# File 'lib/pdf/reader/parser.rb', line 76

def initialize(buffer, operators: {}, objects: nil, relaxed_dictionaries: false)
  @buffer = buffer
  @operators = operators
  @objects  = objects
  @relaxed_dictionaries = relaxed_dictionaries
  @hex_pack_buffer = [""] #: Array[String]
end

Instance Method Details

#object(id, gen) ⇒ Object

Reads an entire PDF object from the buffer and returns it as a Ruby String. If the object is a content stream, returns both the stream and the dictionary that describes it

id - the object ID to return gen - the object revision number to return

Signature:

  • (Integer, Integer) -> (

  • PDF::Reader::Reference |

  • PDF::Reader::Token |

  • PDF::Reader::Stream |

  • Numeric |

  • String |

  • Symbol |

  • Array[untyped] |

  • Hash[untyped, untyped] |

  • nil

  • )



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# File 'lib/pdf/reader/parser.rb', line 135

def object(id, gen)
  idCheck = parse_token

  # Sometimes the xref table is corrupt and points to an offset slightly too early in the file.
  # check the next token, maybe we can find the start of the object we're looking for
  if idCheck != id
    Error.assert_equal(parse_token, id)
  end
  Error.assert_equal(parse_token, gen)
  Error.str_assert(parse_token, "obj")

  obj = parse_token
  post_obj = parse_token

  if obj.is_a?(Hash) && post_obj == "stream"
    stream(obj)
  else
    obj
  end
end

#parse_tokenObject

Reads the next token from the underlying buffer and convets it to an appropriate object

Signature:

  • () -> (

  • PDF::Reader::Reference |

  • PDF::Reader::Token |

  • Numeric |

  • String |

  • Symbol |

  • Array[untyped] |

  • Hash[untyped, untyped] |

  • nil

  • )



97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/pdf/reader/parser.rb', line 97

def parse_token
  token = @buffer.token

  if token.nil?
    nil
  elsif token.is_a?(String) && STRATEGIES.has_key?(token)
    proc = STRATEGIES[token]
    proc.call(self, token) if proc
  elsif token.is_a? PDF::Reader::Reference
    token
  elsif @operators.has_key? token
    INTERNED_TOKENS[token] ||= Token.new(token)
  elsif token.frozen?
    token
  elsif match?(token, /\d*\.\d/)
    token.to_f
  else
    token.to_i
  end
end