1
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
9
10 http://www.apache.org/licenses/LICENSE-2.0
11
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 ==================================================================== */
18
19
20 package org.apache.poi.hssf.record;
21
22 import org.apache.poi.util.LittleEndian;
23 import org.apache.poi.util.StringUtil;
24
25 /**
26 * Supports the STRING record structure.
27 *
28 * @author Glen Stampoultzis (glens at apache.org)
29 */
30 public class StringRecord
31 extends Record
32 {
33 public final static short sid = 0x207;
34 private int field_1_string_length;
35 private byte field_2_unicode_flag;
36 private String field_3_string;
37
38
39 public StringRecord()
40 {
41 }
42
43 /**
44 * Constructs a String record and sets its fields appropriately.
45 *
46 * @param in the RecordInputstream to read the record from
47 */
48 public StringRecord(RecordInputStream in)
49 {
50 super(in);
51 }
52
53
54 /**
55 * Throw a runtime exception in the event of a
56 * record passed with a differing ID.
57 *
58 * @param id alleged id for this record
59 */
60 protected void validateSid( short id )
61 {
62 if (id != sid)
63 {
64 throw new RecordFormatException("Not a valid StringRecord");
65 }
66 }
67
68 /**
69 * @param in the RecordInputstream to read the record from
70 */
71 protected void fillFields( RecordInputStream in)
72 {
73 field_1_string_length = in.readShort();
74 field_2_unicode_flag = in.readByte();
75 byte[] data = in.readRemainder();
76 //Why isnt this using the in.readString methods???
77 if (isUnCompressedUnicode())
78 {
79 field_3_string = StringUtil.getFromUnicodeLE(data, 0, field_1_string_length );
80 }
81 else
82 {
83 field_3_string = StringUtil.getFromCompressedUnicode(data, 0, field_1_string_length);
84 }
85 }
86
87 public void processContinueRecord(byte[] data) {
88 if(isUnCompressedUnicode()) {
89 field_3_string += StringUtil.getFromUnicodeLE(data, 0, field_1_string_length - field_3_string.length());
90 } else {
91 field_3_string += StringUtil.getFromCompressedUnicode(data, 0, field_1_string_length - field_3_string.length());
92 }
93 }
94
95 public boolean isInValueSection()
96 {
97 return true;
98 }
99
100 private int getStringByteLength()
101 {
102 return isUnCompressedUnicode() ? field_1_string_length * 2 : field_1_string_length;
103 }
104
105 /**
106 * gives the current serialized size of the record. Should include the sid and reclength (4 bytes).
107 */
108 public int getRecordSize()
109 {
110 return 4 + 2 + 1 + getStringByteLength();
111 }
112
113 /**
114 * is this uncompressed unicode (16bit)? Or just 8-bit compressed?
115 * @return isUnicode - True for 16bit- false for 8bit
116 */
117 public boolean isUnCompressedUnicode()
118 {
119 return (field_2_unicode_flag == 1);
120 }
121
122 /**
123 * called by the class that is responsible for writing this sucker.
124 * Subclasses should implement this so that their data is passed back in a
125 * byte array.
126 *
127 * @param offset to begin writing at
128 * @param data byte array containing instance data
129 * @return number of bytes written
130 */
131 public int serialize( int offset, byte[] data )
132 {
133 LittleEndian.putShort(data, 0 + offset, sid);
134 LittleEndian.putShort(data, 2 + offset, ( short ) (3 + getStringByteLength()));
135 LittleEndian.putUShort(data, 4 + offset, field_1_string_length);
136 data[6 + offset] = field_2_unicode_flag;
137 if (isUnCompressedUnicode())
138 {
139 StringUtil.putUnicodeLE(field_3_string, data, 7 + offset);
140 }
141 else
142 {
143 StringUtil.putCompressedUnicode(field_3_string, data, 7 + offset);
144 }
145 return getRecordSize();
146 }
147
148 /**
149 * return the non static version of the id for this record.
150 */
151 public short getSid()
152 {
153 return sid;
154 }
155
156 /**
157 * @return The string represented by this record.
158 */
159 public String getString()
160 {
161 return field_3_string;
162 }
163
164 /**
165 * Sets whether the string is compressed or not
166 * @param unicode_flag 1 = uncompressed, 0 = compressed
167 */
168 public void setCompressedFlag( byte unicode_flag )
169 {
170 this.field_2_unicode_flag = unicode_flag;
171 }
172
173 /**
174 * Sets the string represented by this record.
175 */
176 public void setString( String string )
177 {
178 this.field_1_string_length = string.length();
179 this.field_3_string = string;
180 setCompressedFlag(StringUtil.hasMultibyte(string) ? (byte)1 : (byte)0);
181 }
182
183
184
185 public String toString()
186 {
187 StringBuffer buffer = new StringBuffer();
188
189 buffer.append("[STRING]\n");
190 buffer.append(" .string = ")
191 .append(field_3_string).append("\n");
192 buffer.append("[/STRING]\n");
193 return buffer.toString();
194 }
195
196 public Object clone() {
197 StringRecord rec = new StringRecord();
198 rec.field_1_string_length = this.field_1_string_length;
199 rec.field_2_unicode_flag= this.field_2_unicode_flag;
200 rec.field_3_string = this.field_3_string;
201 return rec;
202
203 }
204
205 }