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