=begin
This file is part of Origami, PDF manipulation framework for Ruby
Copyright (C) 2016 Guillaume Delugré.
Origami is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Origami is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with Origami. If not, see .
=end
module Origami
class InvalidReferenceError < Error #:nodoc:
end
#
# Class representing a Reference Object.
# Reference are like symbolic links pointing to a particular object into the file.
#
class Reference
include Origami::Object
include Comparable
TOKENS = [ "(?\\d+)" + WHITESPACES + "(?\\d+)" + WHITESPACES + "R" ] #:nodoc:
REGEXP_TOKEN = Regexp.new(TOKENS.first, Regexp::MULTILINE)
@@regexp = Regexp.new(WHITESPACES + TOKENS.first + WHITESPACES)
attr_accessor :refno, :refgen
def initialize(refno, refgen)
super()
@refno, @refgen = refno, refgen
end
def self.parse(stream, _parser = nil) #:nodoc:
scanner = Parser.init_scanner(stream)
offset = scanner.pos
if scanner.scan(@@regexp).nil?
raise InvalidReferenceError, "Bad reference to indirect objet format"
end
no = scanner['no'].to_i
gen = scanner['gen'].to_i
ref = Reference.new(no, gen)
ref.file_offset = offset
ref
end
#
# Returns the object pointed to by the reference.
# The reference must be part of a document.
# Raises an InvalidReferenceError if the object cannot be found.
#
def follow
doc = self.document
if doc.nil?
raise InvalidReferenceError, "Not attached to any document"
end
target = doc.get_object(self)
if target.nil? and not Origami::OPTIONS[:ignore_bad_references]
raise InvalidReferenceError, "Cannot resolve reference : #{self}"
end
target or Null.new
end
alias solve follow
#
# Returns true if the reference points to an object.
#
def valid?
begin
self.solve
true
rescue InvalidReferenceError
false
end
end
def hash #:nodoc:
self.to_a.hash
end
def <=>(ref) #:nodoc
self.to_a <=> ref.to_a
end
#
# Compares to Reference object.
#
def ==(ref)
return false unless ref.is_a?(Reference)
self.to_a == ref.to_a
end
alias eql? ==
#
# Returns a Ruby array with the object number and the generation this reference is pointing to.
#
def to_a
[@refno, @refgen]
end
def to_s(eol: $/) #:nodoc:
super("#{@refno} #{@refgen} R", eol: eol)
end
#
# Returns the referenced object value.
#
def value
self.solve.value
end
end
end