1 /
55
56 package org.apache.poi.hssf.record;
57
58 import java.io.InputStream;
59 import java.io.IOException;
60
61 import java.util.*;
62
63 import java.lang.reflect.Constructor;
64
65 import org.apache.poi.util.LittleEndian;
66
67
78
79 public class RecordFactory
80 {
81 private static int NUM_RECORDS = 10000;
82 private static final Class[] records;
83
84 static {
85 if (FormulaRecord.EXPERIMENTAL_FORMULA_SUPPORT_ENABLED) {
86 records = new Class[]
87 {
88 BOFRecord.class, InterfaceHdrRecord.class, MMSRecord.class,
89 InterfaceEndRecord.class, WriteAccessRecord.class,
90 CodepageRecord.class, DSFRecord.class, TabIdRecord.class,
91 FnGroupCountRecord.class, WindowProtectRecord.class,
92 ProtectRecord.class, PasswordRecord.class, ProtectionRev4Record.class,
93 PasswordRev4Record.class, WindowOneRecord.class, BackupRecord.class,
94 HideObjRecord.class, DateWindow1904Record.class,
95 PrecisionRecord.class, RefreshAllRecord.class, BookBoolRecord.class,
96 FontRecord.class, FormatRecord.class, ExtendedFormatRecord.class,
97 StyleRecord.class, UseSelFSRecord.class, BoundSheetRecord.class,
98 CountryRecord.class, SSTRecord.class, ExtSSTRecord.class,
99 EOFRecord.class, IndexRecord.class, CalcModeRecord.class,
100 CalcCountRecord.class, RefModeRecord.class, IterationRecord.class,
101 DeltaRecord.class, SaveRecalcRecord.class, PrintHeadersRecord.class,
102 PrintGridlinesRecord.class, GridsetRecord.class, GutsRecord.class,
103 DefaultRowHeightRecord.class, WSBoolRecord.class, HeaderRecord.class,
104 FooterRecord.class, HCenterRecord.class, VCenterRecord.class,
105 PrintSetupRecord.class, DefaultColWidthRecord.class,
106 DimensionsRecord.class, RowRecord.class, LabelSSTRecord.class,
107 RKRecord.class, NumberRecord.class, DBCellRecord.class,
108 WindowTwoRecord.class, SelectionRecord.class, ContinueRecord.class,
109 LabelRecord.class, BlankRecord.class, ColumnInfoRecord.class,
110 MulRKRecord.class, MulBlankRecord.class, MergeCellsRecord.class,
111 FormulaRecord.class, BoolErrRecord.class, ExternSheetRecord.class,
112 NameRecord.class, LeftMarginRecord.class, RightMarginRecord.class,
113 TopMarginRecord.class, BottomMarginRecord.class,
114 PaletteRecord.class, StringRecord.class, RecalcIdRecord.class
115 };
116 } else {
117 records = new Class[]
118 {
119 BOFRecord.class, InterfaceHdrRecord.class, MMSRecord.class,
120 InterfaceEndRecord.class, WriteAccessRecord.class,
121 CodepageRecord.class, DSFRecord.class, TabIdRecord.class,
122 FnGroupCountRecord.class, WindowProtectRecord.class,
123 ProtectRecord.class, PasswordRecord.class, ProtectionRev4Record.class,
124 PasswordRev4Record.class, WindowOneRecord.class, BackupRecord.class,
125 HideObjRecord.class, DateWindow1904Record.class,
126 PrecisionRecord.class, RefreshAllRecord.class, BookBoolRecord.class,
127 FontRecord.class, FormatRecord.class, ExtendedFormatRecord.class,
128 StyleRecord.class, UseSelFSRecord.class, BoundSheetRecord.class,
129 CountryRecord.class, SSTRecord.class, ExtSSTRecord.class,
130 EOFRecord.class, IndexRecord.class, CalcModeRecord.class,
131 CalcCountRecord.class, RefModeRecord.class, IterationRecord.class,
132 DeltaRecord.class, SaveRecalcRecord.class, PrintHeadersRecord.class,
133 PrintGridlinesRecord.class, GridsetRecord.class, GutsRecord.class,
134 DefaultRowHeightRecord.class, WSBoolRecord.class, HeaderRecord.class,
135 FooterRecord.class, HCenterRecord.class, VCenterRecord.class,
136 PrintSetupRecord.class, DefaultColWidthRecord.class,
137 DimensionsRecord.class, RowRecord.class, LabelSSTRecord.class,
138 RKRecord.class, NumberRecord.class, DBCellRecord.class,
139 WindowTwoRecord.class, SelectionRecord.class, ContinueRecord.class,
140 LabelRecord.class, BlankRecord.class, ColumnInfoRecord.class,
141 MulRKRecord.class, MulBlankRecord.class, MergeCellsRecord.class,
142 BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class,
143 LeftMarginRecord.class, RightMarginRecord.class,
144 TopMarginRecord.class, BottomMarginRecord.class,
145 PaletteRecord.class, StringRecord.class, RecalcIdRecord.class
146 };
147
148 }
149 }
150 private static Map recordsMap = recordsToMap(records);
151
152
155
156 public static void setCapacity(int capacity)
157 {
158 NUM_RECORDS = capacity;
159 }
160
161
172
173 public static List createRecords(InputStream in)
174 throws RecordFormatException
175 {
176 ArrayList records = new ArrayList(NUM_RECORDS);
177 Record last_record = null;
178
179 try
180 {
181 short rectype = 0;
182
183 do
184 {
185 rectype = LittleEndian.readShort(in);
186 if (rectype != 0)
187 {
188 short recsize = LittleEndian.readShort(in);
189 byte[] data = new byte[ ( int ) recsize ];
190
191 in.read(data);
192 Record[] recs = createRecord(rectype, recsize,
193 data);
194
195 if (recs.length > 1)
196 {
197 for (int k = 0; k < recs.length; k++)
198 {
199 records.add(
200 recs[ k ]);
201 last_record =
202 recs[ k ];
203 }
204 }
205 else
206 {
207 Record record = recs[ 0 ];
208
209 if (record != null)
210 {
211 if (rectype == ContinueRecord.sid)
212 {
213 if (last_record == null)
214 {
215 throw new RecordFormatException(
216 "First record is a ContinueRecord??");
217 }
218 last_record.processContinueRecord(data);
219 }
220 else
221 {
222 last_record = record;
223 records.add(record);
224 }
225 }
226 }
227 }
228 }
229 while (rectype != 0);
230 }
231 catch (IOException e)
232 {
233 throw new RecordFormatException("Error reading bytes");
234 }
235
236
237
238 return records;
239 }
240
241 public static Record [] createRecord(short rectype, short size,
242 byte [] data)
243 {
244 Record retval = null;
245 Record[] realretval = null;
246
247 try
248 {
249 Constructor constructor =
250 ( Constructor ) recordsMap.get(new Short(rectype));
251
252 if (constructor != null)
253 {
254 retval = ( Record ) constructor.newInstance(new Object[]
255 {
256 new Short(rectype), new Short(size), data
257 });
258 }
259 else
260 {
261 retval = new UnknownRecord(rectype, size, data);
262 }
263 }
264 catch (Exception introspectionException)
265 {
266 introspectionException.printStackTrace();
267 throw new RecordFormatException(
268 "Unable to construct record instance, the following exception occured: " + introspectionException.getMessage());
269 }
270 if (retval instanceof RKRecord)
271 {
272 RKRecord rk = ( RKRecord ) retval;
273 NumberRecord num = new NumberRecord();
274
275 num.setColumn(rk.getColumn());
276 num.setRow(rk.getRow());
277 num.setXFIndex(rk.getXFIndex());
278 num.setValue(rk.getRKNumber());
279 retval = num;
280 }
281 else if (retval instanceof DBCellRecord)
282 {
283 retval = null;
284 }
285 else if (retval instanceof MulRKRecord)
286 {
287 MulRKRecord mrk = ( MulRKRecord ) retval;
288
289 realretval = new Record[ mrk.getNumColumns() ];
290 for (int k = 0; k < mrk.getNumColumns(); k++)
291 {
292 NumberRecord nr = new NumberRecord();
293
294 nr.setColumn(( short ) (k + mrk.getFirstColumn()));
295 nr.setRow(mrk.getRow());
296 nr.setXFIndex(mrk.getXFAt(k));
297 nr.setValue(mrk.getRKNumberAt(k));
298 realretval[ k ] = nr;
299 }
300 }
301 else if (retval instanceof MulBlankRecord)
302 {
303 MulBlankRecord mb = ( MulBlankRecord ) retval;
304
305 realretval = new Record[ mb.getNumColumns() ];
306 for (int k = 0; k < mb.getNumColumns(); k++)
307 {
308 BlankRecord br = new BlankRecord();
309
310 br.setColumn(( short ) (k + mb.getFirstColumn()));
311 br.setRow(mb.getRow());
312 br.setXFIndex(mb.getXFAt(k));
313 realretval[ k ] = br;
314 }
315 }
316 if (realretval == null)
317 {
318 realretval = new Record[ 1 ];
319 realretval[ 0 ] = retval;
320 }
321 return realretval;
322 }
323
324 public static short [] getAllKnownRecordSIDs()
325 {
326 short[] results = new short[ recordsMap.size() ];
327 int i = 0;
328
329 for (Iterator iterator = recordsMap.keySet().iterator();
330 iterator.hasNext(); )
331 {
332 Short sid = ( Short ) iterator.next();
333
334 results[ i++ ] = sid.shortValue();
335 }
336 return results;
337 }
338
339 private static Map recordsToMap(Class [] records)
340 {
341 Map result = new HashMap();
342 Constructor constructor;
343
344 for (int i = 0; i < records.length; i++)
345 {
346 Class record = null;
347 short sid = 0;
348
349 record = records[ i ];
350 try
351 {
352 sid = record.getField("sid").getShort(null);
353 constructor = record.getConstructor(new Class[]
354 {
355 short.class, short.class, byte [].class
356 });
357 }
358 catch (Exception illegalArgumentException)
359 {
360 throw new RecordFormatException(
361 "Unable to determine record types");
362 }
363 result.put(new Short(sid), constructor);
364 }
365 return result;
366 }
367 }
368