Module: Origami::Object
- Defined in:
- lib/origami/object.rb,
lib/origami/obfuscation.rb
Overview
Parent module representing a PDF Object. PDF specification declares a set of primitive object types :
-
Null
-
Boolean
-
Integer
-
Real
-
Name
-
String
-
Array
-
Dictionary
-
Stream
Defined Under Namespace
Modules: ClassMethods
Constant Summary collapse
- TOKENS =
:nodoc:
%w{ obj endobj }
- @@regexp_obj =
Regexp.new(WHITESPACES + "(?<no>\\d+)" + WHITESPACES + "(?<gen>\\d+)" + WHITESPACES + TOKENS.first + WHITESPACES)
- @@regexp_endobj =
Regexp.new(WHITESPACES + TOKENS.last + WHITESPACES)
Instance Attribute Summary collapse
-
#file_offset ⇒ Object
Returns the value of attribute file_offset.
-
#generation ⇒ Object
Returns the value of attribute generation.
-
#no ⇒ Object
Returns the value of attribute no.
-
#objstm_offset ⇒ Object
Returns the value of attribute objstm_offset.
-
#parent ⇒ Object
Returns the value of attribute parent.
Class Method Summary collapse
-
.included(base) ⇒ Object
Modules or classes including this module are considered native types.
-
.parse(stream, parser = nil) ⇒ Object
:nodoc:.
-
.skip_until_next_obj(stream) ⇒ Object
:nodoc:.
-
.typeof(stream, noref = false) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#<=>(obj) ⇒ Object
Compare two objects from their respective numbers.
-
#cast_to(type, _parser = nil) ⇒ Object
:nodoc:.
-
#copy ⇒ Object
Deep copy of an object.
-
#document ⇒ Object
Returns the PDF which the object belongs to.
-
#export ⇒ Object
Creates an exportable version of current object.
-
#indirect? ⇒ Boolean
Returns whether the objects is indirect, which means that it is not embedded into another object.
-
#indirect_parent ⇒ Object
Returns the indirect object which contains this object.
-
#initialize(*cons) ⇒ Object
Creates a new PDF Object.
-
#logicalize ⇒ Object
Returns a logicalized copy of self.
-
#logicalize! ⇒ Object
Transforms recursively every references to the copy of their respective object.
-
#native_type ⇒ Object
Returns the native type of the Object.
-
#post_build ⇒ Object
Generic method called just after the object is finalized.
-
#pre_build ⇒ Object
Generic method called just before the object is finalized.
-
#reference ⇒ Object
Returns an indirect reference to this object, or a Null object is this object is not indirect.
- #set_document(doc) ⇒ Object
-
#set_indirect(bool) ⇒ Object
Sets whether the object is indirect or not.
-
#solve ⇒ Object
Returns self.
-
#to_o ⇒ Object
Returns self.
-
#to_s(data) ⇒ Object
(also: #output, #to_obfuscated_str)
Outputs this object into PDF code.
-
#type ⇒ Object
Returns the symbol type of this Object.
-
#version_required ⇒ Object
:nodoc:.
-
#xrefs ⇒ Object
Returns an array of references pointing to the current object.
Instance Attribute Details
#file_offset ⇒ Object
Returns the value of attribute file_offset.
316 317 318 |
# File 'lib/origami/object.rb', line 316 def file_offset @file_offset end |
#generation ⇒ Object
Returns the value of attribute generation.
316 317 318 |
# File 'lib/origami/object.rb', line 316 def generation @generation end |
#no ⇒ Object
Returns the value of attribute no.
316 317 318 |
# File 'lib/origami/object.rb', line 316 def no @no end |
#objstm_offset ⇒ Object
Returns the value of attribute objstm_offset.
316 317 318 |
# File 'lib/origami/object.rb', line 316 def objstm_offset @objstm_offset end |
#parent ⇒ Object
Returns the value of attribute parent.
317 318 319 |
# File 'lib/origami/object.rb', line 317 def parent @parent end |
Class Method Details
.included(base) ⇒ Object
Modules or classes including this module are considered native types.
322 323 324 325 |
# File 'lib/origami/object.rb', line 322 def self.included(base) base.class_variable_set(:@@native_type, base) base.extend(ClassMethods) end |
.parse(stream, parser = nil) ⇒ Object
:nodoc:
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 |
# File 'lib/origami/object.rb', line 603 def parse(stream, parser = nil) #:nodoc: offset = stream.pos # # End of body ? # return nil if stream.match?(/xref/) or stream.match?(/trailer/) or stream.match?(/startxref/) if stream.scan(@@regexp_obj).nil? raise InvalidObjectError, "Object shall begin with '%d %d obj' statement" end no = stream['no'].to_i gen = stream['gen'].to_i type = typeof(stream) if type.nil? raise InvalidObjectError, "Cannot determine object (no:#{no},gen:#{gen}) type" end begin new_obj = type.parse(stream, parser) rescue raise InvalidObjectError, "Failed to parse object (no:#{no},gen:#{gen})\n\t -> [#{$!.class}] #{$!.}" end new_obj.set_indirect(true) new_obj.no = no new_obj.generation = gen new_obj.file_offset = offset if stream.skip(@@regexp_endobj).nil? raise UnterminatedObjectError.new("Object shall end with 'endobj' statement", new_obj) end new_obj end |
.skip_until_next_obj(stream) ⇒ Object
:nodoc:
644 645 646 647 648 649 650 651 652 653 |
# File 'lib/origami/object.rb', line 644 def skip_until_next_obj(stream) #:nodoc: [ @@regexp_obj, /xref/, /trailer/, /startxref/ ].each do |re| if stream.scan_until(re) stream.pos -= stream.matched_size return true end end false end |
.typeof(stream, noref = false) ⇒ Object
:nodoc:
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 |
# File 'lib/origami/object.rb', line 576 def typeof(stream, noref = false) #:nodoc: stream.skip(REGEXP_WHITESPACES) case stream.peek(1) when '/' then return Name when '<' return (stream.peek(2) == '<<') ? Stream : HexaString when '(' then return LiteralString when '[' then return Origami::Array when 'n' then return Null if stream.peek(4) == 'null' when 't' then return Boolean if stream.peek(4) == 'true' when 'f' then return Boolean if stream.peek(5) == 'false' else if not noref and stream.check(Reference::REGEXP_TOKEN) then return Reference elsif stream.check(Real::REGEXP_TOKEN) then return Real elsif stream.check(Integer::REGEXP_TOKEN) then return Integer else nil end end nil end |
Instance Method Details
#<=>(obj) ⇒ Object
Compare two objects from their respective numbers.
398 399 400 |
# File 'lib/origami/object.rb', line 398 def <=>(obj) [@no, @generation] <=> [obj.no, obj.generation] end |
#cast_to(type, _parser = nil) ⇒ Object
:nodoc:
669 670 671 672 673 674 675 |
# File 'lib/origami/object.rb', line 669 def cast_to(type, _parser = nil) #:nodoc: if type.native_type != self.native_type raise TypeError, "Incompatible cast from #{self.class} to #{type}" end self end |
#copy ⇒ Object
Deep copy of an object.
412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/origami/object.rb', line 412 def copy saved_doc = @document saved_parent = @parent @document = @parent = nil # do not process parent object and document in the copy # Perform the recursive copy (quite dirty). copyobj = Marshal.load(Marshal.dump(self)) # restore saved values @document = saved_doc @parent = saved_parent copyobj.set_document(saved_doc) if copyobj.indirect? copyobj.parent = parent copyobj end |
#document ⇒ Object
Returns the PDF which the object belongs to.
561 562 563 564 565 566 |
# File 'lib/origami/object.rb', line 561 def document if self.indirect? then @document else @parent.document unless @parent.nil? end end |
#export ⇒ Object
Creates an exportable version of current object. The exportable version is a copy of self with solved references, no owning PDF and no parent. References to Catalog or PageTreeNode objects have been destroyed.
When exported, an object can be moved into another document without hassle.
469 470 471 472 473 474 475 476 477 |
# File 'lib/origami/object.rb', line 469 def export exported_obj = self.logicalize exported_obj.no = exported_obj.generation = 0 exported_obj.set_document(nil) if exported_obj.indirect? exported_obj.parent = nil exported_obj.xref_cache.clear exported_obj end |
#indirect? ⇒ Boolean
Returns whether the objects is indirect, which means that it is not embedded into another object.
405 406 407 |
# File 'lib/origami/object.rb', line 405 def indirect? @indirect end |
#indirect_parent ⇒ Object
Returns the indirect object which contains this object. If the current object is already indirect, returns self.
537 538 539 540 541 542 |
# File 'lib/origami/object.rb', line 537 def indirect_parent obj = self obj = obj.parent until obj.indirect? obj end |
#initialize(*cons) ⇒ Object
Creates a new PDF Object.
352 353 354 355 356 357 358 359 |
# File 'lib/origami/object.rb', line 352 def initialize(*cons) @indirect = false @no, @generation = 0, 0 @document = nil @parent = nil super(*cons) unless cons.empty? end |
#logicalize ⇒ Object
Returns a logicalized copy of self. See logicalize!
483 484 485 |
# File 'lib/origami/object.rb', line 483 def logicalize #:nodoc: self.copy.logicalize! end |
#logicalize! ⇒ Object
Transforms recursively every references to the copy of their respective object. Catalog and PageTreeNode objects are excluded to limit the recursion.
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 |
# File 'lib/origami/object.rb', line 491 def logicalize! #:nodoc: resolve_all_references = -> (obj, browsed = [], ref_cache = {}) do return if browsed.include?(obj) browsed.push(obj) if obj.is_a?(ObjectStream) obj.each do |subobj| resolve_all_references[subobj, browsed, ref_cache] end end if obj.is_a?(Dictionary) or obj.is_a?(Array) obj.map! do |subobj| if subobj.is_a?(Reference) new_obj = if ref_cache.has_key?(subobj) ref_cache[subobj] else ref_cache[subobj] = subobj.solve.copy end new_obj.no = new_obj.generation = 0 new_obj.parent = obj new_obj unless new_obj.is_a?(Catalog) or new_obj.is_a?(PageTreeNode) else subobj end end obj.each do |subobj| resolve_all_references[subobj, browsed, ref_cache] end elsif obj.is_a?(Stream) resolve_all_references[obj.dictionary, browsed, ref_cache] end end resolve_all_references[self] end |
#native_type ⇒ Object
Returns the native type of the Object.
345 346 347 |
# File 'lib/origami/object.rb', line 345 def native_type self.class.native_type end |
#post_build ⇒ Object
Generic method called just after the object is finalized. At this time, any indirect object has its own number and generation identifier.
391 392 393 |
# File 'lib/origami/object.rb', line 391 def post_build self end |
#pre_build ⇒ Object
Generic method called just before the object is finalized. At this time, no number nor generation allocation has yet been done.
383 384 385 |
# File 'lib/origami/object.rb', line 383 def pre_build self end |
#reference ⇒ Object
Returns an indirect reference to this object, or a Null object is this object is not indirect.
434 435 436 437 438 439 440 441 |
# File 'lib/origami/object.rb', line 434 def reference raise InvalidObjectError, "Cannot reference a direct object" unless self.indirect? ref = Reference.new(@no, @generation) ref.parent = self ref end |
#set_document(doc) ⇒ Object
568 569 570 571 572 |
# File 'lib/origami/object.rb', line 568 def set_document(doc) raise InvalidObjectError, "You cannot set the document of a direct object" unless self.indirect? @document = doc end |
#set_indirect(bool) ⇒ Object
Sets whether the object is indirect or not. Indirect objects are allocated numbers at build time.
365 366 367 368 369 370 371 372 373 374 375 376 377 |
# File 'lib/origami/object.rb', line 365 def set_indirect(bool) unless bool == true or bool == false raise TypeError, "The argument must be boolean" end if bool == false @no = @generation = 0 @document = nil end @indirect = bool self end |
#solve ⇒ Object
Returns self.
554 555 556 |
# File 'lib/origami/object.rb', line 554 def solve self end |
#to_s(data) ⇒ Object Also known as: output, to_obfuscated_str
Outputs this object into PDF code.
- data
-
The object data.
681 682 683 684 685 686 687 688 |
# File 'lib/origami/object.rb', line 681 def to_s(data) content = "" content << "#{no} #{generation} #{TOKENS.first}" << EOL if self.indirect? content << data content << EOL << TOKENS.last << EOL if self.indirect? content.force_encoding('binary') end |
#type ⇒ Object
Returns the symbol type of this Object.
663 664 665 666 667 |
# File 'lib/origami/object.rb', line 663 def type name = (self.class.name or self.class.superclass.name or self.native_type.name) name.split("::").last.to_sym end |
#version_required ⇒ Object
:nodoc:
656 657 658 |
# File 'lib/origami/object.rb', line 656 def version_required #:nodoc: [ 1.0, 0 ] end |
#xrefs ⇒ Object
Returns an array of references pointing to the current object.
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 |
# File 'lib/origami/object.rb', line 446 def xrefs raise InvalidObjectError, "Cannot find xrefs to a direct object" unless self.indirect? raise InvalidObjectError, "Not attached to any document" if self.document.nil? @document.each_object(compressed: true) .flat_map { |object| case object when Stream object.dictionary.xref_cache[self.reference] when Dictionary, Array object.xref_cache[self.reference] end } .compact! end |