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