Bug #44471 - Crystal Reports generates files with short StyleRecords, which isn't...
[poi.git] / src / java / org / apache / poi / hssf / record / StyleRecord.java
blob65ca23cf34324e29773cd8e38277439971348320
2 /* ====================================================================
3 Licensed to the Apache Software Foundation (ASF) under one or more
4 contributor license agreements. See the NOTICE file distributed with
5 this work for additional information regarding copyright ownership.
6 The ASF licenses this file to You under the Apache License, Version 2.0
7 (the "License"); you may not use this file except in compliance with
8 the License. You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
17 ==================================================================== */
20 package org.apache.poi.hssf.record;
22 import org.apache.poi.util.LittleEndian;
23 import org.apache.poi.util.StringUtil;
24 import org.apache.poi.util.BitField;
25 import org.apache.poi.util.BitFieldFactory;
27 /**
28 * Title: Style Record<P>
29 * Description: Describes a builtin to the gui or user defined style<P>
30 * REFERENCE: PG 390 Microsoft Excel 97 Developer's Kit (ISBN: 1-57231-498-2)<P>
31 * @author Andrew C. Oliver (acoliver at apache dot org)
32 * @author aviks : string fixes for UserDefined Style
33 * @version 2.0-pre
36 public class StyleRecord
37 extends Record
39 public final static short sid = 0x293;
40 public final static short STYLE_USER_DEFINED = 0;
41 public final static short STYLE_BUILT_IN = 1;
43 // shared by both user defined and builtin styles
44 private short field_1_xf_index; // TODO: bitfield candidate
46 // only for built in styles
47 private byte field_2_builtin_style;
48 private byte field_3_outline_style_level;
50 // only for user defined styles
51 private short field_2_name_length; //OO doc says 16 bit length, so we believe
52 private byte field_3_string_options;
53 private BitField fHighByte;
54 private String field_4_name;
56 public StyleRecord()
60 /**
61 * Constructs a Style record and sets its fields appropriately.
62 * @param in the RecordInputstream to read the record from
65 public StyleRecord(RecordInputStream in)
67 super(in);
70 protected void validateSid(short id)
72 if (id != sid)
74 throw new RecordFormatException("NOT A STYLE RECORD");
78 protected void fillFields(RecordInputStream in)
80 fHighByte = BitFieldFactory.getInstance(0x01); //have to init here, since we are being called
81 //from super, and class level init hasnt been done.
82 field_1_xf_index = in.readShort();
83 if (getType() == STYLE_BUILT_IN)
85 field_2_builtin_style = in.readByte();
86 field_3_outline_style_level = in.readByte();
88 else if (getType() == STYLE_USER_DEFINED)
90 field_2_name_length = in.readShort();
92 // Some files from Crystal Reports lack
93 // the remaining fields, which is naughty
94 if(in.remaining() > 0) {
95 field_3_string_options = in.readByte();
97 byte[] string = in.readRemainder();
98 if (fHighByte.isSet(field_3_string_options)) {
99 field_4_name= StringUtil.getFromUnicodeBE(string, 0, field_2_name_length);
100 } else {
101 field_4_name=StringUtil.getFromCompressedUnicode(string, 0, field_2_name_length);
106 // todo sanity check exception to make sure we're one or the other
110 * set the entire index field (including the type) (see bit setters that reference this method)
111 * @param index bitmask
114 public void setIndex(short index)
116 field_1_xf_index = index;
119 // bitfields for field 1
122 * set the type of the style (builtin or user-defined)
123 * @see #STYLE_USER_DEFINED
124 * @see #STYLE_BUILT_IN
125 * @param type of style (userdefined/builtin)
126 * @see #setIndex(short)
129 public void setType(short type)
131 field_1_xf_index = setField(field_1_xf_index, type, 0x8000, 15);
135 * set the actual index of the style extended format record
136 * @see #setIndex(short)
137 * @param index of the xf record
140 public void setXFIndex(short index)
142 field_1_xf_index = setField(field_1_xf_index, index, 0x1FFF, 0);
145 // end bitfields
146 // only for user defined records
149 * if this is a user defined record set the length of the style name
150 * @param length of the style's name
151 * @see #setName(String)
154 public void setNameLength(byte length)
156 field_2_name_length = length;
160 * set the style's name
161 * @param name of the style
162 * @see #setNameLength(byte)
165 public void setName(String name)
167 field_4_name = name;
168 //TODO set name length and string options
171 // end user defined
172 // only for buildin records
175 * if this is a builtin style set teh number of the built in style
176 * @param builtin style number (0-7)
180 public void setBuiltin(byte builtin)
182 field_2_builtin_style = builtin;
186 * set the row or column level of the style (if builtin 1||2)
189 public void setOutlineStyleLevel(byte level)
191 field_3_outline_style_level = level;
194 // end builtin records
195 // field 1
198 * get the entire index field (including the type) (see bit getters that reference this method)
199 * @return bitmask
202 public short getIndex()
204 return field_1_xf_index;
207 // bitfields for field 1
210 * get the type of the style (builtin or user-defined)
211 * @see #STYLE_USER_DEFINED
212 * @see #STYLE_BUILT_IN
213 * @return type of style (userdefined/builtin)
214 * @see #getIndex()
217 public short getType()
219 return ( short ) ((field_1_xf_index & 0x8000) >> 15);
223 * get the actual index of the style extended format record
224 * @see #getIndex()
225 * @return index of the xf record
228 public short getXFIndex()
230 return ( short ) (field_1_xf_index & 0x1FFF);
233 // end bitfields
234 // only for user defined records
237 * if this is a user defined record get the length of the style name
238 * @return length of the style's name
239 * @see #getName()
242 public short getNameLength()
244 return field_2_name_length;
248 * get the style's name
249 * @return name of the style
250 * @see #getNameLength()
253 public String getName()
255 return field_4_name;
258 // end user defined
259 // only for buildin records
262 * if this is a builtin style get the number of the built in style
263 * @return builtin style number (0-7)
267 public byte getBuiltin()
269 return field_2_builtin_style;
273 * get the row or column level of the style (if builtin 1||2)
276 public byte getOutlineStyleLevel()
278 return field_3_outline_style_level;
281 // end builtin records
282 public String toString()
284 StringBuffer buffer = new StringBuffer();
286 buffer.append("[STYLE]\n");
287 buffer.append(" .xf_index_raw = ")
288 .append(Integer.toHexString(getIndex())).append("\n");
289 buffer.append(" .type = ")
290 .append(Integer.toHexString(getType())).append("\n");
291 buffer.append(" .xf_index = ")
292 .append(Integer.toHexString(getXFIndex())).append("\n");
293 if (getType() == STYLE_BUILT_IN)
295 buffer.append(" .builtin_style = ")
296 .append(Integer.toHexString(getBuiltin())).append("\n");
297 buffer.append(" .outline_level = ")
298 .append(Integer.toHexString(getOutlineStyleLevel()))
299 .append("\n");
301 else if (getType() == STYLE_USER_DEFINED)
303 buffer.append(" .name_length = ")
304 .append(Integer.toHexString(getNameLength())).append("\n");
305 buffer.append(" .name = ").append(getName())
306 .append("\n");
308 buffer.append("[/STYLE]\n");
309 return buffer.toString();
312 private short setField(int fieldValue, int new_value, int mask,
313 int shiftLeft)
315 return ( short ) ((fieldValue & ~mask)
316 | ((new_value << shiftLeft) & mask));
319 public int serialize(int offset, byte [] data)
321 LittleEndian.putShort(data, 0 + offset, sid);
322 if (getType() == STYLE_BUILT_IN)
324 LittleEndian.putShort(data, 2 + offset,
325 (( short ) 0x04)); // 4 bytes (8 total)
327 else
329 LittleEndian.putShort(data, 2 + offset,
330 (( short ) (getRecordSize()-4)));
332 LittleEndian.putShort(data, 4 + offset, getIndex());
333 if (getType() == STYLE_BUILT_IN)
335 data[ 6 + offset ] = getBuiltin();
336 data[ 7 + offset ] = getOutlineStyleLevel();
338 else
340 LittleEndian.putShort(data, 6 + offset , getNameLength());
341 data[8+offset]=this.field_3_string_options;
342 StringUtil.putCompressedUnicode(getName(), data, 9 + offset);
344 return getRecordSize();
347 public int getRecordSize()
349 int retval;
351 if (getType() == STYLE_BUILT_IN)
353 retval = 8;
355 else
357 if (fHighByte.isSet(field_3_string_options)) {
358 retval= 9+2*getNameLength();
359 }else {
360 retval = 9 + getNameLength();
363 return retval;
366 public short getSid()
368 return sid;