Lines 56-61
Link Here
|
56 |
package org.apache.poi.hssf.record; |
56 |
package org.apache.poi.hssf.record; |
57 |
|
57 |
|
58 |
import org.apache.poi.util.LittleEndian; |
58 |
import org.apache.poi.util.LittleEndian; |
|
|
59 |
import org.apache.poi.util.LittleEndianConsts; |
59 |
import org.apache.poi.util.StringUtil; |
60 |
import org.apache.poi.util.StringUtil; |
60 |
|
61 |
|
61 |
/** |
62 |
/** |
Lines 74-83
Link Here
|
74 |
extends Record |
75 |
extends Record |
75 |
implements Comparable |
76 |
implements Comparable |
76 |
{ |
77 |
{ |
|
|
78 |
/** character count field size in byte */ |
79 |
static final short CHARCOUNTSIZE_SINGLEBYTE = LittleEndianConsts.BYTE_SIZE; |
80 |
static final short CHARCOUNTSIZE_DOUBLEBYTE = LittleEndianConsts.SHORT_SIZE; |
81 |
|
82 |
|
77 |
public final static short sid = 0xFFF; |
83 |
public final static short sid = 0xFFF; |
78 |
private short field_1_charCount; // = 0; |
84 |
private short field_1_charCount; // = 0; |
79 |
private byte field_2_optionflags; // = 0; |
85 |
private byte field_2_optionflags; // = 0; |
80 |
private String field_3_string; // = null; |
86 |
private String field_3_string; // = null; |
|
|
87 |
private byte field_4_ccAdjust =1; // charCount size adjustment |
88 |
// default to 1 i.e. charCount as short |
81 |
private final int RICH_TEXT_BIT = 8; |
89 |
private final int RICH_TEXT_BIT = 8; |
82 |
private final int EXT_BIT = 4; |
90 |
private final int EXT_BIT = 4; |
83 |
|
91 |
|
Lines 85-91
Link Here
|
85 |
{ |
93 |
{ |
86 |
} |
94 |
} |
87 |
|
95 |
|
88 |
|
|
|
89 |
public int hashCode() |
96 |
public int hashCode() |
90 |
{ |
97 |
{ |
91 |
int stringHash = 0; |
98 |
int stringHash = 0; |
Lines 114-119
Link Here
|
114 |
&& field_3_string.equals(other.field_3_string)); |
121 |
&& field_3_string.equals(other.field_3_string)); |
115 |
} |
122 |
} |
116 |
|
123 |
|
|
|
124 |
|
117 |
/** |
125 |
/** |
118 |
* construct a unicode string record and fill its fields, ID is ignored |
126 |
* construct a unicode string record and fill its fields, ID is ignored |
119 |
* @param id - ignored |
127 |
* @param id - ignored |
Lines 127-132
Link Here
|
127 |
} |
135 |
} |
128 |
|
136 |
|
129 |
/** |
137 |
/** |
|
|
138 |
* construct a unicode string record and fill its fields, ID is ignored |
139 |
* @param data - the bytes of the string/fields |
140 |
* @param size - size of the data |
141 |
* @param ccSize - the size (in byte) of the charCount field |
142 |
*/ |
143 |
|
144 |
public UnicodeString(byte [] data, short size, short ccSize ) |
145 |
{ |
146 |
super(); |
147 |
field_4_ccAdjust = (byte)((ccSize == (short) 2)?1:0) ; |
148 |
fillFields(data, size); |
149 |
} |
150 |
|
151 |
/** |
152 |
* construct a unicode string record and fill its fields, ID is ignored |
153 |
* @param data - the bytes of the string/fields |
154 |
* @param size - size of the data |
155 |
* @param offset - offset of the record |
156 |
* @param ccSize - the size (in byte) of the charCount field |
157 |
*/ |
158 |
|
159 |
public UnicodeString(byte [] data, short size, int offset , short ccSize ) |
160 |
{ |
161 |
super(); |
162 |
//UnicodeString us = new UnicodeString(); |
163 |
field_4_ccAdjust = (byte)((ccSize == (short) 2)?1:0) ; |
164 |
fillFields(data, size,offset); |
165 |
|
166 |
} |
167 |
/** |
168 |
* construct a unicode string from a string fragment + data with an |
169 |
* additional offset for extended(Far East and Rich Text) info and |
170 |
* the size (in byte) of the charCount field given as last parameter |
171 |
*/ |
172 |
public UnicodeString(byte [] data, short size, int offset ,int extOffset, |
173 |
short ccSize ) |
174 |
{ |
175 |
super(); |
176 |
//UnicodeString us = new UnicodeString(); |
177 |
field_4_ccAdjust = (byte)((ccSize == (short) 2)?1:0) ; |
178 |
fillFields(data, size,offset,extOffset); |
179 |
} |
180 |
|
181 |
/** |
130 |
* construct a unicode string from a string fragment + data |
182 |
* construct a unicode string from a string fragment + data |
131 |
*/ |
183 |
*/ |
132 |
|
184 |
|
Lines 138-173
Link Here
|
138 |
} |
190 |
} |
139 |
|
191 |
|
140 |
/** |
192 |
/** |
141 |
* NO OP |
193 |
* construct a unicode string from a string fragment + data with the size |
|
|
194 |
* (in byte) of the charCount field given as last parameter |
142 |
*/ |
195 |
*/ |
143 |
|
196 |
|
144 |
protected void validateSid(short id) |
197 |
public UnicodeString( byte [] data, short size, String prefix, |
|
|
198 |
short ccSize) |
145 |
{ |
199 |
{ |
|
|
200 |
super(); |
201 |
field_4_ccAdjust = (byte)((ccSize == (short) 2)?1:0) ; |
202 |
fillFields(data, size, 0); |
203 |
field_3_string = prefix + field_3_string; |
204 |
setCharCount(); |
205 |
} |
206 |
|
207 |
/** |
208 |
* construct a unicode string from a string fragment + data with the size |
209 |
* (in byte) of the charCount field given as last parameter |
210 |
*/ |
211 |
|
212 |
public UnicodeString( byte [] data, short size, int offset, String prefix, |
213 |
short ccSize) |
214 |
{ |
215 |
super(); |
216 |
field_4_ccAdjust = (byte)((ccSize == (short) 2)?1:0) ; |
217 |
fillFields(data, size, offset); |
218 |
field_3_string = prefix + field_3_string; |
219 |
setCharCount(); |
146 |
|
220 |
|
147 |
// included only for interface compliance |
|
|
148 |
} |
221 |
} |
149 |
|
222 |
|
150 |
protected void fillFields(byte [] data, short size) |
223 |
/** |
|
|
224 |
* construct a unicode string from a string fragment + data with an |
225 |
* additional offset for extended(Far East and Rich Text) info and the size |
226 |
* (in byte) of the charCount field given as last parameter |
227 |
*/ |
228 |
|
229 |
public UnicodeString( byte [] data, short size, int offset, int extOffset, |
230 |
String prefix, short ccSize) |
231 |
{ |
232 |
/* |
233 |
super(); |
234 |
field_4_ccAdjust = (byte)((ccSize == (short) 2)?1:0) ; |
235 |
fillFields(data, size, offset); |
236 |
field_3_string = prefix + field_3_string; |
237 |
setCharCount(); |
238 |
*/ |
239 |
|
240 |
} |
241 |
|
242 |
|
243 |
/** |
244 |
* NO OP |
245 |
*/ |
246 |
|
247 |
protected void validateSid(short id) |
151 |
{ |
248 |
{ |
152 |
field_1_charCount = LittleEndian.getShort(data, 0); |
|
|
153 |
field_2_optionflags = data[ 2 ]; |
154 |
if ((field_2_optionflags & 1) == 0) |
155 |
{ |
156 |
field_3_string = new String(data, 3, getCharCount()); |
157 |
} |
158 |
else |
159 |
{ |
160 |
char[] array = new char[ getCharCount() ]; |
161 |
|
249 |
|
162 |
for (int j = 0; j < array.length; j++) |
250 |
// included only for interface compliance |
163 |
{ |
|
|
164 |
array[ j ] = ( char ) LittleEndian.getShort(data, |
165 |
3 + (j * 2)); |
166 |
} |
167 |
field_3_string = new String(array); |
168 |
} |
169 |
} |
251 |
} |
170 |
|
252 |
|
|
|
253 |
|
171 |
/** |
254 |
/** |
172 |
* get the number of characters in the string |
255 |
* get the number of characters in the string |
173 |
* |
256 |
* |
Lines 286-291
Link Here
|
286 |
.append(Integer.toHexString(getOptionFlags())).append("\n"); |
369 |
.append(Integer.toHexString(getOptionFlags())).append("\n"); |
287 |
buffer.append(" .string = ").append(getString()) |
370 |
buffer.append(" .string = ").append(getString()) |
288 |
.append("\n"); |
371 |
.append("\n"); |
|
|
372 |
buffer.append(" .extOffset = ").append(field_4_ccAdjust).append("\n"); |
289 |
buffer.append("[/UNICODESTRING]\n"); |
373 |
buffer.append("[/UNICODESTRING]\n"); |
290 |
return buffer.toString(); |
374 |
return buffer.toString(); |
291 |
} |
375 |
} |
Lines 300-307
Link Here
|
300 |
} |
384 |
} |
301 |
|
385 |
|
302 |
// byte[] retval = new byte[ 3 + (getString().length() * charsize)]; |
386 |
// byte[] retval = new byte[ 3 + (getString().length() * charsize)]; |
303 |
LittleEndian.putShort(data, 0 + offset, getCharCount()); |
387 |
if ( field_4_ccAdjust == 1) { |
304 |
data[ 2 + offset ] = getOptionFlags(); |
388 |
LittleEndian.putShort(data, 0 + offset, getCharCount()); |
|
|
389 |
} |
390 |
else { |
391 |
data[ offset]= (byte)getCharCount(); |
392 |
} |
393 |
|
394 |
data[ 1+ field_4_ccAdjust+ offset ] = getOptionFlags(); |
305 |
|
395 |
|
306 |
// System.out.println("Unicode: We've got "+retval[2]+" for our option flag"); |
396 |
// System.out.println("Unicode: We've got "+retval[2]+" for our option flag"); |
307 |
try { |
397 |
try { |
Lines 309-333
Link Here
|
309 |
String(getString().getBytes("Unicode"),"Unicode"); |
399 |
String(getString().getBytes("Unicode"),"Unicode"); |
310 |
if (getOptionFlags() == 0) |
400 |
if (getOptionFlags() == 0) |
311 |
{ |
401 |
{ |
312 |
StringUtil.putCompressedUnicode(unicodeString, data, 0x3 + |
402 |
StringUtil.putCompressedUnicode(unicodeString, data, |
313 |
offset); |
403 |
0x2 + field_4_ccAdjust + offset); |
314 |
} |
404 |
} |
315 |
else |
405 |
else |
316 |
{ |
406 |
{ |
317 |
StringUtil.putUncompressedUnicode(unicodeString, data, |
407 |
StringUtil.putUncompressedUnicode(unicodeString, data, |
318 |
0x3 + offset); |
408 |
0x2 + field_4_ccAdjust + offset); |
319 |
} |
409 |
} |
320 |
} |
410 |
} |
321 |
catch (Exception e) { |
411 |
catch (Exception e) { |
322 |
if (getOptionFlags() == 0) |
412 |
if (getOptionFlags() == 0) |
323 |
{ |
413 |
{ |
324 |
StringUtil.putCompressedUnicode(getString(), data, 0x3 + |
414 |
StringUtil.putCompressedUnicode(getString(), data, |
325 |
offset); |
415 |
0x2 + field_4_ccAdjust + offset); |
326 |
} |
416 |
} |
327 |
else |
417 |
else |
328 |
{ |
418 |
{ |
329 |
StringUtil.putUncompressedUnicode(getString(), data, |
419 |
StringUtil.putUncompressedUnicode(getString(), data, |
330 |
0x3 + offset); |
420 |
0x2 +field_4_ccAdjust + offset); |
331 |
} |
421 |
} |
332 |
} |
422 |
} |
333 |
return getRecordSize(); |
423 |
return getRecordSize(); |
Lines 341-347
Link Here
|
341 |
public int getRecordSize() |
431 |
public int getRecordSize() |
342 |
{ |
432 |
{ |
343 |
int charsize = isUncompressedUnicode() ? 2 : 1; |
433 |
int charsize = isUncompressedUnicode() ? 2 : 1; |
344 |
return 3 + (getString().length() * charsize); |
434 |
return 2 + field_4_ccAdjust + |
|
|
435 |
(getString().length() * charsize); |
345 |
} |
436 |
} |
346 |
|
437 |
|
347 |
public short getSid() |
438 |
public short getSid() |
Lines 349-354
Link Here
|
349 |
return this.sid; |
440 |
return this.sid; |
350 |
} |
441 |
} |
351 |
|
442 |
|
|
|
443 |
protected void fillFields(byte [] data, short size) |
444 |
{ |
445 |
fillFields(data, size, 0); |
446 |
} |
447 |
|
352 |
/** |
448 |
/** |
353 |
* called by the constructor, should set class level fields. Should throw |
449 |
* called by the constructor, should set class level fields. Should throw |
354 |
* runtime exception for bad/icomplete data. |
450 |
* runtime exception for bad/icomplete data. |
Lines 360-365
Link Here
|
360 |
|
456 |
|
361 |
protected void fillFields(byte [] data, short size, int offset) |
457 |
protected void fillFields(byte [] data, short size, int offset) |
362 |
{ |
458 |
{ |
|
|
459 |
fillFields(data, size, offset,0); |
460 |
/* |
461 |
if ( field_4_ccAdjust == 1) {// CharCount field is 2 bytes |
462 |
field_1_charCount = LittleEndian.getShort(data, offset); |
463 |
} |
464 |
else { |
465 |
field_1_charCount = (short)LittleEndian.getUnsignedByte(data, offset); |
466 |
} |
467 |
|
468 |
field_2_optionflags = data[ offset+ 1+field_4_ccAdjust ]; |
469 |
if ((field_2_optionflags & 1) == 0) |
470 |
{ |
471 |
field_3_string = new String(data,offset + 2+field_4_ccAdjust, getCharCount()); |
472 |
} |
473 |
else |
474 |
{ |
475 |
char[] array = new char[ getCharCount() ]; |
476 |
|
477 |
for (int j = 0; j < array.length; j++) |
478 |
{ |
479 |
array[ j ] = ( char ) LittleEndian.getShort(data,offset+ |
480 |
2+field_4_ccAdjust + (j * 2)); |
481 |
} |
482 |
field_3_string = new String(array); |
483 |
} |
484 |
*/ |
485 |
} |
486 |
|
487 |
/** |
488 |
* called by the constructor, should set class level fields. Should throw |
489 |
* runtime exception for bad/icomplete data. |
490 |
* |
491 |
* @param data raw data |
492 |
* @param size size of data |
493 |
* @param offset of the records data (provided a big array of the file) |
494 |
* @param extOffset skip additional offset after header and before string start |
495 |
*/ |
496 |
|
497 |
protected void fillFields(byte [] data, short size, int offset,int extOffset) |
498 |
{ |
499 |
|
500 |
field_2_optionflags = data[ offset+ 1+field_4_ccAdjust ]; |
501 |
short charByteSize = (short)(size - stringHeaderOverhead()); |
502 |
|
503 |
if ( field_4_ccAdjust == 1) {// CharCount field is 2 bytes |
504 |
field_1_charCount = LittleEndian.getShort(data, offset); |
505 |
} |
506 |
else { |
507 |
field_1_charCount = (short)LittleEndian.getUnsignedByte(data, offset); |
508 |
} |
509 |
|
510 |
if ((field_2_optionflags & 1) == 0) // 8bit char |
511 |
{ |
512 |
if ( field_1_charCount > charByteSize) { // string in this record is broken over continuation |
513 |
field_1_charCount = charByteSize; |
514 |
} |
515 |
try { |
516 |
field_3_string = new String(data,offset + 2 + field_4_ccAdjust + |
517 |
extOffset , getCharCount(),"ISO-8859-1"); |
518 |
} |
519 |
catch (Exception e){ |
520 |
e.printStackTrace(); |
521 |
} |
522 |
|
523 |
} |
524 |
else // 16bit char |
525 |
{ |
526 |
if ( field_1_charCount >( charByteSize / 2)) { // string in this record is broken over continuation |
527 |
field_1_charCount = (short) (charByteSize / 2) ; |
528 |
} |
529 |
char[] array = new char[ getCharCount() ]; |
530 |
|
531 |
for (int j = 0; j < array.length; j++) |
532 |
{ |
533 |
array[ j ] = ( char ) LittleEndian.getShort(data,offset+ |
534 |
2+field_4_ccAdjust + extOffset + (j * 2)); |
535 |
} |
536 |
field_3_string = new String(array); |
537 |
} |
363 |
} |
538 |
} |
364 |
|
539 |
|
365 |
public int compareTo(Object obj) |
540 |
public int compareTo(Object obj) |
Lines 380-392
Link Here
|
380 |
|
555 |
|
381 |
if (isUncompressedUnicode()) |
556 |
if (isUncompressedUnicode()) |
382 |
{ |
557 |
{ |
383 |
int proposedStringLength = proposedBrokenLength - 3; |
558 |
int proposedStringLength = proposedBrokenLength - (2 + field_4_ccAdjust); |
384 |
|
559 |
|
385 |
if ((proposedStringLength % 2) == 1) |
560 |
if ((proposedStringLength % 2) == 1) |
386 |
{ |
561 |
{ |
387 |
proposedStringLength--; |
562 |
proposedStringLength--; |
388 |
} |
563 |
} |
389 |
rval = proposedStringLength + 3; |
564 |
rval = proposedStringLength + 2 + field_4_ccAdjust; |
390 |
} |
565 |
} |
391 |
return rval; |
566 |
return rval; |
392 |
} |
567 |
} |
Lines 394-399
Link Here
|
394 |
public boolean isExtendedText() |
569 |
public boolean isExtendedText() |
395 |
{ |
570 |
{ |
396 |
return (getOptionFlags() & EXT_BIT) != 0; |
571 |
return (getOptionFlags() & EXT_BIT) != 0; |
|
|
572 |
} |
573 |
|
574 |
private short stringHeaderOverhead() |
575 |
{ |
576 |
return (short)(2 + field_4_ccAdjust + |
577 |
+ ( ((field_2_optionflags & RICH_TEXT_BIT) != 0)? |
578 |
LittleEndianConsts.SHORT_SIZE : 0 ) |
579 |
+ ( ((field_2_optionflags & EXT_BIT) != 0)? |
580 |
LittleEndianConsts.INT_SIZE : 0 ) ); |
397 |
} |
581 |
} |
398 |
|
582 |
|
399 |
} |
583 |
} |