Class: Origami::Dictionary

Inherits:
Hash
  • Object
show all
Extended by:
TypeGuessing
Includes:
CompoundObject, FieldAccessor
Defined in:
lib/origami/dictionary.rb,
lib/origami/obfuscation.rb

Overview

Class representing a Dictionary Object. Dictionaries are containers associating a Name to an embedded Object.

Direct Known Subclasses

Action, Action::GoToE::EmbeddedTarget, Action::Launch::WindowsLaunchParams, Action::RichMediaExecute::Command, AnimationStyle3D, Annotation, Annotation::AdditionalActions, Annotation::AppearanceCharacteristics, Annotation::AppearanceDictionary, Annotation::Artwork3D::Activation, Annotation::BorderEffect, Annotation::BorderStyle, Annotation::RichMedia::Activation, Annotation::RichMedia::Animation, Annotation::RichMedia::Configuration, Annotation::RichMedia::Content, Annotation::RichMedia::CuePoint, Annotation::RichMedia::Deactivation, Annotation::RichMedia::Instance, Annotation::RichMedia::Parameters, Annotation::RichMedia::Position, Annotation::RichMedia::Presentation, Annotation::RichMedia::Settings, Annotation::RichMedia::Window, Background3D, Catalog, CatalogAdditionalActions, Collection, Collection::Color, Collection::Folder, Collection::Item, Collection::Navigator, Collection::Schema, Collection::Sort, Collection::Split, Collection::Subitem, CrossSection3D, DestinationDictionary, DeveloperExtension, EmbeddedFileParameters, Encoding, Encryption::CryptFilterDictionary, Encryption::EncryptionDictionary, Extensions, FDF::Dictionary, FDF::Field, FDF::IconFit, FDF::JavaScript, FDF::NamedPageReference, FDF::Page, FDF::Template, Field::AdditionalActions, Field::CertificateSeedValue, Field::SignatureLock, Field::SignatureSeedValue, Field::Subform, FileSpec, Filter::CCITTFax::DecodeParms, Filter::Crypt::DecodeParms, Filter::DCT::DecodeParms, Filter::JBIG2::DecodeParms, Filter::Predictor::DecodeParms, Font, FontDescriptor, Function::Exponential, Function::Stitching, Graphics::ExtGState, Graphics::FormXObject::Group, Graphics::FormXObject::Reference, Graphics::Pattern::Shading, Graphics::Pattern::Shading::Axial, Graphics::Pattern::Shading::FunctionBased, Graphics::Pattern::Shading::Radial, Graphics::ReferenceDictionary, InteractiveForm, LightingScheme3D, Linearization, Measurement3D, Metadata, NameTreeNode, Names, Node3D, NumberTreeNode, OptionalContent::Configuration, OptionalContent::Group, OptionalContent::Membership, OptionalContent::Properties, OptionalContent::Usage, OptionalContent::Usage::CreatorInfo, OptionalContent::Usage::Export, OptionalContent::Usage::Language, OptionalContent::Usage::PageElement, OptionalContent::Usage::Print, OptionalContent::Usage::User, OptionalContent::Usage::View, OptionalContent::Usage::Zoom, OptionalContent::UsageApplication, Outline, OutlineItem, OutputIntent, PPKLite::AddressList, PPKLite::Catalog, PPKLite::Certificate, PPKLite::PPK, PPKLite::User, PPKLite::UserList, Page, Page::AdditionalActions, Page::BoxColorInformation, Page::BoxStyle, Page::NavigationNode, PageLabel, PageTreeNode, Perms, Projection3D, Reference3D, RenderMode3D, Requirement, Requirement::Handler, Resources, Signature::BuildData, Signature::BuildProperties, Signature::DigitalSignature, Signature::Reference, Units3D, UsageRights::TransformParams, View3D, ViewerPreferences, WebCapture::Command, WebCapture::CommandSettings, WebCapture::ContentSet, WebCapture::SourceInformation, WebCapture::SpiderInfo

Constant Summary collapse

TOKENS =

:nodoc:

%w[<< >>]
@@regexp_open =
Regexp.new(WHITESPACES + TOKENS.first + WHITESPACES)
@@regexp_close =
Regexp.new(WHITESPACES + TOKENS.last + WHITESPACES)

Instance Attribute Summary

Attributes included from ObjectCache

#names_cache, #strings_cache, #xref_cache

Attributes included from Object

#file_offset, #generation, #no, #objstm_offset, #parent

Class Method Summary collapse

Instance Method Summary collapse

Methods included from TypeGuessing

guess_type

Methods included from FieldAccessor

#method_missing, #respond_to_missing?

Methods included from CompoundObject

#copy, #delete, #include?, #update_values, #update_values!

Methods included from ObjectCache

#rebuild_caches

Methods included from Object

#cast_to, #copy, #document, #export, included, #indirect?, #indirect_parent, #logicalize, #logicalize!, #native_type, #numbered?, #post_build, #pre_build, #reference, #set_document, #set_indirect, skip_until_next_obj, #solve, #to_o, #type, typeof, #version_required, #xrefs

Constructor Details

#initialize(hash = {}, parser = nil) ⇒ Dictionary

Creates a new Dictionary.

hash

The hash representing the new Dictionary.

Raises:

  • (TypeError)


43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/origami/dictionary.rb', line 43

def initialize(hash = {}, parser = nil)
  raise TypeError, "Expected type Hash, received #{hash.class}." unless hash.is_a?(Hash)
  super()

  hash.each_pair do |k, v|
    next if k.nil?

    # Turns the values into Objects.
    key, value = k.to_o, v.to_o

    if Origami::OPTIONS[:enable_type_guessing]
      hint_type = guess_value_type(key, value)

      if hint_type.is_a?(Class) && (hint_type < value.class)
        value = value.cast_to(hint_type, parser)
      end

      if hint_type && parser && Origami::OPTIONS[:enable_type_propagation]
        if value.is_a?(Reference)
          parser.defer_type_cast(value, hint_type)
        end
      end
    end

    self[key] = value
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Origami::FieldAccessor

Class Method Details

.hint_type(_name) ⇒ Object

:nodoc:



178
179
180
# File 'lib/origami/dictionary.rb', line 178

def self.hint_type(_name)
  nil
end

.parse(stream, parser = nil) ⇒ Object

:nodoc:



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/origami/dictionary.rb', line 71

def self.parse(stream, parser = nil) # :nodoc:
  scanner = Parser.init_scanner(stream)
  offset = scanner.pos

  if scanner.skip(@@regexp_open).nil?
    raise InvalidDictionaryObjectError, "No token '#{TOKENS.first}' found"
  end

  hash = {}
  while scanner.skip(@@regexp_close).nil?
    key = Name.parse(scanner, parser)

    type = Object.typeof(scanner)
    raise InvalidDictionaryObjectError, "Invalid object for field #{key}" if type.nil?

    value = type.parse(scanner, parser)
    hash[key] = value
  end

  dict_type = if Origami::OPTIONS[:enable_type_guessing]
    guess_type(hash)
  else
    self
  end

  # Creates the Dictionary.
  dict = dict_type.new(hash, parser)

  dict.file_offset = offset
  dict
end

Instance Method Details

#[](key) ⇒ Object



165
166
167
# File 'lib/origami/dictionary.rb', line 165

def [](key)
  super(key.to_o)
end

#[]=(key, val) ⇒ Object



152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/origami/dictionary.rb', line 152

def []=(key, val)
  unless key.is_a?(Symbol) || key.is_a?(Name)
    raise TypeError, "Expecting a Name for a Dictionary entry, found #{key.class} instead."
  end

  if val.nil?
    delete(key)
    return
  end

  super(link_object(key), link_object(val))
end

#merge(dict) ⇒ Object

Merges the content of the Dictionary with another Dictionary.



148
149
150
# File 'lib/origami/dictionary.rb', line 148

def merge(dict)
  self.class.new(super)
end

#to_hObject Also known as: value



172
173
174
# File 'lib/origami/dictionary.rb', line 172

def to_h
  to_a.map! { |k, v| [k.value, v.value] }.to_h
end

#to_obfuscated_strObject



135
136
137
138
139
140
141
142
143
144
145
# File 'lib/origami/obfuscation.rb', line 135

def to_obfuscated_str
  content = TOKENS.first + Obfuscator.junk_spaces
  each_pair do |key, value|
    content << Obfuscator.junk_spaces +
      key.to_obfuscated_str + Obfuscator.junk_spaces +
      value.to_obfuscated_str + Obfuscator.junk_spaces
  end

  content << TOKENS.last
  super(content)
end

#to_s(indent: 1, tab: "\t", eol: $/) ⇒ Object

:nodoc:



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/origami/dictionary.rb', line 103

def to_s(indent: 1, tab: "\t", eol: $/) # :nodoc:
  nl = eol
  tab, nl = '', '' if indent == 0

  content = TOKENS.first + nl
  each_pair do |key, value|
    content << "#{tab * indent}#{key} "

    content <<
      if value.is_a?(Dictionary)
        value.to_s(eol: eol, indent: (indent == 0) ? 0 : indent + 1)
      else
        value.to_s(eol: eol)
      end

    content << nl
  end

  content << tab * (indent - 1) if indent > 0
  content << TOKENS.last

  super(content, eol: eol)
end

#transform_values(&b) ⇒ Object

Returns a new Dictionary object with values modified by given block.



130
131
132
133
134
# File 'lib/origami/dictionary.rb', line 130

def transform_values(&b)
  self.class.new map { |k, v|
    [k.to_sym, b.call(v)]
  }.to_h
end

#transform_values!(&b) ⇒ Object

Modifies the values of the Dictionary, leaving keys unchanged.



139
140
141
142
143
# File 'lib/origami/dictionary.rb', line 139

def transform_values!(&b)
  each_pair do |k, v|
    self[k] = b.call(unlink_object(v))
  end
end