ru_excel 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,231 @@
1
+ =begin
2
+ The XF record is able to store explicit cell formatting attributes or the
3
+ attributes of a cell style. Explicit formatting includes the reference to
4
+ a cell style XF record. This allows to extend a defined cell style with
5
+ some explicit attributes. The formatting attributes are divided into
6
+ 6 groups
7
+
8
+ Group Attributes
9
+ -------------------------------------
10
+ Number format Number format index (index to FORMAT record)
11
+ Font Font index (index to FONT record)
12
+ Alignment Horizontal and vertical alignment, text wrap, indentation,
13
+ orientation/rotation, text direction
14
+ Border Border line styles and colours
15
+ Background Background area style and colours
16
+ Protection Cell locked, formula hidden
17
+
18
+ For each group a flag in the cell XF record specifies whether to use the
19
+ attributes contained in that XF record or in the referenced style
20
+ XF record. In style XF records, these flags specify whether the attributes
21
+ will overwrite explicit cell formatting when the style is applied to
22
+ a cell. Changing a cell style (without applying this style to a cell) will
23
+ change all cells which already use that style and do not contain explicit
24
+ cell attributes for the changed style attributes. If a cell XF record does
25
+ not contain explicit attributes in a group (if the attribute group flag
26
+ is not set), it repeats the attributes of its style XF record.
27
+ =end
28
+ require File.dirname(__FILE__)+'/biff_records'
29
+
30
+ module Excel
31
+ class Font
32
+ ESCAPEMENT_NONE = 0x00
33
+ ESCAPEMENT_SUPERSCRIPT = 0x01
34
+ ESCAPEMENT_SUBSCRIPT = 0x02
35
+
36
+ UNDERLINE_NONE = 0x00
37
+ UNDERLINE_SINGLE = 0x01
38
+ UNDERLINE_SINGLE_ACC = 0x21
39
+ UNDERLINE_DOUBLE = 0x02
40
+ UNDERLINE_DOUBLE_ACC = 0x22
41
+
42
+ FAMILY_NONE = 0x00
43
+ FAMILY_ROMAN = 0x01
44
+ FAMILY_SWISS = 0x02
45
+ FAMILY_MODERN = 0x03
46
+ FAMILY_SCRIPT = 0x04
47
+ FAMILY_DECORARTIVE = 0x05
48
+
49
+ CHARSET_ANSI_LATIN = 0x00
50
+ CHARSET_SYS_DEFAULT = 0x01
51
+ CHARSET_SYMBOL = 0x02
52
+ CHARSET_APPLE_ROMAN = 0x4D
53
+ CHARSET_ANSI_JAP_SHIFT_JIS = 0x80
54
+ CHARSET_ANSI_KOR_HANGUL = 0x81
55
+ CHARSET_ANSI_KOR_JOHAB = 0x82
56
+ CHARSET_ANSI_CHINESE_GBK = 0x86
57
+ CHARSET_ANSI_CHINESE_BIG5 = 0x88
58
+ CHARSET_ANSI_GREEK = 0xA1
59
+ CHARSET_ANSI_TURKISH = 0xA2
60
+ CHARSET_ANSI_VIETNAMESE = 0xA3
61
+ CHARSET_ANSI_HEBREW = 0xB1
62
+ CHARSET_ANSI_ARABIC = 0xB2
63
+ CHARSET_ANSI_BALTIC = 0xBA
64
+ CHARSET_ANSI_CYRILLIC = 0xCC
65
+ CHARSET_ANSI_THAI = 0xDE
66
+ CHARSET_ANSI_LATIN_II = 0xEE
67
+ CHARSET_OEM_LATIN_I = 0xFF
68
+
69
+ def initialize
70
+ # twip = 1/20 of a point = 1/1440 of a inch
71
+ # usually resolution == 96 pixels per 1 inch
72
+ # (rarely 120 pixels per 1 inch or another one)
73
+
74
+ @height = 0x00C8 # 200: this is font with height 10 points
75
+ @italic = false
76
+ @struck_out = false
77
+ @outline = false
78
+ @shadow = false
79
+ @colour_index = 0x7FFF
80
+ @bold = false
81
+ @_weight = 0x0190 # 0x02BC gives bold font
82
+ @escapement = ESCAPEMENT_NONE
83
+ @underline = UNDERLINE_NONE
84
+ @family = FAMILY_NONE
85
+ @charset = CHARSET_ANSI_CYRILLIC
86
+ @name = 'Arial'
87
+ end
88
+ attr_accessor :height, :italic, :struck_out, :outline, :shadow, :colour_index, :bold, :_weight
89
+ attr_accessor :underline, :family, :charset, :name
90
+
91
+ def get_biff_record
92
+ height = @height
93
+
94
+ options = 0x00
95
+ if @bold
96
+ options |= 0x01
97
+ @_weight = 0x02BC
98
+ end
99
+ options |= 0x02 if @italic
100
+ options |= 0x04 if @underline != UNDERLINE_NONE
101
+ options |= 0x08 if @struck_out
102
+ options |= 0x010 if @outline
103
+ options |= 0x020 if @shadow
104
+
105
+ colour_index = @colour_index
106
+ weight = @_weight
107
+ escapement = @escapement
108
+ underline = @underline
109
+ family = @family
110
+ charset = @charset
111
+ name = @name
112
+
113
+ BiffRecord.fontRecord(
114
+ height, options, colour_index, weight, escapement,
115
+ underline, family, charset,
116
+ name)
117
+ end
118
+ end
119
+
120
+ class Alignment
121
+ HORZ_GENERAL = 0x00
122
+ HORZ_LEFT = 0x01
123
+ HORZ_CENTER = 0x02
124
+ HORZ_RIGHT = 0x03
125
+ HORZ_FILLED = 0x04
126
+ HORZ_JUSTIFIED = 0x05 # BIFF4-BIFF8X
127
+ HORZ_CENTER_ACROSS_SEL = 0x06 # Centred across selection (BIFF4-BIFF8X)
128
+ HORZ_DISTRIBUTED = 0x07 # Distributed (BIFF8X)
129
+
130
+ VERT_TOP = 0x00
131
+ VERT_CENTER = 0x01
132
+ VERT_BOTTOM = 0x02
133
+ VERT_JUSTIFIED = 0x03 # Justified (BIFF5-BIFF8X)
134
+ VERT_DISIRIBUTED = 0x04 # Distributed (BIFF8X)
135
+
136
+ DIRECTION_GENERAL = 0x00 # BIFF8X
137
+ DIRECTION_LR = 0x01
138
+ DIRECTION_RL = 0x02
139
+
140
+ ORIENTATION_NOT_ROTATED = 0x00
141
+ ORIENTATION_STACKED = 0x01
142
+ ORIENTATION_90_CC = 0x02
143
+ ORIENTATION_90_CW = 0x03
144
+
145
+ ROTATION_0_ANGLE = 0x00
146
+ ROTATION_STACKED = 0xFF
147
+
148
+ WRAP_AT_RIGHT = 0x01
149
+ NOT_WRAP_AT_RIGHT = 0x00
150
+
151
+ SHRINK_TO_FIT = 0x01
152
+ NOT_SHRINK_TO_FIT = 0x00
153
+
154
+ def initialize
155
+ @horz = HORZ_GENERAL
156
+ @vert = VERT_BOTTOM
157
+ @dire = DIRECTION_GENERAL
158
+ @orie = ORIENTATION_NOT_ROTATED
159
+ @rota = ROTATION_0_ANGLE
160
+ @wrap = NOT_WRAP_AT_RIGHT
161
+ # @wrap = WRAP_AT_RIGHT
162
+ @shri = NOT_SHRINK_TO_FIT
163
+ @inde = 0
164
+ @merg = 0
165
+ end
166
+ attr_accessor :horz, :vert, :dire, :orie, :rota, :wrap, :shri, :inde, :merg
167
+ end
168
+
169
+ class Borders
170
+ NO_LINE = 0x00
171
+ THIN = 0x01
172
+ MEDIUM = 0x02
173
+ DASHED = 0x03
174
+ DOTTED = 0x04
175
+ THICK = 0x05
176
+ DOUBLE = 0x06
177
+ HAIR = 0x07
178
+ #The following for BIFF8
179
+ MEDIUM_DASHED = 0x08
180
+ THIN_DASH_DOTTED = 0x09
181
+ MEDIUM_DASH_DOTTED = 0x0A
182
+ THIN_DASH_DOT_DOTTED = 0x0B
183
+ MEDIUM_DASH_DOT_DOTTED = 0x0C
184
+ SLANTED_MEDIUM_DASH_DOTTED = 0x0D
185
+
186
+ NEED_DIAG1 = 0x01
187
+ NEED_DIAG2 = 0x01
188
+ NO_NEED_DIAG1 = 0x00
189
+ NO_NEED_DIAG2 = 0x00
190
+
191
+ def initialize
192
+ @left = NO_LINE
193
+ @right = NO_LINE
194
+ @top = NO_LINE
195
+ @bottom = NO_LINE
196
+ @diag = NO_LINE
197
+
198
+ @left_colour = 0x40
199
+ @right_colour = 0x40
200
+ @top_colour = 0x40
201
+ @bottom_colour = 0x40
202
+ @diag_colour = 0x40
203
+
204
+ @need_diag1 = NO_NEED_DIAG1
205
+ @need_diag2 = NO_NEED_DIAG2
206
+ end
207
+
208
+ attr_accessor :left, :right, :top, :bottom, :diag, :left_colour, :right_colour, :top_colour, :bottom_colour
209
+ attr_accessor :diag_colour, :need_diag1, :need_diag2
210
+ end
211
+
212
+ class Pattern
213
+ # patterns 0x00 - 0x12
214
+ NO_PATTERN = 0x00
215
+ SOLID_PATTERN = 0x01
216
+ def initialize
217
+ @pattern = NO_PATTERN
218
+ @pattern_fore_colour = 0x40
219
+ @pattern_back_colour = 0x41
220
+ end
221
+ attr_accessor :pattern, :pattern_fore_colour, :pattern_back_colour
222
+ end
223
+
224
+ class Protection
225
+ def initialize
226
+ @cell_locked = 1
227
+ @formula_hidden = 0
228
+ end
229
+ attr_accessor :cell_locked, :formula_hidden
230
+ end
231
+ end
@@ -0,0 +1,170 @@
1
+ dir = File.dirname(__FILE__)
2
+ require dir+'/biff_records'
3
+ require dir+'/worksheet'
4
+ require dir+'/style'
5
+ require 'date'
6
+
7
+ module Excel
8
+ class Row
9
+
10
+ #################################################################
11
+ ## Constructor
12
+ #################################################################
13
+ def initialize(index, parent_sheet)
14
+ @idx = index
15
+ @parent = parent_sheet
16
+ @parent_wb = parent_sheet.parent
17
+ @cells = []
18
+ @min_col_idx = 0
19
+ @max_col_idx = 0
20
+ @total_str = 0
21
+ @xf_index = 0x0F
22
+ @has_default_format = 0
23
+ @height_in_pixels = 0x11
24
+
25
+ @height = 0x00FF
26
+ @has_default_height = 0x00
27
+ @level = 0
28
+ @collapse = 0
29
+ @hidden = 0
30
+ @space_above = 0
31
+ @space_below = 0
32
+ end
33
+
34
+ attr_accessor :level
35
+
36
+ def _adjust_height(style)
37
+ twips = style.font.height
38
+ points = twips.to_f/20.0
39
+ # Cell height in pixels can be calcuted by following approx. formula
40
+ # cell height in pixels = font height in points * 83/50 + 2/5
41
+ # It works when screen resolution is 96 dpi
42
+ pix = (points*83.0/50.0 + 2.0/5.0.to_i).round
43
+ if pix > @height_in_pixels
44
+ @height_in_pixels = pix
45
+ end
46
+ end
47
+
48
+
49
+ def _adjust_bound_col_idx(*args)
50
+ for arg in args
51
+ if arg < @min_col_idx
52
+ @min_col_idx = arg
53
+ elsif arg > @max_col_idx
54
+ @max_col_idx = arg
55
+ end
56
+ end
57
+ end
58
+
59
+ EPOCH = Date.new(1899, 12, 31)
60
+ TIME_EPOCH = Time.mktime(1902, 1, 1)
61
+ TIME_EPOCH_ADD = (Date.new(1902, 1, 1) - Date.new(1899, 12, 31))
62
+ def _excel_date_dt(date)
63
+ if Date === date
64
+ xldate = (date - EPOCH).to_f + date.offset.to_f
65
+ elsif Time === date
66
+ xldate = (date - TIME_EPOCH +
67
+ date.utc_offset - TIME_EPOCH.utc_offset).to_f / (24 * 60 * 60) +
68
+ TIME_EPOCH_ADD
69
+ else
70
+ raise date.inspect+' is not a date'
71
+ end
72
+ # Add a day for Excel's missing leap day in 1900
73
+ xldate += 1 if xldate > 59
74
+ xldate
75
+ end
76
+
77
+ def get_height_in_pixels
78
+ @height_in_pixels
79
+ end
80
+
81
+
82
+ def set_style(style)
83
+ _adjust_height(style)
84
+ @xf_index = @parent_wb.add_style(style)
85
+ end
86
+
87
+
88
+ def get_xf_index
89
+ @xf_index
90
+ end
91
+
92
+
93
+ def get_cells_count
94
+ @cells.length
95
+ end
96
+
97
+
98
+ def get_min_col
99
+ @min_col_idx
100
+ end
101
+
102
+
103
+ def get_max_col
104
+ @min_col_idx
105
+ end
106
+
107
+
108
+ def get_str_count
109
+ @total_str
110
+ end
111
+
112
+
113
+ def get_row_biff_data
114
+ height_options = (@height & 0x07FFF)
115
+ height_options |= (@has_default_height & 0x01) << 15
116
+
117
+ options = (@level & 0x07) << 0
118
+ options |= (@collapse & 0x01) << 4
119
+ options |= (@hidden & 0x01) << 5
120
+ options |= (0x00 & 0x01) << 6
121
+ options |= (0x01 & 0x01) << 8
122
+ if @xf_index != 0x0F
123
+ options |= (0x01 & 0x01) << 7
124
+ else
125
+ options |= (0x00 & 0x01) << 7
126
+ end
127
+ options |= (@xf_index & 0x0FFF) << 16
128
+ options |= (0x00 & @space_above) << 28
129
+ options |= (0x00 & @space_below) << 29
130
+
131
+ BiffRecord.rowRecord(@idx, @min_col_idx, @max_col_idx, height_options, options)
132
+ end
133
+
134
+ def get_cells_biff_data
135
+ #@cells.map{|c| c.get_biff_data()}.join('')
136
+ @cells.join('')
137
+ end
138
+
139
+
140
+ def get_index
141
+ @idx
142
+ end
143
+
144
+
145
+ def write(col, label, style)
146
+ _adjust_height(style)
147
+ _adjust_bound_col_idx(col)
148
+ if String === label
149
+ if label.length > 0
150
+ @cells << Cell.strCell(self, col, @parent_wb.add_style(style), @parent_wb.add_str(label))
151
+ @total_str += 1
152
+ else
153
+ @cells << Cell.blankCell(self, col, @parent_wb.add_style(style))
154
+ end
155
+ elsif Numeric === label
156
+ @cells << Cell.numberCell(self, col, @parent_wb.add_style(style), label)
157
+ elsif Date === label or Time === label
158
+ @cells << Cell.numberCell(self, col, @parent_wb.add_style(style), _excel_date_dt(label))
159
+ else
160
+ @cells << Cell.formulaCell(self, col, @parent_wb.add_style(style), label)
161
+ end
162
+ end
163
+
164
+ def write_blanks(c1, c2, style)
165
+ _adjust_height(style)
166
+ _adjust_bound_col_idx(c1, c2)
167
+ @cells << Cell.mulBlankCell(self, c1, c2, @parent_wb.add_style(style))
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,135 @@
1
+ dir = File.dirname(__FILE__)
2
+ require dir+'/formatting'
3
+ require dir+'/biff_records'
4
+
5
+ module Excel
6
+
7
+ class XFStyle
8
+ Default_num_format = 'general'
9
+ Default_font = Font.new()
10
+ Default_alignment = Alignment.new()
11
+ Default_borders = Borders.new()
12
+ Default_pattern = Pattern.new()
13
+ Default_protection = Protection.new()
14
+
15
+ def initialize
16
+ @num_format_str = Default_num_format
17
+ @font = Default_font
18
+ @alignment = Default_alignment
19
+ @borders = Default_borders
20
+ @pattern = Default_pattern
21
+ @protection = Default_protection
22
+ end
23
+ attr_accessor :num_format_str, :font, :alignment, :borders, :pattern, :protection
24
+ end
25
+
26
+ class StyleCollection
27
+ Std_num_fmt_list = [
28
+ 'general',
29
+ '0',
30
+ '0.00',
31
+ '#,##0',
32
+ '#,##0.00',
33
+ '"$"#,##0_);("$"#,##',
34
+ '"$"#,##0_);[Red]("$"#,##',
35
+ '"$"#,##0.00_);("$"#,##',
36
+ '"$"#,##0.00_);[Red]("$"#,##',
37
+ '0%',
38
+ '0.00%',
39
+ '0.00E+00',
40
+ '# ?/?',
41
+ '# ??/??',
42
+ 'M/D/YY',
43
+ 'D-MMM-YY',
44
+ 'D-MMM',
45
+ 'MMM-YY',
46
+ 'h:mm AM/PM',
47
+ 'h:mm:ss AM/PM',
48
+ 'h:mm',
49
+ 'h:mm:ss',
50
+ 'M/D/YY h:mm',
51
+ '_(#,##0_);(#,##0)',
52
+ '_(#,##0_);[Red](#,##0)',
53
+ '_(#,##0.00_);(#,##0.00)',
54
+ '_(#,##0.00_);[Red](#,##0.00)',
55
+ '_("$"* #,##0_);_("$"* (#,##0);_("$"* "-"_);_(@_)',
56
+ '_(* #,##0_);_(* (#,##0);_(* "-"_);_(@_)',
57
+ '_("$"* #,##0.00_);_("$"* (#,##0.00);_("$"* "-"??_);_(@_)',
58
+ '_(* #,##0.00_);_(* (#,##0.00);_(* "-"??_);_(@_)',
59
+ 'mm:ss',
60
+ '[h]:mm:ss',
61
+ 'mm:ss.0',
62
+ '##0.0E+0',
63
+ '@'
64
+ ]
65
+
66
+ NumFormats = {}
67
+ for fmtidx, fmtstr in (0...23).zip(Std_num_fmt_list[(0)...(23)])
68
+ NumFormats[fmtstr] = fmtidx
69
+ end
70
+ for fmtidx, fmtstr in (37...50).zip(Std_num_fmt_list[(23)..-1])
71
+ NumFormats[fmtstr] = fmtidx
72
+ end
73
+
74
+ def initialize
75
+ @_fonts = {}
76
+ @_fonts[Font.new()] = 0
77
+ @_fonts[Font.new()] = 1
78
+ @_fonts[Font.new()] = 2
79
+ @_fonts[Font.new()] = 3
80
+ # The font with index 4 is omitted in all BIFF versions
81
+ @_fonts[Font.new()] = 5
82
+ @_num_formats = NumFormats.dup
83
+
84
+ @_xf = {}
85
+ @default_style = XFStyle.new()
86
+ @_default_xf = _add_style(@default_style)[0]
87
+ end
88
+ attr_accessor :default_style
89
+
90
+ def add(style)
91
+ style == nil ? 0x10 : _add_style(style)[1]
92
+ end
93
+
94
+ def _add_style(style)
95
+ num_format_str = style.num_format_str
96
+ num_format_idx = @_num_formats[num_format_str] ||=
97
+ 163 + @_num_formats.length - Std_num_fmt_list.length
98
+ font = style.font
99
+ font_idx = @_fonts[font] ||= @_fonts.length + 1
100
+ xf = [font_idx, num_format_idx, style.alignment, style.borders, style.pattern, style.protection]
101
+ xf_index = @_xf[xf] ||= 0x10 + @_xf.length
102
+ [xf, xf_index]
103
+ end
104
+
105
+ def get_biff_data
106
+ result = ''
107
+ result << _all_fonts()
108
+ result << _all_num_formats()
109
+ result << _all_cell_styles()
110
+ result << _all_styles()
111
+ result
112
+ end
113
+
114
+ def _all_fonts
115
+ fonts = @_fonts.map{|k,v| [v,k]}.sort!
116
+ fonts.collect!{|_,font| font.get_biff_record}
117
+ fonts.join('')
118
+ end
119
+
120
+ def _all_num_formats
121
+ formats = @_num_formats.select{|k, v| v>=163}.to_a.each{|a| a.reverse!}
122
+ formats.map!{|fmtidx, fmtstr| BiffRecord.numberFormatRecord(fmtidx, fmtstr)}
123
+ formats.join('')
124
+ end
125
+
126
+ def _all_cell_styles
127
+ result = BiffRecord.xfRecord(@_default_xf, 'style') * 16
128
+ result << @_xf.map{|k,v| [v,k]}.sort!.collect!{|_,xf| BiffRecord.xfRecord(xf)}.join('')
129
+ end
130
+
131
+ def _all_styles
132
+ BiffRecord.styleRecord()
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,73 @@
1
+ =begin
2
+ From BIFF8 on, strings are always stored using UTF-16LE text encoding. The
3
+ character array is a sequence of 16-bit values4. Additionally it is
4
+ possible to use a compressed format, which omits the high bytes of all
5
+ characters, if they are all zero.
6
+
7
+ The following tables describe the standard format of the entire string, but
8
+ in many records the strings differ from this format. This will be mentioned
9
+ separately. It is possible (but not required) to store Rich-Text formatting
10
+ information and Asian phonetic information inside a Unicode string. This
11
+ results in four different ways to store a string. The character array
12
+ is not zero-terminated.
13
+
14
+ The string consists of the character count (as usual an 8-bit value or
15
+ a 16-bit value), option flags, the character array and optional formatting
16
+ information. If the string is empty, sometimes the option flags field will
17
+ not occur. This is mentioned at the respective place.
18
+
19
+ Offset Size Contents
20
+ 0 1 or 2 Length of the string (character count, ln)
21
+ 1 or 2 1 Option flags:
22
+ Bit Mask Contents
23
+ 0 01H Character compression (ccompr):
24
+ 0 = Compressed (8-bit characters)
25
+ 1 = Uncompressed (16-bit characters)
26
+ 2 04H Asian phonetic settings (phonetic):
27
+ 0 = Does not contain Asian phonetic settings
28
+ 1 = Contains Asian phonetic settings
29
+ 3 08H Rich-Text settings (richtext):
30
+ 0 = Does not contain Rich-Text settings
31
+ 1 = Contains Rich-Text settings
32
+ [2 or 3] 2 (optional, only if richtext=1) Number of Rich-Text formatting runs (rt)
33
+ [var.] 4 (optional, only if phonetic=1) Size of Asian phonetic settings block (in bytes, sz)
34
+ var. ln or
35
+ 2�ln Character array (8-bit characters or 16-bit characters, dependent on ccompr)
36
+ [var.] 4�rt (optional, only if richtext=1) List of rt formatting runs
37
+ [var.] sz (optional, only if phonetic=1) Asian Phonetic Settings Block
38
+ =end
39
+
40
+
41
+ require 'iconv'
42
+ module Excel
43
+ module UnicodeUtils
44
+
45
+ def u2ints(str)
46
+ Excel::ICONV[:to_unicode].iconv(str).unpack('S*')
47
+ end
48
+
49
+ def u2bytes(str)
50
+ Excel::ICONV[:to_unicode].iconv(str)
51
+ end
52
+
53
+ def upack2(str)
54
+ begin
55
+ ustr = Excel::ICONV[:check_ascii].iconv(str)
56
+ [str.length, 0].pack('SC')+str
57
+ rescue Iconv::IllegalSequence
58
+ ustr = u2bytes(str)
59
+ [ustr.length / 2, 1].pack('SC')+ustr
60
+ end
61
+ end
62
+
63
+ def upack1(str)
64
+ begin
65
+ ustr = Excel::ICONV[:check_ascii].iconv(str)
66
+ [str.length, 0].pack('CC')+str
67
+ rescue Iconv::IllegalSequence
68
+ ustr = u2bytes(str)
69
+ [ustr.length / 2, 1].pack('CC')+ustr
70
+ end
71
+ end
72
+ end
73
+ end