1
54
55 package org.apache.poi.hssf.record;
56
57 import org.apache.poi.util.BinaryTree;
58
59 import java.util.List;
60 import java.util.ArrayList;
61 import java.util.Map;
62
63
69 class SSTSerializer
70 {
71
72
73 private List recordLengths;
74 private BinaryTree strings;
75
76 private int numStrings;
77 private int numUniqueStrings;
78 private SSTRecordHeader sstRecordHeader;
79
80 public SSTSerializer( List recordLengths, BinaryTree strings, int numStrings, int numUniqueStrings )
81 {
82 this.recordLengths = recordLengths;
83 this.strings = strings;
84 this.numStrings = numStrings;
85 this.numUniqueStrings = numUniqueStrings;
86 this.sstRecordHeader = new SSTRecordHeader( numStrings, numUniqueStrings );
87 }
88
89
100 public int serialize( int record_size, int offset, byte[] data )
101 {
102 int record_length_index = 0;
103
104 if ( calculateUnicodeSize() > SSTRecord.MAX_DATA_SPACE )
105 serializeLargeRecord( record_size, record_length_index, data, offset );
106 else
107 serializeSingleSSTRecord( data, offset, record_length_index );
108 return record_size;
109 }
110
111
112
113
118 public static int calculateUnicodeSize(Map strings)
119 {
120 int retval = 0;
121
122 for ( int k = 0; k < strings.size(); k++ )
123 {
124 retval += getUnicodeString( strings, k ).getRecordSize();
125 }
126 return retval;
127 }
128
129 public int calculateUnicodeSize()
130 {
131 return calculateUnicodeSize(strings);
132 }
133
134
138 private void serializeSingleSSTRecord( byte[] data, int offset, int record_length_index )
139 {
140 int len = ( (Integer) recordLengths.get( record_length_index ) ).intValue();
141 int recordSize = SSTRecord.SST_RECORD_OVERHEAD + len - SSTRecord.STD_RECORD_OVERHEAD;
142 sstRecordHeader.writeSSTHeader( data, 0 + offset, recordSize );
143 int pos = SSTRecord.SST_RECORD_OVERHEAD;
144
145 for ( int k = 0; k < strings.size(); k++ )
146 {
147 System.arraycopy( getUnicodeString( k ).serialize(), 0, data, pos + offset, getUnicodeString( k ).getRecordSize() );
148 pos += getUnicodeString( k ).getRecordSize();
149 }
150 }
151
152
157 private void serializeLargeRecord( int record_size, int record_length_index, byte[] buffer, int offset )
158 {
159
160 byte[] stringReminant = null;
161 int stringIndex = 0;
162 boolean lastneedcontinue = false;
163 boolean first_record = true;
164 int totalWritten = 0;
165
166 while ( totalWritten != record_size )
167 {
168 int recordLength = ( (Integer) recordLengths.get( record_length_index++ ) ).intValue();
169 RecordProcessor recordProcessor = new RecordProcessor( buffer,
170 recordLength, numStrings, numUniqueStrings );
171
172
173 recordProcessor.writeRecordHeader( offset, totalWritten, recordLength, first_record );
174 first_record = false;
175
176
177
178 if ( lastneedcontinue )
179 {
180 lastneedcontinue = stringReminant.length > recordProcessor.getAvailable();
181
182 stringReminant = recordProcessor.writeStringRemainder( lastneedcontinue,
183 stringReminant, offset, totalWritten );
184 }
185
186
187
188 for ( ; stringIndex < strings.size(); stringIndex++ )
189 {
190 UnicodeString unistr = getUnicodeString( stringIndex );
191
192 if ( unistr.getRecordSize() <= recordProcessor.getAvailable() )
193 {
194 recordProcessor.writeWholeString( unistr, offset, totalWritten );
195 }
196 else
197 {
198
199
200 if ( recordProcessor.getAvailable() >= SSTRecord.STRING_MINIMAL_OVERHEAD )
201 {
202
203
204 stringReminant = recordProcessor.writePartString( unistr, offset, totalWritten );
205 lastneedcontinue = true;
206 stringIndex++;
207 }
208 break;
209 }
210 }
211 totalWritten += recordLength + SSTRecord.STD_RECORD_OVERHEAD;
212 }
213 }
214
215 private UnicodeString getUnicodeString( int index )
216 {
217 return getUnicodeString(strings, index);
218 }
219
220 private static UnicodeString getUnicodeString( Map strings, int index )
221 {
222 Integer intunipos = new Integer( index );
223 return ( (UnicodeString) strings.get( intunipos ) );
224 }
225
226 public int getRecordSize()
227 {
228 SSTRecordSizeCalculator calculator = new SSTRecordSizeCalculator(strings);
229 int recordSize = calculator.getRecordSize();
230 recordLengths = calculator.getRecordLengths();
231 return recordSize;
232 }
233
234 public List getRecordLengths()
235 {
236 return recordLengths;
237 }
238 }
239