1 /
55 package org.apache.poi.hssf.eventmodel;
56
57 import java.io.InputStream;
58 import java.io.IOException;
59
60 import java.util.*;
61
62 import java.lang.reflect.Constructor;
63
64 import org.apache.poi.hssf.record.BOFRecord;
65 import org.apache.poi.hssf.record.BackupRecord;
66 import org.apache.poi.hssf.record.BlankRecord;
67 import org.apache.poi.hssf.record.BookBoolRecord;
68 import org.apache.poi.hssf.record.BoolErrRecord;
69 import org.apache.poi.hssf.record.BottomMarginRecord;
70 import org.apache.poi.hssf.record.BoundSheetRecord;
71 import org.apache.poi.hssf.record.CalcCountRecord;
72 import org.apache.poi.hssf.record.CalcModeRecord;
73 import org.apache.poi.hssf.record.CodepageRecord;
74 import org.apache.poi.hssf.record.ColumnInfoRecord;
75 import org.apache.poi.hssf.record.ContinueRecord;
76 import org.apache.poi.hssf.record.CountryRecord;
77 import org.apache.poi.hssf.record.DBCellRecord;
78 import org.apache.poi.hssf.record.DSFRecord;
79 import org.apache.poi.hssf.record.DateWindow1904Record;
80 import org.apache.poi.hssf.record.DefaultColWidthRecord;
81 import org.apache.poi.hssf.record.DefaultRowHeightRecord;
82 import org.apache.poi.hssf.record.DeltaRecord;
83 import org.apache.poi.hssf.record.DimensionsRecord;
84 import org.apache.poi.hssf.record.EOFRecord;
85 import org.apache.poi.hssf.record.ExtSSTRecord;
86 import org.apache.poi.hssf.record.ExtendedFormatRecord;
87 import org.apache.poi.hssf.record.ExternSheetRecord;
88 import org.apache.poi.hssf.record.FnGroupCountRecord;
89 import org.apache.poi.hssf.record.FontRecord;
90 import org.apache.poi.hssf.record.FooterRecord;
91 import org.apache.poi.hssf.record.FormatRecord;
92 import org.apache.poi.hssf.record.FormulaRecord;
93 import org.apache.poi.hssf.record.GridsetRecord;
94 import org.apache.poi.hssf.record.GutsRecord;
95 import org.apache.poi.hssf.record.HCenterRecord;
96 import org.apache.poi.hssf.record.HeaderRecord;
97 import org.apache.poi.hssf.record.HideObjRecord;
98 import org.apache.poi.hssf.record.IndexRecord;
99 import org.apache.poi.hssf.record.InterfaceEndRecord;
100 import org.apache.poi.hssf.record.InterfaceHdrRecord;
101 import org.apache.poi.hssf.record.IterationRecord;
102 import org.apache.poi.hssf.record.LabelRecord;
103 import org.apache.poi.hssf.record.LabelSSTRecord;
104 import org.apache.poi.hssf.record.LeftMarginRecord;
105 import org.apache.poi.hssf.record.MMSRecord;
106 import org.apache.poi.hssf.record.MergeCellsRecord;
107 import org.apache.poi.hssf.record.MulBlankRecord;
108 import org.apache.poi.hssf.record.MulRKRecord;
109 import org.apache.poi.hssf.record.NameRecord;
110 import org.apache.poi.hssf.record.NumberRecord;
111 import org.apache.poi.hssf.record.PaletteRecord;
112 import org.apache.poi.hssf.record.PasswordRecord;
113 import org.apache.poi.hssf.record.PasswordRev4Record;
114 import org.apache.poi.hssf.record.PrecisionRecord;
115 import org.apache.poi.hssf.record.PrintGridlinesRecord;
116 import org.apache.poi.hssf.record.PrintHeadersRecord;
117 import org.apache.poi.hssf.record.PrintSetupRecord;
118 import org.apache.poi.hssf.record.ProtectRecord;
119 import org.apache.poi.hssf.record.ProtectionRev4Record;
120 import org.apache.poi.hssf.record.RKRecord;
121 import org.apache.poi.hssf.record.Record;
122 import org.apache.poi.hssf.record.RecordFormatException;
123 import org.apache.poi.hssf.record.RefModeRecord;
124 import org.apache.poi.hssf.record.RefreshAllRecord;
125 import org.apache.poi.hssf.record.RightMarginRecord;
126 import org.apache.poi.hssf.record.RowRecord;
127 import org.apache.poi.hssf.record.SSTRecord;
128 import org.apache.poi.hssf.record.SaveRecalcRecord;
129 import org.apache.poi.hssf.record.SelectionRecord;
130 import org.apache.poi.hssf.record.StringRecord;
131 import org.apache.poi.hssf.record.StyleRecord;
132 import org.apache.poi.hssf.record.TabIdRecord;
133 import org.apache.poi.hssf.record.TopMarginRecord;
134 import org.apache.poi.hssf.record.UnknownRecord;
135 import org.apache.poi.hssf.record.UseSelFSRecord;
136 import org.apache.poi.hssf.record.VCenterRecord;
137 import org.apache.poi.hssf.record.WSBoolRecord;
138 import org.apache.poi.hssf.record.WindowOneRecord;
139 import org.apache.poi.hssf.record.WindowProtectRecord;
140 import org.apache.poi.hssf.record.WindowTwoRecord;
141 import org.apache.poi.hssf.record.WriteAccessRecord;
142 import org.apache.poi.util.LittleEndian;
143
144
145
155 public class EventRecordFactory
156 {
157
158
161 private static final Class[] records;
162
163 static {
164 records = new Class[]
165 {
166 BOFRecord.class, InterfaceHdrRecord.class, MMSRecord.class,
167 InterfaceEndRecord.class, WriteAccessRecord.class,
168 CodepageRecord.class, DSFRecord.class, TabIdRecord.class,
169 FnGroupCountRecord.class, WindowProtectRecord.class,
170 ProtectRecord.class, PasswordRecord.class, ProtectionRev4Record.class,
171 PasswordRev4Record.class, WindowOneRecord.class, BackupRecord.class,
172 HideObjRecord.class, DateWindow1904Record.class,
173 PrecisionRecord.class, RefreshAllRecord.class, BookBoolRecord.class,
174 FontRecord.class, FormatRecord.class, ExtendedFormatRecord.class,
175 StyleRecord.class, UseSelFSRecord.class, BoundSheetRecord.class,
176 CountryRecord.class, SSTRecord.class, ExtSSTRecord.class,
177 EOFRecord.class, IndexRecord.class, CalcModeRecord.class,
178 CalcCountRecord.class, RefModeRecord.class, IterationRecord.class,
179 DeltaRecord.class, SaveRecalcRecord.class, PrintHeadersRecord.class,
180 PrintGridlinesRecord.class, GridsetRecord.class, GutsRecord.class,
181 DefaultRowHeightRecord.class, WSBoolRecord.class, HeaderRecord.class,
182 FooterRecord.class, HCenterRecord.class, VCenterRecord.class,
183 PrintSetupRecord.class, DefaultColWidthRecord.class,
184 DimensionsRecord.class, RowRecord.class, LabelSSTRecord.class,
185 RKRecord.class, NumberRecord.class, DBCellRecord.class,
186 WindowTwoRecord.class, SelectionRecord.class, ContinueRecord.class,
187 LabelRecord.class, BlankRecord.class, ColumnInfoRecord.class,
188 MulRKRecord.class, MulBlankRecord.class, MergeCellsRecord.class,
189 BoolErrRecord.class, ExternSheetRecord.class, NameRecord.class,
190 LeftMarginRecord.class, RightMarginRecord.class,
191 TopMarginRecord.class, BottomMarginRecord.class,
192 PaletteRecord.class, StringRecord.class
193 };
194
195 }
196
197
200 private static Map recordsMap = recordsToMap(records);
201
202
206 private static short[] sidscache;
207
208
211 private List listeners;
212
213
216 private boolean abortable;
217
218
223 public EventRecordFactory() {
224 this(true);
225 }
226
227
233 public EventRecordFactory(boolean abortable) {
234 this.abortable = abortable;
235 listeners = new ArrayList(recordsMap.size());
236
237 if (sidscache == null) {
238 sidscache = getAllKnownRecordSIDs();
239 }
240
241 }
242
243
251 public void registerListener(ERFListener listener, short[] sids) {
252 if (sids == null)
253 sids = sidscache;
254 ERFListener wrapped = new ListenerWrapper(listener, sids, abortable);
255 listeners.add(wrapped);
256 }
257
258
262 protected Iterator listeners() {
263 return listeners.iterator();
264 }
265
266
272 private boolean throwRecordEvent(Record record)
273 {
274 boolean result = true;
275 Iterator i = listeners.iterator();
276
277 while (i.hasNext()) {
278 result = ((ERFListener) i.next()).processRecord(record);
279 if (abortable == true && result == false) {
280 break;
281 }
282 }
283 return result;
284 }
285
286
297 public void processRecords(InputStream in)
298 throws RecordFormatException
299 {
300 Record last_record = null;
301
302 try
303 {
304 short rectype = 0;
305
306 do
307 {
308 rectype = LittleEndian.readShort(in);
309 if (rectype != 0)
310 {
311 short recsize = LittleEndian.readShort(in);
312 byte[] data = new byte[ ( int ) recsize ];
313
314 in.read(data);
315 Record[] recs = createRecord(rectype, recsize,
316 data);
317
318 if (recs.length > 1)
319 {
320 for (int k = 0; k < recs.length; k++)
321 {
322 if ( last_record != null ) {
323 if (throwRecordEvent(last_record) == false && abortable == true) {
324 last_record = null;
325 break;
326 }
327 }
328
329
330 last_record =
331 recs[ k ];
332 }
333 }
334 else
335 {
336 Record record = recs[ 0 ];
337
338 if (record != null)
339 {
340 if (rectype == ContinueRecord.sid)
341 {
342 if (last_record == null)
343 {
344 throw new RecordFormatException(
345 "First record is a ContinueRecord??");
346 }
347 last_record.processContinueRecord(data);
348 }
349 else
350 {
351 if (last_record != null) {
352 if (throwRecordEvent(last_record) == false && abortable == true) {
353 last_record = null;
354 break;
355 }
356 }
357
358 last_record = record;
359
360
361 }
362 }
363 }
364 }
365 }
366 while (rectype != 0);
367
368 if (last_record != null) {
369 throwRecordEvent(last_record);
370 }
371 }
372 catch (IOException e)
373 {
374 throw new RecordFormatException("Error reading bytes");
375 }
376
377
378
379
380 }
381
382
386 public static Record [] createRecord(short rectype, short size,
387 byte [] data)
388 {
389 Record retval = null;
390 Record[] realretval = null;
391
392 try
393 {
394 Constructor constructor =
395 ( Constructor ) recordsMap.get(new Short(rectype));
396
397 if (constructor != null)
398 {
399 retval = ( Record ) constructor.newInstance(new Object[]
400 {
401 new Short(rectype), new Short(size), data
402 });
403 }
404 else
405 {
406 retval = new UnknownRecord(rectype, size, data);
407 }
408 }
409 catch (Exception introspectionException)
410 {
411 introspectionException.printStackTrace();
412 throw new RecordFormatException(
413 "Unable to construct record instance, the following exception occured: " + introspectionException.getMessage());
414 }
415 if (retval instanceof RKRecord)
416 {
417 RKRecord rk = ( RKRecord ) retval;
418 NumberRecord num = new NumberRecord();
419
420 num.setColumn(rk.getColumn());
421 num.setRow(rk.getRow());
422 num.setXFIndex(rk.getXFIndex());
423 num.setValue(rk.getRKNumber());
424 retval = num;
425 }
426 else if (retval instanceof DBCellRecord)
427 {
428 retval = null;
429 }
430 else if (retval instanceof MulRKRecord)
431 {
432 MulRKRecord mrk = ( MulRKRecord ) retval;
433
434 realretval = new Record[ mrk.getNumColumns() ];
435 for (int k = 0; k < mrk.getNumColumns(); k++)
436 {
437 NumberRecord nr = new NumberRecord();
438
439 nr.setColumn(( short ) (k + mrk.getFirstColumn()));
440 nr.setRow(mrk.getRow());
441 nr.setXFIndex(mrk.getXFAt(k));
442 nr.setValue(mrk.getRKNumberAt(k));
443 realretval[ k ] = nr;
444 }
445 }
446 else if (retval instanceof MulBlankRecord)
447 {
448 MulBlankRecord mb = ( MulBlankRecord ) retval;
449
450 realretval = new Record[ mb.getNumColumns() ];
451 for (int k = 0; k < mb.getNumColumns(); k++)
452 {
453 BlankRecord br = new BlankRecord();
454
455 br.setColumn(( short ) (k + mb.getFirstColumn()));
456 br.setRow(mb.getRow());
457 br.setXFIndex(mb.getXFAt(k));
458 realretval[ k ] = br;
459 }
460 }
461 if (realretval == null)
462 {
463 realretval = new Record[ 1 ];
464 realretval[ 0 ] = retval;
465 }
466 return realretval;
467 }
468
469
472 public static short [] getAllKnownRecordSIDs()
473 {
474 short[] results = new short[ recordsMap.size() ];
475 int i = 0;
476
477 for (Iterator iterator = recordsMap.keySet().iterator();
478 iterator.hasNext(); )
479 {
480 Short sid = ( Short ) iterator.next();
481
482 results[ i++ ] = sid.shortValue();
483 }
484 return results;
485 }
486
487
492 private static Map recordsToMap(Class [] records)
493 {
494 Map result = new HashMap();
495 Constructor constructor;
496
497 for (int i = 0; i < records.length; i++)
498 {
499 Class record = null;
500 short sid = 0;
501
502 record = records[ i ];
503 try
504 {
505 sid = record.getField("sid").getShort(null);
506 constructor = record.getConstructor(new Class[]
507 {
508 short.class, short.class, byte [].class
509 });
510 }
511 catch (Exception illegalArgumentException)
512 {
513 throw new RecordFormatException(
514 "Unable to determine record types");
515 }
516 result.put(new Short(sid), constructor);
517 }
518 return result;
519 }
520
521 }
522
523
527 class ListenerWrapper implements ERFListener {
528 private ERFListener listener;
529 private short[] sids;
530 private boolean abortable;
531
532 ListenerWrapper(ERFListener listener, short[] sids, boolean abortable) {
533 this.listener = listener;
534 this.sids = sids;
535 this.abortable = abortable;
536 }
537
538
539 public boolean processRecord(Record rec)
540 {
541 boolean result = true;
542 for (int k = 0; k < sids.length; k++) {
543 if (sids[k] == rec.getSid()) {
544 result = listener.processRecord(rec);
545
546 if (abortable == true && result == false) {
547 break;
548 }
549 }
550 }
551 return result;
552 }
553 }
554