summaryrefslogtreecommitdiffhomepage
path: root/lib/axlsx/util/storage.rb
blob: 1e12b2d468e0da977fdb823abd69cae028458165 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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
70
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# frozen_string_literal: true

module Axlsx
  # The Storage class represents a storage object or stream in a compound file.
  class Storage
    # Packing for the Storage when pushing an array of items into a byte stream
    # Name, name length, type, color, left sibling, right sibling, child, classid, state, created, modified, sector, size
    PACKING = "s32 s1 c2 l3 x16 x4 q2 l q"

    # storage types
    TYPES = {
      :root => 5,
      :stream => 2,
      :storage => 1
    }.freeze

    # Creates a byte string for this storage
    # @return [String]
    def to_s
      data = [@name.concat(Array.new(32 - @name.size, 0)),
              @name_size,
              @type,
              @color,
              @left,
              @right,
              @child,
              @created,
              @modified,
              @sector,
              @size].flatten
      data.pack(PACKING)
    end

    # storage colors
    COLORS = {
      :red => 0,
      :black => 1
    }

    # The color of this node in the directory tree. Defaults to black if not specified
    # @return [Integer] color
    attr_reader :color

    # Sets the color for this storage
    # @param [Integer] v Must be one of the COLORS constant hash values
    def color=(v)
      RestrictionValidator.validate :storage_color, COLORS.values, v
      @color = v
    end

    # The size of the name for this node.
    # interesting to see that office actually uses 'R' for the root directory and lists the size as 2 bytes - thus is it *NOT* null
    # terminated. I am making this r/w so that I can override the size
    # @return [Integer] color
    attr_reader :name_size

    # the name of the stream
    attr_reader :name

    # sets the name of the stream.
    # This will automatically set the name_size attribute
    # @return [String] name
    def name=(v)
      @name = v.bytes.to_a << 0
      @name_size = @name.size * 2
    end

    # The size of the stream
    attr_reader :size

    # The stream associated with this storage
    attr_reader :data

    # Set the data associated with the stream. If the stream type is undefined, we automatically specify the storage as a stream type.    # with the exception of storages that are type root, all storages with data should be type stream.
    # @param [String] v The data for this storages stream
    # @return [Array]
    def data=(v)
      Axlsx::validate_string(v)
      self.type = TYPES[:stream] unless @type
      @size = v.size
      @data = v.bytes.to_a
    end

    # The starting sector for the stream. If this storage is not a stream, or the root node this is nil
    # @return [Integer] sector
    attr_accessor :sector

    # The 0 based index in the directoies chain for this the left sibling of this storage.

    # @return [Integer] left
    attr_accessor :left

    # The 0 based index in the directoies chain for this the right sibling of this storage.
    # @return [Integer] right
    attr_accessor :right

    # The 0 based index in the directoies chain for the child of this storage.
    # @return [Integer] child
    attr_accessor :child

    # The created attribute for the storage
    # @return [Integer] created
    attr_accessor :created

    # The modified attribute for the storage
    # @return [Integer] modified
    attr_accessor :modified

    # The type of storage
    # see TYPES
    # @return [Integer] type
    attr_reader :type

    # Sets the type for this storage.
    # @param [Integer] v the type to specify must be one of the TYPES constant hash values.
    def type=(v)
      RestrictionValidator.validate :storage_type, TYPES.values, v
      @type = v
    end

    # Creates a new storage object.
    # @param [String] name the name of the storage
    # @option options [Integer] color (black)
    # @option options [Integer] type (storage)
    # @option options [String] data
    # @option options [Integer] left (-1)
    # @option options [Integer] right (-1)
    # @option options [Integer] child (-1)
    # @option options [Integer] created (0)
    # @option options [Integer] modified (0)
    # @option options [Integer] sector (0)
    def initialize(name, options = {})
      @left = @right = @child = -1
      @sector = @size = @created = @modified = 0
      options.each do |o|
        self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
      end
      @color ||= COLORS[:black]
      @type ||= (data.nil? ? TYPES[:storage] : TYPES[:stream])
      self.name = name
    end
  end
end