Class: Workbook::SharedStringTable

Inherits:
Object
  • Object
show all
Defined in:
lib/writeexcel/shared_string_table.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeSharedStringTable

Returns a new instance of SharedStringTable


16
17
18
19
20
# File 'lib/writeexcel/shared_string_table.rb', line 16

def initialize
  @shared_string_table = []
  @string_to_shared_string = {}
  @str_total = 0
end

Instance Attribute Details

#str_totalObject (readonly)

Returns the value of attribute str_total


14
15
16
# File 'lib/writeexcel/shared_string_table.rb', line 14

def str_total
  @str_total
end

Instance Method Details

#<<(string) ⇒ Object


26
27
28
29
30
31
32
33
34
# File 'lib/writeexcel/shared_string_table.rb', line 26

def <<(string)
  @str_total += 1
  unless has_string?(string)
    shared_string = SharedString.new(string, str_unique)
    @shared_string_table << shared_string
    @string_to_shared_string[string] = shared_string
  end
  id(string)
end

#block_sizesObject


48
49
50
# File 'lib/writeexcel/shared_string_table.rb', line 48

def block_sizes
  @block_sizes ||= calculate_block_sizes
end

#calculate_block_sizesObject

Handling of the SST continue blocks is complicated by the need to include an additional continuation byte depending on whether the string is split between blocks or whether it starts at the beginning of the block. (There are also additional complications that will arise later when/if Rich Strings are supported). As such we cannot use the simple CONTINUE mechanism provided by the add_continue() method in BIFFwriter.pm. Thus we have to make two passes through the strings data. The first is to calculate the required block sizes and the second, in store_shared_strings(), is to write the actual strings. The first pass through the data is also used to calculate the size of the SST and CONTINUE records for use in setting the BOUNDSHEET record offsets. The downside of this is that the same algorithm repeated in store_shared_strings.


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
144
145
146
147
148
149
150
151
# File 'lib/writeexcel/shared_string_table.rb', line 65

def calculate_block_sizes
  # Iterate through the strings to calculate the CONTINUE block sizes.
  #
  # The SST blocks requires a specialised CONTINUE block, so we have to
  # ensure that the maximum data block size is less than the limit used by
  # add_continue() in BIFFwriter.pm. For simplicity we use the same size
  # for the SST and CONTINUE records:
  #   8228 : Maximum Excel97 block size
  #     -4 : Length of block header
  #     -8 : Length of additional SST header information
  #     -8 : Arbitrary number to keep within add_continue() limit
  # = 8208
  #
  continue_limit = 8208
  block_length   = 0
  written        = 0
  block_sizes    = []
  continue       = 0

  strings.each do |string|
    string_length = string.bytesize

    # Block length is the total length of the strings that will be
    # written out in a single SST or CONTINUE block.
    #
    block_length += string_length

    # We can write the string if it doesn't cross a CONTINUE boundary
    if block_length < continue_limit
      written += string_length
      next
    end

    # Deal with the cases where the next string to be written will exceed
    # the CONTINUE boundary. If the string is very long it may need to be
    # written in more than one CONTINUE record.
    encoding      = string.unpack("xx C")[0]
    split_string  = 0
    while block_length >= continue_limit
      header_length, space_remaining, align, split_string =
        Workbook.split_string_setup(encoding, split_string, continue_limit, written, continue)

      if space_remaining > header_length
        # Write as much as possible of the string in the current block
        written      += space_remaining

        # Reduce the current block length by the amount written
        block_length -= continue_limit -continue -align

        # Store the max size for this block
        block_sizes.push(continue_limit -align)

        # If the current string was split then the next CONTINUE block
        # should have the string continue flag (grbit) set unless the
        # split string fits exactly into the remaining space.
        #
        if block_length > 0
          continue = 1
        else
          continue = 0
        end
      else
        # Store the max size for this block
        block_sizes.push(written +continue)

        # Not enough space to start the string in the current block
        block_length -= continue_limit -space_remaining -continue
        continue = 0
      end

      # If the string (or substr) is small enough we can write it in the
      # new CONTINUE block. Else, go through the loop again to write it in
      # one or more CONTINUE blocks
      #
      if block_length < continue_limit
        written = block_length
      else
        written = 0
      end
    end
  end

  # Store the max size for the last block unless it is empty
  block_sizes.push(written +continue) if written +continue != 0

  block_sizes
end

#has_string?(string) ⇒ Boolean

Returns:

  • (Boolean)

22
23
24
# File 'lib/writeexcel/shared_string_table.rb', line 22

def has_string?(string)
  !!@string_to_shared_string[string]
end

#id(string) ⇒ Object


40
41
42
# File 'lib/writeexcel/shared_string_table.rb', line 40

def id(string)
  @string_to_shared_string[string].str_id
end

#str_uniqueObject


44
45
46
# File 'lib/writeexcel/shared_string_table.rb', line 44

def str_unique
  @shared_string_table.size
end

#stringsObject


36
37
38
# File 'lib/writeexcel/shared_string_table.rb', line 36

def strings
  @shared_string_table.collect { |shared_string| shared_string.string }
end