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(scanner) ⇒ Object
:nodoc:.
-
.typeof(stream) ⇒ Object
:nodoc:.
Instance Method Summary collapse
-
#cast_to(type, parser = nil) ⇒ Object
Casts an object to a new type.
-
#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.
-
#numbered? ⇒ Boolean
Returns whether an object number exists for this 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.
- #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, eol: $/) ⇒ 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.
359 360 361 |
# File 'lib/origami/object.rb', line 359 def file_offset @file_offset end |
#generation ⇒ Object
Returns the value of attribute generation.
359 360 361 |
# File 'lib/origami/object.rb', line 359 def generation @generation end |
#no ⇒ Object
Returns the value of attribute no.
359 360 361 |
# File 'lib/origami/object.rb', line 359 def no @no end |
#objstm_offset ⇒ Object
Returns the value of attribute objstm_offset.
359 360 361 |
# File 'lib/origami/object.rb', line 359 def objstm_offset @objstm_offset end |
#parent ⇒ Object
Returns the value of attribute parent.
360 361 362 |
# File 'lib/origami/object.rb', line 360 def parent @parent end |
Class Method Details
.included(base) ⇒ Object
Modules or classes including this module are considered native types.
365 366 367 368 |
# File 'lib/origami/object.rb', line 365 def self.included(base) base.class_variable_set(:@@native_type, base) base.extend(ClassMethods) end |
.parse(stream, parser = nil) ⇒ Object
:nodoc:
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 |
# File 'lib/origami/object.rb', line 623 def parse(stream, parser = nil) #:nodoc: scanner = Parser.init_scanner(stream) offset = scanner.pos # # End of body ? # return nil if scanner.match?(/xref/) or scanner.match?(/trailer/) or scanner.match?(/startxref/) if scanner.scan(@@regexp_obj).nil? raise InvalidObjectError, "Object shall begin with '%d %d obj' statement" end no = scanner['no'].to_i gen = scanner['gen'].to_i type = typeof(scanner) if type.nil? raise InvalidObjectError, "Cannot determine object (no:#{no},gen:#{gen}) type" end begin new_obj = type.parse(scanner, 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 scanner.skip(@@regexp_endobj).nil? raise UnterminatedObjectError.new("Object shall end with 'endobj' statement", new_obj) end new_obj end |
.skip_until_next_obj(scanner) ⇒ Object
:nodoc:
662 663 664 665 666 667 668 669 670 671 |
# File 'lib/origami/object.rb', line 662 def skip_until_next_obj(scanner) #:nodoc: [ @@regexp_obj, /xref/, /trailer/, /startxref/ ].each do |re| if scanner.scan_until(re) scanner.pos -= scanner.matched_size return true end end false end |
.typeof(stream) ⇒ Object
:nodoc:
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 |
# File 'lib/origami/object.rb', line 595 def typeof(stream) #:nodoc: scanner = Parser.init_scanner(stream) scanner.skip(REGEXP_WHITESPACES) case scanner.peek(1) when '/' then return Name when '<' return (scanner.peek(2) == '<<') ? Stream : HexaString when '(' then return LiteralString when '[' then return Origami::Array when 'n' then return Null if scanner.peek(4) == 'null' when 't' then return Boolean if scanner.peek(4) == 'true' when 'f' then return Boolean if scanner.peek(5) == 'false' else if scanner.check(Reference::REGEXP_TOKEN) then return Reference elsif scanner.check(Real::REGEXP_TOKEN) then return Real elsif scanner.check(Integer::REGEXP_TOKEN) then return Integer else nil end end nil end |
Instance Method Details
#cast_to(type, parser = nil) ⇒ Object
Casts an object to a new type.
479 480 481 482 483 484 485 486 |
# File 'lib/origami/object.rb', line 479 def cast_to(type, parser = nil) assert_cast_type(type) cast = type.new(self.copy, parser) cast.file_offset = @file_offset transfer_attributes(cast) end |
#copy ⇒ Object
Deep copy of an object.
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 |
# File 'lib/origami/object.rb', line 457 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.
580 581 582 583 584 585 |
# File 'lib/origami/object.rb', line 580 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.
526 527 528 529 530 531 532 533 534 |
# File 'lib/origami/object.rb', line 526 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.
443 444 445 |
# File 'lib/origami/object.rb', line 443 def indirect? @indirect end |
#indirect_parent ⇒ Object
Returns the indirect object which contains this object. If the current object is already indirect, returns self.
556 557 558 559 560 561 |
# File 'lib/origami/object.rb', line 556 def indirect_parent obj = self obj = obj.parent until obj.indirect? obj end |
#initialize(*cons) ⇒ Object
Creates a new PDF Object.
395 396 397 398 399 400 401 402 403 |
# File 'lib/origami/object.rb', line 395 def initialize(*cons) @indirect = false @no, @generation = 0, 0 @document = nil @parent = nil @file_offset = nil super(*cons) unless cons.empty? end |
#logicalize ⇒ Object
Returns a logicalized copy of self. See logicalize!
540 541 542 |
# File 'lib/origami/object.rb', line 540 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.
548 549 550 |
# File 'lib/origami/object.rb', line 548 def logicalize! #:nodoc: resolve_all_references(self) end |
#native_type ⇒ Object
Returns the native type of the Object.
388 389 390 |
# File 'lib/origami/object.rb', line 388 def native_type self.class.native_type end |
#numbered? ⇒ Boolean
Returns whether an object number exists for this object.
450 451 452 |
# File 'lib/origami/object.rb', line 450 def numbered? @no > 0 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.
436 437 438 |
# File 'lib/origami/object.rb', line 436 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.
428 429 430 |
# File 'lib/origami/object.rb', line 428 def pre_build self end |
#reference ⇒ Object
Returns an indirect reference to this object.
491 492 493 494 495 496 497 498 |
# File 'lib/origami/object.rb', line 491 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
587 588 589 590 591 |
# File 'lib/origami/object.rb', line 587 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.
409 410 411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'lib/origami/object.rb', line 409 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 @file_offset = nil end @indirect = bool self end |
#solve ⇒ Object
Returns self.
573 574 575 |
# File 'lib/origami/object.rb', line 573 def solve self end |
#to_s(data, eol: $/) ⇒ Object Also known as: output, to_obfuscated_str
Outputs this object into PDF code.
- data
-
The object data.
691 692 693 694 695 696 697 698 |
# File 'lib/origami/object.rb', line 691 def to_s(data, eol: $/) content = "" content << "#{no} #{generation} #{TOKENS.first}" << eol if indirect? and numbered? content << data content << eol << TOKENS.last << eol if indirect? and numbered? content.force_encoding('binary') end |
#type ⇒ Object
Returns the symbol type of this Object.
681 682 683 684 685 |
# File 'lib/origami/object.rb', line 681 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:
674 675 676 |
# File 'lib/origami/object.rb', line 674 def version_required #:nodoc: [ '1.0', 0 ] end |
#xrefs ⇒ Object
Returns an array of references pointing to the current object.
503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 |
# File 'lib/origami/object.rb', line 503 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 ObjectCache object.xref_cache[self.reference] end } .compact! end |