=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 REGULARCHARS = "([^ \\t\\r\\n\\0\\[\\]<>()%\\/]|#[a-fA-F0-9][a-fA-F0-9])*" #:nodoc: class InvalidNameObjectError < InvalidObjectError #:nodoc: end # # Class representing a Name Object. # Name objects are strings which identify some PDF file inner structures. # class Name #< DelegateClass(Symbol) include Origami::Object TOKENS = %w{ / } #:nodoc: @@regexp = Regexp.new(WHITESPACES + TOKENS.first + "(?#{REGULARCHARS})" + WHITESPACES) #:nodoc # # Creates a new Name. # _name_:: A symbol representing the new Name value. # def initialize(name = "") unless name.is_a?(Symbol) or name.is_a?(::String) raise TypeError, "Expected type Symbol or String, received #{name.class}." end @value = name.to_s super() end def value @value.to_sym end alias to_sym value def <=>(name) return unless name.is_a?(Name) self.value <=> name.value end def ==(object) #:nodoc: self.eql?(object) or @value.to_sym == object end def eql?(object) #:nodoc: object.is_a?(Name) and self.value.eql?(object.value) end def hash #:nodoc: @value.hash end def to_s #:nodoc: super(TOKENS.first + Name.expand(@value)) end def self.parse(stream, _parser = nil) #:nodoc: offset = stream.pos name = if stream.scan(@@regexp).nil? raise InvalidNameObjectError, "Bad name format" else value = stream['name'] Name.new(value.include?('#') ? contract(value) : value) end name.file_offset = offset name end def self.contract(name) #:nodoc: i = 0 name = name.dup while i < name.length if name[i] == "#" digits = name[i+1, 2] unless /^[A-Za-z0-9]{2}$/ === digits raise InvalidNameObjectError, "Irregular use of # token" end char = digits.hex.chr if char == "\0" raise InvalidNameObjectError, "Null byte forbidden inside name definition" end name[i, 3] = char end i = i + 1 end name end def self.expand(name) #:nodoc: forbiddenchars = /[ #\t\r\n\0\[\]<>()%\/]/ name.gsub(forbiddenchars) do |c| "#" + c.ord.to_s(16).rjust(2,"0") end end end end