1
54
55 package org.apache.poi.hssf.record;
56
57 import org.apache.poi.util.LittleEndianConsts;
58
59 import java.util.ArrayList;
60 import java.util.List;
61 import java.util.Map;
62
63
68 class SSTRecordSizeCalculator
69 {
70 private UnicodeString unistr = null;
71 private int stringReminant = 0;
72 private int unipos = 0;
73
74 private boolean isRemainingString = false;
75 private int totalBytesWritten = 0;
76 private boolean finished = false;
77 private boolean firstRecord = true;
78 private int totalWritten = 0;
79 private int recordSize = 0;
80 private List recordLengths = new ArrayList();
81 private int pos = 0;
82 private Map strings;
83
84 public SSTRecordSizeCalculator(Map strings)
85 {
86 this.strings = strings;
87 }
88
89
95 public int getRecordSize()
96 {
97 initVars();
98
99 int retval;
100 int totalStringSpaceRequired = SSTSerializer.calculateUnicodeSize(strings);
101
102 if ( totalStringSpaceRequired > SSTRecord.MAX_DATA_SPACE )
103 {
104 retval = sizeOverContinuation( totalStringSpaceRequired );
105 }
106 else
107 {
108
109 retval = SSTRecord.SST_RECORD_OVERHEAD + totalStringSpaceRequired;
110 recordLengths.add( new Integer( totalStringSpaceRequired ) );
111 }
112 return retval;
113 }
114
115 public List getRecordLengths()
116 {
117 return recordLengths;
118 }
119
120 private int sizeOverContinuation( int totalStringSpaceRequired )
121 {
122 int retval;
123
124 while ( !finished )
125 {
126 recordSize = 0;
127 pos = 0;
128
129 if ( firstRecord )
130 {
131 addMaxLengthRecordSize();
132 }
133 else
134 {
135
136
137 pos = 0;
138 int toBeWritten = ( totalStringSpaceRequired - totalBytesWritten ) + ( isRemainingString ? 1 : 0 );
139 int size = Math.min( SSTRecord.MAX_RECORD_SIZE - SSTRecord.STD_RECORD_OVERHEAD, toBeWritten );
140
141 if ( size == toBeWritten )
142 {
143 finished = true;
144 }
145 recordSize = size + SSTRecord.STD_RECORD_OVERHEAD;
146 recordLengths.add( new Integer( size ) );
147 pos = 4;
148 }
149 if ( isRemainingString )
150 {
151 calcReminant();
152 }
153 calcRemainingStrings();
154 totalWritten += recordSize;
155 }
156 retval = totalWritten;
157
158 return retval;
159 }
160
161 private void addMaxLengthRecordSize()
162 {
163
164 recordSize = SSTRecord.MAX_RECORD_SIZE;
165 pos = 12;
166 firstRecord = false;
167 recordLengths.add( new Integer( recordSize - SSTRecord.STD_RECORD_OVERHEAD ) );
168 }
169
170 private void calcRemainingStrings()
171 {
172 for ( ; unipos < strings.size(); unipos++ )
173 {
174 int available = SSTRecord.MAX_RECORD_SIZE - pos;
175 Integer intunipos = new Integer( unipos );
176
177 unistr = ( (UnicodeString) strings.get( intunipos ) );
178 if ( unistr.getRecordSize() <= available )
179 {
180 totalBytesWritten += unistr.getRecordSize();
181 pos += unistr.getRecordSize();
182 }
183 else
184 {
185 if ( available >= SSTRecord.STRING_MINIMAL_OVERHEAD )
186 {
187 int toBeWritten =
188 unistr.maxBrokenLength( available );
189
190 totalBytesWritten += toBeWritten;
191 stringReminant =
192 ( unistr.getRecordSize() - toBeWritten )
193 + LittleEndianConsts.BYTE_SIZE;
194 if ( available != toBeWritten )
195 {
196 int shortrecord = recordSize
197 - ( available - toBeWritten );
198
199 recordLengths.set(
200 recordLengths.size() - 1,
201 new Integer(
202 shortrecord - SSTRecord.STD_RECORD_OVERHEAD ) );
203 recordSize = shortrecord;
204 }
205 isRemainingString = true;
206 unipos++;
207 }
208 else
209 {
210 int shortrecord = recordSize - available;
211
212 recordLengths.set( recordLengths.size() - 1,
213 new Integer( shortrecord - SSTRecord.STD_RECORD_OVERHEAD ) );
214 recordSize = shortrecord;
215 }
216 break;
217 }
218 }
219 }
220
221 private void calcReminant()
222 {
223 int available = SSTRecord.MAX_RECORD_SIZE - pos;
224
225 if ( stringReminant <= available )
226 {
227
228
229 totalBytesWritten += stringReminant - 1;
230 pos += stringReminant;
231 isRemainingString = false;
232 }
233 else
234 {
235
236
237 int toBeWritten = unistr.maxBrokenLength( available );
238
239 if ( available != toBeWritten )
240 {
241 int shortrecord = recordSize - ( available - toBeWritten );
242 recordLengths.set( recordLengths.size() - 1,
243 new Integer( shortrecord - SSTRecord.STD_RECORD_OVERHEAD ) );
244 recordSize = shortrecord;
245 }
246 totalBytesWritten += toBeWritten - 1;
247 pos += toBeWritten;
248 stringReminant -= toBeWritten - 1;
249 isRemainingString = true;
250 }
251 }
252
253 private void initVars()
254 {
255 unistr = null;
256 stringReminant = 0;
257 unipos = 0;
258 isRemainingString = false;
259 totalBytesWritten = 0;
260 finished = false;
261 firstRecord = true;
262 totalWritten = 0;
263 }
264
265 }
266