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