ru_excel 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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