1 /
55
56 package org.apache.poi.hssf.record;
57
58 import org.apache.poi.util.BinaryTree;
59 import org.apache.poi.util.LittleEndian;
60 import org.apache.poi.util.LittleEndianConsts;
61
62 import java.util.*;
63
64
78
79 public class SSTRecord
80 extends Record
81 {
82
83
84
85 private static final int _max = 8228;
86
87
88
89 private static final int _std_record_overhead =
90 2 * LittleEndianConsts.SHORT_SIZE;
91
92
93
94 private static final int _sst_record_overhead =
95 (_std_record_overhead + (2 * LittleEndianConsts.INT_SIZE));
96
97
98
99 private static final int _max_data_space =
100 _max - _sst_record_overhead;
101
102
103
104 private static final int _string_minimal_overhead =
105 LittleEndianConsts.SHORT_SIZE + LittleEndianConsts.BYTE_SIZE;
106 public static final short sid = 0xfc;
107
108
109 private int field_1_num_strings;
110
111
112 private int field_2_num_unique_strings;
113 private BinaryTree field_3_strings;
114
115
116
117 private int __expected_chars;
118
119
120
121 private String _unfinished_string;
122
123
124 private int _total_length_bytes;
125
126
127
128 private int _string_data_offset;
129
130
131 private boolean _wide_char;
132 private List _record_lengths = null;
133
134
137
138 public SSTRecord()
139 {
140 field_1_num_strings = 0;
141 field_2_num_unique_strings = 0;
142 field_3_strings = new BinaryTree();
143 setExpectedChars(0);
144 _unfinished_string = "";
145 _total_length_bytes = 0;
146 _string_data_offset = 0;
147 _wide_char = false;
148 }
149
150
158
159 public SSTRecord(final short id, final short size, final byte [] data)
160 {
161 super(id, size, data);
162 }
163
164
173
174 public SSTRecord(final short id, final short size, final byte [] data,
175 int offset)
176 {
177 super(id, size, data, offset);
178 }
179
180
194
195 public int addString(final String string)
196 {
197 int rval;
198
199 if (string == null)
200 {
201 rval = addString("", false);
202 }
203 else
204 {
205
206
207
208
209 boolean useUTF16 = false;
210 int strlen = string.length();
211
212 for (int j = 0; j < strlen; j++)
213 {
214 if (string.charAt(j) > 255)
215 {
216 useUTF16 = true;
217 break;
218 }
219 }
220 rval = addString(string, useUTF16);
221 }
222 return rval;
223 }
224
225
240
241 public int addString(final String string, final boolean useUTF16)
242 {
243 field_1_num_strings++;
244 String str = (string == null) ? ""
245 : string;
246 int rval = -1;
247 UnicodeString ucs = new UnicodeString();
248
249 ucs.setString(str);
250 ucs.setCharCount(( short ) str.length());
251 ucs.setOptionFlags(( byte ) (useUTF16 ? 1
252 : 0));
253 Integer integer = ( Integer ) field_3_strings.getKeyForValue(ucs);
254
255 if (integer != null)
256 {
257 rval = integer.intValue();
258 }
259 else
260 {
261
262
263
264 rval = field_3_strings.size();
265 field_2_num_unique_strings++;
266 integer = new Integer(rval);
267 field_3_strings.put(integer, ucs);
268 }
269 return rval;
270 }
271
272
275
276 public int getNumStrings()
277 {
278 return field_1_num_strings;
279 }
280
281
284
285 public int getNumUniqueStrings()
286 {
287 return field_2_num_unique_strings;
288 }
289
290
300
301 public void setNumStrings(final int count)
302 {
303 field_1_num_strings = count;
304 }
305
306
316
317 public void getNumUniqueStrings(final int count)
318 {
319 field_2_num_unique_strings = count;
320 }
321
322
329
330 public String getString(final int id)
331 {
332 return (( UnicodeString ) field_3_strings.get(new Integer(id)))
333 .getString();
334 }
335
336 public boolean getString16bit(final int id)
337 {
338 return ((( UnicodeString ) field_3_strings.get(new Integer(id)))
339 .getOptionFlags() == 1);
340 }
341
342
347
348 public String toString()
349 {
350 StringBuffer buffer = new StringBuffer();
351
352 buffer.append("[SST]\n");
353 buffer.append(" .numstrings = ")
354 .append(Integer.toHexString(getNumStrings())).append("\n");
355 buffer.append(" .uniquestrings = ")
356 .append(Integer.toHexString(getNumUniqueStrings())).append("\n");
357 for (int k = 0; k < field_3_strings.size(); k++)
358 {
359 buffer.append(" .string_" + k + " = ")
360 .getend((( UnicodeString ) field_3_strings
361 .get(new Integer(k))).toString()).append("\n");
362 }
363 buffer.append("[/SST]\n");
364 return buffer.toString();
365 }
366
367
378
379 public int serialize(int offset, byte [] data)
380 {
381 int rval = getRecordSize();
382 int record_length_index = 0;
383
384
385 int unicodesize = calculateUnicodeSize();
386
387 if (unicodesize > _max_data_space)
388 {
389 byte[] stringreminant = null;
390 int unipos = 0;
391 boolean lastneedcontinue = false;
392 int stringbyteswritten = 0;
393 boolean first_record = true;
394 int totalWritten = 0;
395 int size = 0;
396
397 while (totalWritten != rval)
398 {
399 int pos = 0;
400
401
402 int available;
403
404 if (first_record)
405 {
406 size =
407 (( Integer ) _record_lengths
408 .get(record_length_index++)).intValue();
409 available = size - 8;
410 pos = writeSSTHeader(data,
411 pos + offset
412 + totalWritten, size);
413 size += _std_record_overhead;
414 first_record = false;
415 }
416 else
417 {
418 pos = 0;
419 int to_be_written = (unicodesize - stringbyteswritten)
420 + (lastneedcontinue ? 1
421 : 0);
422
423 size =
424 (( Integer ) _record_lengths
425 .get(record_length_index++)).intValue();
426 available = size;
427 pos = writeContinueHeader(data,
428 pos + offset
429 + totalWritten, size);
430 size = size + _std_record_overhead;
431 }
432
433
434
435 if (lastneedcontinue)
436 {
437
438
439
440 if (stringreminant.length <= available)
441 {
442
443
444 System.arraycopy(stringreminant, 0, data,
445 pos + offset + totalWritten,
446 stringreminant.length);
447 stringbyteswritten += stringreminant.length - 1;
448 pos += stringreminant.length;
449 lastneedcontinue = false;
450 available -= stringreminant.length;
451 }
452 else
453 {
454
455
456 System.arraycopy(stringreminant, 0, data,
457 pos + offset + totalWritten,
458 available);
459 stringbyteswritten += available - 1;
460 pos += available;
461 byte[] leftover =
462 new byte[ (stringreminant.length - available) + LittleEndianConsts.BYTE_SIZE ];
463
464 System.arraycopy(stringreminant, available, leftover,
465 LittleEndianConsts.BYTE_SIZE,
466 stringreminant.length - available);
467 leftover[ 0 ] = stringreminant[ 0 ];
468 stringreminant = leftover;
469 available = 0;
470 lastneedcontinue = true;
471 }
472 }
473
474
475
476
477 for (; unipos < field_3_strings.size(); unipos++)
478 {
479 Integer intunipos = new Integer(unipos);
480 UnicodeString unistr =
481 (( UnicodeString ) field_3_strings.get(intunipos));
482
483 if (unistr.getRecordSize() <= available)
484 {
485 unistr.serialize(pos + offset + totalWritten, data);
486 int rsize = unistr.getRecordSize();
487
488 stringbyteswritten += rsize;
489 pos += rsize;
490 available -= rsize;
491 }
492 else
493 {
494
495
496 if (available >= _string_minimal_overhead)
497 {
498
499
500 byte[] ucs = unistr.serialize();
501
502 System.arraycopy(ucs, 0, data,
503 pos + offset + totalWritten,
504 available);
505 stringbyteswritten += available;
506 stringreminant =
507 new byte[ (ucs.length - available) + LittleEndianConsts.BYTE_SIZE ];
508 System.arraycopy(ucs, available, stringreminant,
509 LittleEndianConsts.BYTE_SIZE,
510 ucs.length - available);
511 stringreminant[ 0 ] =
512 ucs[ LittleEndianConsts.SHORT_SIZE ];
513 available = 0;
514 lastneedcontinue = true;
515 unipos++;
516 }
517 break;
518 }
519 }
520 totalWritten += size;
521 }
522 }
523 else
524 {
525
526
527 int datasize = _sst_record_overhead + unicodesize;
528
529 writeSSTHeader(
530 data, 0 + offset,
531 _sst_record_overhead
532 + (( Integer ) _record_lengths.get(
533 record_length_index++)).intValue() - _std_record_overhead);
534 int pos = _sst_record_overhead;
535
536 for (int k = 0; k < field_3_strings.size(); k++)
537 {
538 UnicodeString unistr =
539 (( UnicodeString ) field_3_strings.get(new Integer(k)));
540
541 System.arraycopy(unistr.serialize(), 0, data, pos + offset,
542 unistr.getRecordSize());
543 pos += unistr.getRecordSize();
544 }
545 }
546 return rval;
547 }
548
549
550 private int calculateStringsize()
551 {
552 int retval = 0;
553
554 for (int k = 0; k < field_3_strings.size(); k++)
555 {
556 retval +=
557 (( UnicodeString ) field_3_strings.get(new Integer(k)))
558 .getRecordSize();
559 }
560 return retval;
561 }
562
563
583
584 public void processContinueRecord(final byte [] record)
585 {
586 if (getExpectedChars() == 0)
587 {
588 _unfinished_string = "";
589 _total_length_bytes = 0;
590 _string_data_offset = 0;
591 _wide_char = false;
592 manufactureStrings(record, 0, ( short ) record.length);
593 }
594 else
595 {
596 int data_length = record.length - LittleEndianConsts.BYTE_SIZE;
597
598 if (calculateByteCount(getExpectedChars()) > data_length)
599 {
600
601
602 byte[] input =
603 new byte[ record.length + LittleEndianConsts.SHORT_SIZE ];
604 short size = ( short ) (((record[ 0 ] & 1) == 1)
605 ? (data_length
606 / LittleEndianConsts.SHORT_SIZE)
607 : (data_length
608 / LittleEndianConsts.BYTE_SIZE));
609
610 LittleEndian.putShort(input, ( byte ) 0, size);
611 System.arraycopy(record, 0, input,
612 LittleEndianConsts.SHORT_SIZE,
613 record.length);
614 UnicodeString ucs = new UnicodeString(UnicodeString.sid,
615 ( short ) input.length,
616 input);
617
618 _unfinished_string = _unfinished_string + ucs.getString();
619 setExpectedChars(getExpectedChars() - size);
620 }
621 else
622 {
623 setupStringParameters(record, -LittleEndianConsts.SHORT_SIZE,
624 getExpectedChars());
625 byte[] str_data = new byte[ _total_length_bytes ];
626 int length = _string_minimal_overhead
627 + (calculateByteCount(getExpectedChars()));
628 byte[] bstring = new byte[ length ];
629
630
631
632
633 System.arraycopy(record, 0, str_data,
634 LittleEndianConsts.SHORT_SIZE,
635 str_data.length
636 - LittleEndianConsts.SHORT_SIZE);
637
638
639 LittleEndian.putShort(bstring, 0,
640 ( short ) getExpectedChars());
641
642
643 bstring[ LittleEndianConsts.SHORT_SIZE ] =
644 str_data[ LittleEndianConsts.SHORT_SIZE ];
645
646
647
648 System.arraycopy(str_data, _string_data_offset, bstring,
649 _string_minimal_overhead,
650 bstring.length - _string_minimal_overhead);
651
652
653 UnicodeString string =
654 new UnicodeString(UnicodeString.sid,
655 ( short ) bstring.length, bstring,
656 _unfinished_string);
657 Integer integer = new Integer(field_3_strings.size());
658
659 field_3_strings.put(integer, string);
660 manufactureStrings(record,
661 _total_length_bytes
662 - LittleEndianConsts
663 .SHORT_SIZE, ( short ) record.length);
664 }
665 }
666 }
667
668 /**
669 * @return sid
670 */
671
672 public short getSid()
673 {
674 return sid;
675 }
676
677 /**
678 * @return hashcode
679 */
680
681 public int hashCode()
682 {
683 return field_2_num_unique_strings;
684 }
685
686 /**
687 *
688 * @param o
689 * @return true if equal
690 */
691
692 public boolean equals(Object o)
693 {
694 if ((o == null) || (o.getClass() != this.getClass()))
695 {
696 return false;
697 }
698 SSTRecord other = ( SSTRecord ) o;
699
700 return ((field_1_num_strings == other
701 .field_1_num_strings) && (field_2_num_unique_strings == other
702 .field_2_num_unique_strings) && field_3_strings
703 .equals(other.field_3_strings));
704 }
705
706 /**
707 * validate SID
708 *
709 * @param id the alleged SID
710 *
711 * @exception RecordFormatException if validation fails
712 */
713
714 protected void validateSid(final short id)
715 throws RecordFormatException
716 {
717 if (id != sid)
718 {
719 throw new RecordFormatException("NOT An SST RECORD");
720 }
721 }
722
723 /**
724 * Fill the fields from the data
725 * <P>
726 * The data consists of sets of string data. This string data is
727 * arranged as follows:
728 * <P>
729 * <CODE>
730 * short string_length; // length of string data
731 * byte string_flag; // flag specifying special string
732 * // handling
733 * short run_count; // optional count of formatting runs
734 * int extend_length; // optional extension length
735 * char[] string_data; // string data, can be byte[] or
736 * // short[] (length of array is
737 * // string_length)
738 * int[] formatting_runs; // optional formatting runs (length of
739 * // array is run_count)
740 * byte[] extension; // optional extension (length of array
741 * // is extend_length)
742 * </CODE>
743 * <P>
744 * The string_flag is bit mapped as follows:
745 * <P>
746 * <TABLE>
747 * <TR>
748 * <TH>Bit number</TH>
749 * <TH>Meaning if 0</TH>
750 * <TH>Meaning if 1</TH>
751 * <TR>
752 * <TR>
753 * <TD>0</TD>
754 * <TD>string_data is byte[]</TD>
755 * <TD>string_data is short[]</TH>
756 * <TR>
757 * <TR>
758 * <TD>1</TD>
759 * <TD>Should always be 0</TD>
760 * <TD>string_flag is defective</TH>
761 * <TR>
762 * <TR>
763 * <TD>2</TD>
764 * <TD>extension is not included</TD>
765 * <TD>extension is included</TH>
766 * <TR>
767 * <TR>
768 * <TD>3</TD>
769 * <TD>formatting run data is not included</TD>
770 * <TD>formatting run data is included</TH>
771 * <TR>
772 * <TR>
773 * <TD>4</TD>
774 * <TD>Should always be 0</TD>
775 * <TD>string_flag is defective</TH>
776 * <TR>
777 * <TR>
778 * <TD>5</TD>
779 * <TD>Should always be 0</TD>
780 * <TD>string_flag is defective</TH>
781 * <TR>
782 * <TR>
783 * <TD>6</TD>
784 * <TD>Should always be 0</TD>
785 * <TD>string_flag is defective</TH>
786 * <TR>
787 * <TR>
788 * <TD>7</TD>
789 * <TD>Should always be 0</TD>
790 * <TD>string_flag is defective</TH>
791 * <TR>
792 * </TABLE>
793 * <P>
794 * We can handle eating the overhead associated with bits 2 or 3
795 * (or both) being set, but we have no idea what to do with the
796 * associated data. The UnicodeString class can handle the byte[]
797 * vs short[] nature of the actual string data
798 *
799 * @param data raw data
800 * @param size size of the raw data
801 */
802
803 protected void fillFields(final byte [] data, final short size,
804 int offset)
805 {
806
807 // this method is ALWAYS called after construction -- using
808 // the nontrivial constructor, of course -- so this is where
809 // we initialize our fields
810 field_1_num_strings = LittleEndian.getInt(data, 0 + offset);
811 field_2_num_unique_strings = LittleEndian.getInt(data, 4 + offset);
812 field_3_strings = new BinaryTree();
813 setExpectedChars(0);
814 _unfinished_string = "";
815 _total_length_bytes = 0;
816 _string_data_offset = 0;
817 _wide_char = false;
818 manufactureStrings(data, 8 + offset, size);
819 }
820
821 /**
822 * @return the number of characters we expect in the first
823 * sub-record in a subsequent continuation record
824 */
825
826 int getExpectedChars()
827 {
828 return __expected_chars;
829 }
830
831 /**
832 * @return an iterator of the strings we hold. All instances are
833 * UnicodeStrings
834 */
835
836 Iterator getStrings()
837 {
838 return field_3_strings.values().iterator();
839 }
840
841 /**
842 * @return count of the strings we hold.
843 */
844
845 int countStrings()
846 {
847 return field_3_strings.size();
848 }
849
850 /**
851 * @return the unfinished string
852 */
853
854 String getUnfinishedString()
855 {
856 return _unfinished_string;
857 }
858
859 /**
860 * @return the total length of the current string
861 */
862
863 int getTotalLength()
864 {
865 return _total_length_bytes;
866 }
867
868 /**
869 * @return offset into current string data
870 */
871
872 int getStringDataOffset()
873 {
874 return _string_data_offset;
875 }
876
877 /**
878 * @return true if current string uses wide characters
879 */
880
881 boolean isWideChar()
882 {
883 return _wide_char;
884 }
885
886 private int writeSSTHeader(final byte [] data, final int pos,
887 final int recsize)
888 {
889 int offset = pos;
890
891 LittleEndian.putShort(data, offset, sid);
892 offset += LittleEndianConsts.SHORT_SIZE;
893 LittleEndian.putShort(data, offset, ( short ) (recsize));
894 offset += LittleEndianConsts.SHORT_SIZE;
895 LittleEndian.putInt(data, offset, getNumStrings());
896 offset += LittleEndianConsts.INT_SIZE;
897 LittleEndian.putInt(data, offset, getNumUniqueStrings());
898 offset += LittleEndianConsts.INT_SIZE;
899 return offset - pos;
900 }
901
902 private int writeContinueHeader(final byte [] data, final int pos,
903 final int recsize)
904 {
905 int offset = pos;
906
907 LittleEndian.putShort(data, offset, ContinueRecord.sid);
908 offset += LittleEndianConsts.SHORT_SIZE;
909 LittleEndian.putShort(data, offset, ( short ) (recsize));
910 offset += LittleEndianConsts.SHORT_SIZE;
911 return offset - pos;
912 }
913
914 private int calculateUCArrayLength(final byte [][] ucarray)
915 {
916 int retval = 0;
917
918 for (int k = 0; k < ucarray.length; k++)
919 {
920 retval += ucarray[ k ].length;
921 }
922 return retval;
923 }
924
925 private void manufactureStrings(final byte [] data, final int index,
926 short size)
927 {
928 int offset = index;
929
930 while (offset < size)
931 {
932 int remaining = size - offset;
933
934 if ((remaining > 0)
935 && (remaining < LittleEndianConsts.SHORT_SIZE))
936 {
937 throw new RecordFormatException(
938 "Cannot get length of the last string in SSTRecord");
939 }
940 if (remaining == LittleEndianConsts.SHORT_SIZE)
941 {
942 setExpectedChars(LittleEndian.getShort(data, offset));
943 _unfinished_string = "";
944 break;
945 }
946 short char_count = LittleEndian.getShort(data, offset);
947
948 setupStringParameters(data, offset, char_count);
949 if (remaining < _total_length_bytes)
950 {
951 setExpectedChars(calculateCharCount(_total_length_bytes
952 - remaining));
953 char_count -= getExpectedChars();
954 _total_length_bytes = remaining;
955 }
956 else
957 {
958 setExpectedChars(0);
959 }
960 processString(data, offset, char_count);
961 offset += _total_length_bytes;
962 if (getExpectedChars() != 0)
963 {
964 break;
965 }
966 }
967 }
968
969 private void setupStringParameters(final byte [] data, final int index,
970 final int char_count)
971 {
972 byte flag = data[ index + LittleEndianConsts.SHORT_SIZE ];
973
974 _wide_char = (flag & 1) == 1;
975 boolean extended = (flag & 4) == 4;
976 boolean formatted_run = (flag & 8) == 8;
977
978 _total_length_bytes = _string_minimal_overhead
979 + calculateByteCount(char_count);
980 _string_data_offset = _string_minimal_overhead;
981 if (formatted_run)
982 {
983 short run_count = LittleEndian.getShort(data,
984 index
985 + _string_data_offset);
986
987 _string_data_offset += LittleEndianConsts.SHORT_SIZE;
988 _total_length_bytes += LittleEndianConsts.SHORT_SIZE
989 + (LittleEndianConsts.INT_SIZE
990 * run_count);
991 }
992 if (extended)
993 {
994 int extension_length = LittleEndian.getInt(data,
995 index
996 + _string_data_offset);
997
998 _string_data_offset += LittleEndianConsts.INT_SIZE;
999 _total_length_bytes += LittleEndianConsts.INT_SIZE
1000 + extension_length;
1001 }
1002 }
1003
1004 private void processString(final byte [] data, final int index,
1005 final short char_count)
1006 {
1007 byte[] str_data = new byte[ _total_length_bytes ];
1008 int length = _string_minimal_overhead
1009 + calculateByteCount(char_count);
1010 byte[] bstring = new byte[ length ];
1011
1012 System.arraycopy(data, index, str_data, 0, str_data.length);
1013 int offset = 0;
1014
1015 LittleEndian.putShort(bstring, offset, char_count);
1016 offset += LittleEndianConsts.SHORT_SIZE;
1017 bstring[ offset ] = str_data[ offset ];
1018 System.arraycopy(str_data, _string_data_offset, bstring,
1019 _string_minimal_overhead,
1020 bstring.length - _string_minimal_overhead);
1021 UnicodeString string = new UnicodeString(UnicodeString.sid,
1022 ( short ) bstring.length,
1023 bstring);
1024
1025 if (getExpectedChars() != 0)
1026 {
1027 _unfinished_string = string.getString();
1028 }
1029 else
1030 {
1031 Integer integer = new Integer(field_3_strings.size());
1032
1033 field_3_strings.put(integer, string);
1034 }
1035 }
1036
1037 private void setExpectedChars(final int count)
1038 {
1039 __expected_chars = count;
1040 }
1041
1042 private int calculateByteCount(final int character_count)
1043 {
1044 return character_count * (_wide_char ? LittleEndianConsts.SHORT_SIZE
1045 : LittleEndianConsts.BYTE_SIZE);
1046 }
1047
1048 private int calculateCharCount(final int byte_count)
1049 {
1050 return byte_count / (_wide_char ? LittleEndianConsts.SHORT_SIZE
1051 : LittleEndianConsts.BYTE_SIZE);
1052 }
1053
1054 // we can probably simplify this later...this calculates the size
1055 // w/o serializing but still is a bit slow
1056 public int getRecordSize()
1057 {
1058 _record_lengths = new ArrayList();
1059 int retval = 0;
1060 int unicodesize = calculateUnicodeSize();
1061
1062 if (unicodesize > _max_data_space)
1063 {
1064 UnicodeString unistr = null;
1065 int stringreminant = 0;
1066 int unipos = 0;
1067 boolean lastneedcontinue = false;
1068 int stringbyteswritten = 0;
1069 boolean finished = false;
1070 boolean first_record = true;
1071 int totalWritten = 0;
1072
1073 while (!finished)
1074 {
1075 int record = 0;
1076 int pos = 0;
1077
1078 if (first_record)
1079 {
1080
1081 // writing SST record
1082 record = _max;
1083 pos = 12;
1084 first_record = false;
1085 _record_lengths.add(new Integer(record
1086 - _std_record_overhead));
1087 }
1088 else
1089 {
1090
1091 // writing continue record
1092 pos = 0;
1093 int to_be_written = (unicodesize - stringbyteswritten)
1094 + (lastneedcontinue ? 1
1095 : 0);
1096 int size = Math.min(_max - _std_record_overhead,
1097 to_be_written);
1098
1099 if (size == to_be_written)
1100 {
1101 finished = true;
1102 }
1103 record = size + _std_record_overhead;
1104 _record_lengths.add(new Integer(size));
1105 pos = 4;
1106 }
1107 if (lastneedcontinue)
1108 {
1109 int available = _max - pos;
1110
1111 if (stringreminant <= available)
1112 {
1113
1114 // write reminant
1115 stringbyteswritten += stringreminant - 1;
1116 pos += stringreminant;
1117 lastneedcontinue = false;
1118 }
1119 else
1120 {
1121
1122 // write as much of the remnant as possible
1123 int toBeWritten = unistr.maxBrokenLength(available);
1124
1125 if (available != toBeWritten)
1126 {
1127 int shortrecord = record
1128 - (available - toBeWritten);
1129
1130 _record_lengths.set(
1131 _record_lengths.size() - 1,
1132 new Integer(
1133 shortrecord - _std_record_overhead));
1134 record = shortrecord;
1135 }
1136 stringbyteswritten += toBeWritten - 1;
1137 pos += toBeWritten;
1138 stringreminant -= toBeWritten - 1;
1139 lastneedcontinue = true;
1140 }
1141 }
1142 for (; unipos < field_3_strings.size(); unipos++)
1143 {
1144 int available = _max - pos;
1145 Integer intunipos = new Integer(unipos);
1146
1147 unistr =
1148 (( UnicodeString ) field_3_strings.get(intunipos));
1149 if (unistr.getRecordSize() <= available)
1150 {
1151 stringbyteswritten += unistr.getRecordSize();
1152 pos += unistr.getRecordSize();
1153 }
1154 else
1155 {
1156 if (available >= _string_minimal_overhead)
1157 {
1158 int toBeWritten =
1159 unistr.maxBrokenLength(available);
1160
1161 stringbyteswritten += toBeWritten;
1162 stringreminant =
1163 (unistr.getRecordSize() - toBeWritten)
1164 + LittleEndianConsts.BYTE_SIZE;
1165 if (available != toBeWritten)
1166 {
1167 int shortrecord = record
1168 - (available - toBeWritten);
1169
1170 _record_lengths.set(
1171 _record_lengths.size() - 1,
1172 new Integer(
1173 shortrecord - _std_record_overhead));
1174 record = shortrecord;
1175 }
1176 lastneedcontinue = true;
1177 unipos++;
1178 }
1179 else
1180 {
1181 int shortrecord = record - available;
1182
1183 _record_lengths.set(
1184 _record_lengths.size() - 1,
1185 new Integer(
1186 shortrecord - _std_record_overhead));
1187 record = shortrecord;
1188 }
1189 break;
1190 }
1191 }
1192 totalWritten += record;
1193 }
1194 retval = totalWritten;
1195 }
1196 else
1197 {
1198
1199 // short data: write one simple SST record
1200 retval = _sst_record_overhead + unicodesize;
1201 _record_lengths.add(new Integer(unicodesize));
1202 }
1203 return retval;
1204 }
1205
1206 private int calculateUnicodeSize()
1207 {
1208 int retval = 0;
1209
1210 for (int k = 0; k < field_3_strings.size(); k++)
1211 {
1212 UnicodeString string =
1213 ( UnicodeString ) field_3_strings.get(new Integer(k));
1214
1215 retval += string.getRecordSize();
1216 }
1217 return retval;
1218 }
1219 }
1220 ?????????????????????????????????????????SHORT_SIZE???????????????????????????????????????????????????????????????record???????????????????????getSid????????????????sid?????????????????????hashCode????????????????field_2_num_unique_strings?????????????????????????equals??????????????o?????????????????????????????o?????????SSTRecord?????????????????????????????????????????o??????????????field_1_num_strings??????????????????field_1_num_strings?????????????????????????????????????????other??????????????????field_2_num_unique_strings???????????????????????????????????????field_2_num_unique_strings?????????????????????????????????????????????????????????????????????other?????????????????????????????????????????????????field_3_strings?????????????????????????????other???????????????????????????????????field_3_strings?????????????????????????validateSid????????????????RecordFormatException?????????????id???????????????????sid?????????????????????????fillFields????????????????????????????????????field_1_num_strings??????????????????????????????????????LittleEndian???????????????????????????????????????????????????getInt??????????????????????????????????????????????????????????data????????????????????????????????????????????????????????????????????offset?????????field_2_num_unique_strings??????????????????????????????????????LittleEndian???????????????????????????????????????????????????getInt??????????????????????????????????????????????????????????data????????????????????????????????????????????????????????????????????offset?????????field_3_strings??????????????????????????????????????????BinaryTree?????????setExpectedChars?????????_unfinished_string?????????_total_length_bytes?????????_string_data_offset?????????_wide_char?????????manufactureStrings????????????????????????????data??????????????????????????????????????offset??????????????????????????????????????????????size??????????????getExpectedChars????????????????__expected_chars???????????????????getStrings????????????????field_3_strings????????????????????????????????values??????????????countStrings????????????????field_3_strings????????????????????????????????size?????????????????getUnfinishedString????????????????_unfinished_string??????????????getTotalLength????????????????_total_length_bytes??????????????getStringDataOffset????????????????_string_data_offset??????????????????isWideChar????????????????_wide_char?????????????????writeSSTHeader??????????????????????pos?????????LittleEndian??????????????????????putShort???????????????????????????????data?????????????????????????????????????offset?????????????????????????????????????????????sid?????????offset???????????????????LittleEndianConsts??????????????????????????????????????SHORT_SIZE?????????LittleEndian??????????????????????putShort???????????????????????????????data?????????????????????????????????????offset????????????????????????????????????????????????????????recsize?????????offset???????????????????LittleEndianConsts??????????????????????????????????????SHORT_SIZE?????????LittleEndian??????????????????????putInt?????????????????????????????data???????????????????????????????????offset???????????????????????????????????????????getNumStrings?????????offset???????????????????LittleEndianConsts??????????????????????????????????????INT_SIZE?????????LittleEndian??????????????????????putInt?????????????????????????????data???????????????????????????????????offset???????????????????????????????????????????getNumUniqueStrings?????????offset???????????????????LittleEndianConsts??????????????????????????????????????INT_SIZE????????????????offset?????????????????????????pos?????????????????writeContinueHeader??????????????????????pos?????????LittleEndian??????????????????????putShort???????????????????????????????data?????????????????????????????????????offset?????????offset???????????????????LittleEndianConsts??????????????????????????????????????SHORT_SIZE?????????LittleEndian??????????????????????putShort???????????????????????????????data?????????????????????????????????????offset????????????????????????????????????????????????????????recsize?????????offset???????????????????LittleEndianConsts??????????????????????????????????????SHORT_SIZE????????????????offset?????????????????????????pos?????????????????calculateUCArrayLength?????????????????????????k?????????????????????????????ucarray?????????????????????????????????????????????k?????????????retval???????????????????????ucarray????????????????????????????????k????????????????retval??????????????????manufactureStrings??????????????????????index????????????????offset?????????????????????????size?????????????????????????????size????????????????????????????????????offset??????????????????remaining?????????????????????????remaining?????????????????????????????????????LittleEndianConsts????????????????????????????????????????????????????????SHORT_SIZE?????????????????remaining??????????????????????????????LittleEndianConsts?????????????????????????????????????????????????SHORT_SIZE?????????????????setExpectedChars??????????????????????????????????LittleEndian???????????????????????????????????????????????getShort????????????????????????????????????????????????????????data??????????????????????????????????????????????????????????????offset?????????????????_unfinished_string????????????????????????????????LittleEndian?????????????????????????????????????????????getShort??????????????????????????????????????????????????????data????????????????????????????????????????????????????????????offset?????????????setupStringParameters???????????????????????????????????data?????????????????????????????????????????offset?????????????????????????????????????????????????char_count?????????????????remaining?????????????????????????????_total_length_bytes?????????????????setExpectedChars??????????????????????????????????calculateCharCount?????????????????????????????????????????????????????_total_length_bytes???????????????????????????????????????????????????????remaining?????????????????char_count????????????????????????????????????????getExpectedChars?????????????????_total_length_bytes???????????????????????????????????????remaining?????????????????setExpectedChars?????????????processString???????????????????????????data?????????????????????????????????offset?????????????????????????????????????????char_count?????????????offset???????????????????????_total_length_bytes?????????????????getExpectedChars??????????????????setupStringParameters?????????????????????data???????????????????????????index???????????????????????????????????LittleEndianConsts??????????????????????????????????????????????????????SHORT_SIZE?????????_wide_char???????????????????????flag??????????????????????????????????flag??????????????????????????????????flag?????????_total_length_bytes???????????????????????????????_string_minimal_overhead?????????????????????????????????calculateByteCount????????????????????????????????????????????????????char_count?????????_string_data_offset???????????????????????????????_string_minimal_overhead?????????????formatted_run???????????????????????????????LittleEndian????????????????????????????????????????????getShort?????????????????????????????????????????????????????data?????????????????????????????????????????????????????index???????????????????????????????????????????????????????_string_data_offset?????????????_string_data_offset????????????????????????????????????LittleEndianConsts???????????????????????????????????????????????????????SHORT_SIZE?????????????_total_length_bytes????????????????????????????????????LittleEndianConsts???????????????????????????????????????????????????????SHORT_SIZE???????????????????????????????????????LittleEndianConsts??????????????????????????????????????????????????????????INT_SIZE?????????????????????????????????????????run_count?????????????extended????????????????????????????????????LittleEndian?????????????????????????????????????????????????getInt????????????????????????????????????????????????????????data????????????????????????????????????????????????????????index??????????????????????????????????????????????????????????_string_data_offset?????????????_string_data_offset????????????????????????????????????LittleEndianConsts???????????????????????????????????????????????????????INT_SIZE?????????????_total_length_bytes????????????????????????????????????LittleEndianConsts???????????????????????????????????????????????????????INT_SIZE??????????????????????????????????????extension_length??????????????????processString???????????????????????????????byte?????????????????????????????????????_total_length_bytes???????????????????????????_string_minimal_overhead?????????????????????????????calculateByteCount????????????????????????????????????????????????char_count???????????????????????????????byte?????????????????????????????????????length??????????????????????????data????????????????????????????????index???????????????????????????????????????str_data????????????????????????????????????????????????????str_data?????????LittleEndian??????????????????????putShort???????????????????????????????bstring????????????????????????????????????????offset????????????????????????????????????????????????char_count?????????offset??????????????????????????????LittleEndianConsts?????????????????????????????????????????????????SHORT_SIZE?????????bstring??????????????????offset?????????????????????????????str_data???????????????????????????????????????offset??????????????????????????str_data????????????????????????????????????_string_data_offset?????????????????????????????????????????????????????????bstring??????????????????????????_string_minimal_overhead??????????????????????????bstring???????????????????????????????????????????_string_minimal_overhead?????????UnicodeString????????????????????????????????????????????????????????????bstring??????????????????????????????????????????????????bstring?????????????getExpectedChars?????????????_unfinished_string??????????????????????????????????string?????????????????????????????????????????getString???????????????????????????????????????????field_3_strings???????????????????????????????????????????????????????????size?????????????field_3_strings?????????????????????????????put?????????????????????????????????integer??????????????????????????????????????????string??????????????????setExpectedChars?????????__expected_chars????????????????????????????count?????????????????calculateByteCount????????????????character_count???????????????????????????????????_wide_char????????????????????????????????????????????????LittleEndianConsts???????????????????????????????????????????????????????????????????SHORT_SIZE????????????????????????????????????????????????LittleEndianConsts???????????????????????????????????????????????????????????????????BYTE_SIZE?????????????????calculateCharCount????????????????byte_count??????????????????????????????_wide_char???????????????????????????????????????????LittleEndianConsts??????????????????????????????????????????????????????????????SHORT_SIZE???????????????????????????????????????????LittleEndianConsts??????????????????????????????????????????????????????????????BYTE_SIZE??????????????????????????getRecordSize?????????_record_lengths???????????????????????????calculateUnicodeSize?????????????unicodesize???????????????????????????_max_data_space?????????????UnicodeString?????????????????????finished?????????????????????first_record??????????????????????????????????????????record????????????????????????????????????_max?????????????????????pos?????????????????????first_record?????????????????????_record_lengths?????????????????????????????????????????????????????record???????????????????????????????????????????????????????_std_record_overhead??????????????????????????????????????????pos??????????????????????????????????????????unicodesize????????????????????????????????????????????????????????stringbyteswritten????????????????????????????????????????????lastneedcontinue??????????????????????????????????????????????????_max?????????????????????????????????????????????????????????_std_record_overhead??????????????????????????????????????????????????to_be_written?????????????????????????size?????????????????????????????????to_be_written?????????????????????????finished?????????????????????record??????????????????????????????size?????????????????????????????????????_std_record_overhead?????????????????????_record_lengths?????????????????????????????????????????????????????size?????????????????????pos?????????????????????lastneedcontinue?????????????????????????????????????_max????????????????????????????????????????????pos?????????????????????????stringreminant???????????????????????????????????????????available??????????????????????????????????????????????????stringbyteswritten???????????????????????????????????????????????stringreminant?????????????????????????pos???????????????????????????????????????????????stringreminant?????????????????????????lastneedcontinue????????????????????????????????????????????????????????????????????unistr??????????????????????????????????????????????????maxBrokenLength??????????????????????????????????????????????????????????????????available?????????????????????????????available??????????????????????????????????????????toBeWritten???????????????????????????????????????????????record??????????????????????????????????????????????????available??????????????????????????????????????????????????????????????toBeWritten?????????????????????????????_record_lengths?????????????????????????????????_record_lengths?????????????????????????????????????shortrecord???????????????????????????????????????????????????_std_record_overhead?????????????????????????????record??????????????????????????????????????shortrecord?????????????????????????stringbyteswritten???????????????????????????????????????????????toBeWritten?????????????????????????pos???????????????????????????????????????????????toBeWritten?????????????????????????stringreminant???????????????????????????????????????????????toBeWritten?????????????????????????lastneedcontinue????????????????????????unipos?????????????????????????????????field_3_strings?????????????????????????????????????????????????size?????????????????????????????????????????????????????????unipos?????????????????????????????????????????_max????????????????????????????????????????????????pos?????????????????????????????????????????????????????unipos?????????????????????unistr????????????????????????????????????????????field_3_strings????????????????????????????????????????????????????????????get????????????????????????????????????????????????????????????????intunipos?????????????????????????unistr????????????????????????????????getRecordSize???????????????????????????????????????????????????available?????????????????????????stringbyteswritten???????????????????????????????????????????????unistr??????????????????????????????????????????????????????getRecordSize?????????????????????????pos???????????????????????????????????????????????unistr??????????????????????????????????????????????????????getRecordSize?????????????????????????????available??????????????????????????????????????????_string_minimal_overhead?????????????????????????????????unistr????????????????????????????????????????maxBrokenLength????????????????????????????????????????????????????????available?????????????????????????????stringbyteswritten???????????????????????????????????????????????????toBeWritten?????????????????????????????stringreminant??????????????????????????????????unistr?????????????????????????????????????????getRecordSize???????????????????????????????????????????????????????????toBeWritten???????????????????????????????????LittleEndianConsts??????????????????????????????????????????????????????BYTE_SIZE?????????????????????????????????available??????????????????????????????????????????????toBeWritten???????????????????????????????????????????????????record??????????????????????????????????????????????????????available??????????????????????????????????????????????????????????????????toBeWritten?????????????????????????????????_record_lengths?????????????????????????????????????_record_lengths?????????????????????????????????????????shortrecord???????????????????????????????????????????????????????_std_record_overhead?????????????????????????????????record??????????????????????????????????????????shortrecord?????????????????????????????lastneedcontinue?????????????????????????????unipos???????????????????????????????????????????????record????????????????????????????????????????????????????????available?????????????????????????????_record_lengths?????????????????????????????????_record_lengths?????????????????????????????????????shortrecord???????????????????????????????????????????????????_std_record_overhead?????????????????????????????record??????????????????????????????????????shortrecord?????????????????totalWritten?????????????????????????????????record?????????????retval??????????????????????totalWritten??????????????????????????retval??????????????????????_sst_record_overhead?????????????????????????????????????????????unicodesize?????????????_record_lengths?????????????????????????????????????????????unicodesize????????????????retval?????????????????calculateUnicodeSize?????????????????????????k?????????????????????????????field_3_strings?????????????????????????????????????????????size?????????????????????????????????????????????????????k?????????????UnicodeString???????????????????????????????????field_3_strings???????????????????????????????????????????????????get???????????????????????????????????????????????????????????????????k?????????????retval???????????????????????string??????????????????????????????getRecordSize????????????????retval