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