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.
366 367 368 |
# File 'lib/origami/object.rb', line 366 def file_offset @file_offset end |
#generation ⇒ Object
Returns the value of attribute generation.
366 367 368 |
# File 'lib/origami/object.rb', line 366 def generation @generation end |
#no ⇒ Object
Returns the value of attribute no.
366 367 368 |
# File 'lib/origami/object.rb', line 366 def no @no end |
#objstm_offset ⇒ Object
Returns the value of attribute objstm_offset.
366 367 368 |
# File 'lib/origami/object.rb', line 366 def objstm_offset @objstm_offset end |
#parent ⇒ Object
Returns the value of attribute parent.
367 368 369 |
# File 'lib/origami/object.rb', line 367 def parent @parent end |
Class Method Details
.included(base) ⇒ Object
Modules or classes including this module are considered native types.
372 373 374 375 |
# File 'lib/origami/object.rb', line 372 def self.included(base) base.class_variable_set(:@@native_type, base) base.extend(ClassMethods) end |
.parse(stream, parser = nil) ⇒ Object
:nodoc:
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 661 662 663 664 |
# File 'lib/origami/object.rb', line 627 def parse(stream, parser = nil) # :nodoc: scanner = Parser.init_scanner(stream) offset = scanner.pos # # End of body ? # return nil if scanner.match?(/xref/) || scanner.match?(/trailer/) || 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:
666 667 668 669 670 671 672 673 674 675 |
# File 'lib/origami/object.rb', line 666 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:
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
# File 'lib/origami/object.rb', line 601 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' return Null if scanner.peek(4) == 'null' when 't' return Boolean if scanner.peek(4) == 'true' when 'f' 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 end end nil end |
Instance Method Details
#cast_to(type, parser = nil) ⇒ Object
Casts an object to a new type.
486 487 488 489 490 491 492 493 |
# File 'lib/origami/object.rb', line 486 def cast_to(type, parser = nil) assert_cast_type(type) cast = type.new(copy, parser) cast.file_offset = @file_offset transfer_attributes(cast) end |
#copy ⇒ Object
Deep copy of an object.
464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 |
# File 'lib/origami/object.rb', line 464 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.
587 588 589 590 591 592 |
# File 'lib/origami/object.rb', line 587 def document if indirect? then @document else @parent&.document 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.
533 534 535 536 537 538 539 540 541 |
# File 'lib/origami/object.rb', line 533 def export exported_obj = 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.
450 451 452 |
# File 'lib/origami/object.rb', line 450 def indirect? @indirect end |
#indirect_parent ⇒ Object
Returns the indirect object which contains this object. If the current object is already indirect, returns self.
563 564 565 566 567 568 |
# File 'lib/origami/object.rb', line 563 def indirect_parent obj = self obj = obj.parent until obj.indirect? obj end |
#initialize(*cons) ⇒ Object
Creates a new PDF Object.
402 403 404 405 406 407 408 409 410 |
# File 'lib/origami/object.rb', line 402 def initialize(*cons) @indirect = false @no, @generation = 0, 0 @document = nil @parent = nil @file_offset = nil super unless cons.empty? end |
#logicalize ⇒ Object
Returns a logicalized copy of self. See logicalize!
547 548 549 |
# File 'lib/origami/object.rb', line 547 def logicalize # :nodoc: 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.
555 556 557 |
# File 'lib/origami/object.rb', line 555 def logicalize! # :nodoc: resolve_all_references(self) end |
#native_type ⇒ Object
Returns the native type of the Object.
395 396 397 |
# File 'lib/origami/object.rb', line 395 def native_type self.class.native_type end |
#numbered? ⇒ Boolean
Returns whether an object number exists for this object.
457 458 459 |
# File 'lib/origami/object.rb', line 457 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.
443 444 445 |
# File 'lib/origami/object.rb', line 443 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.
435 436 437 |
# File 'lib/origami/object.rb', line 435 def pre_build self end |
#reference ⇒ Object
Returns an indirect reference to this object.
498 499 500 501 502 503 504 505 |
# File 'lib/origami/object.rb', line 498 def reference raise InvalidObjectError, "Cannot reference a direct object" unless indirect? ref = Reference.new(@no, @generation) ref.parent = self ref end |
#set_document(doc) ⇒ Object
594 595 596 597 598 |
# File 'lib/origami/object.rb', line 594 def set_document(doc) raise InvalidObjectError, "You cannot set the document of a direct object" unless indirect? @document = doc end |
#set_indirect(bool) ⇒ Object
Sets whether the object is indirect or not. Indirect objects are allocated numbers at build time.
416 417 418 419 420 421 422 423 424 425 426 427 428 429 |
# File 'lib/origami/object.rb', line 416 def set_indirect(bool) unless (bool == true) || (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.
580 581 582 |
# File 'lib/origami/object.rb', line 580 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.
695 696 697 698 699 700 701 702 |
# File 'lib/origami/object.rb', line 695 def to_s(data, eol: $/) content = +"" content << "#{no} #{generation} #{TOKENS.first}" << eol if indirect? && numbered? content << data content << eol << TOKENS.last << eol if indirect? && numbered? content.force_encoding('binary') end |
#type ⇒ Object
Returns the symbol type of this Object.
685 686 687 688 689 |
# File 'lib/origami/object.rb', line 685 def type name = (self.class.name or self.class.superclass.name or native_type.name) name.split("::").last.to_sym end |
#version_required ⇒ Object
:nodoc:
678 679 680 |
# File 'lib/origami/object.rb', line 678 def version_required # :nodoc: ['1.0', 0] end |
#xrefs ⇒ Object
Returns an array of references pointing to the current object.
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
# File 'lib/origami/object.rb', line 510 def xrefs raise InvalidObjectError, "Cannot find xrefs to a direct object" unless indirect? raise InvalidObjectError, "Not attached to any document" if document.nil? @document.each_object(compressed: true) .flat_map { |object| case object when Stream object.dictionary.xref_cache[reference] when ObjectCache object.xref_cache[reference] end } .compact! end |