1
54
55
60 package org.apache.poi.hssf.dev;
61
62 import org.apache.poi.hssf.record.*;
63 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
64 import org.apache.poi.util.HexDump;
65 import org.apache.poi.util.LittleEndian;
66
67 import java.io.FileInputStream;
68 import java.io.IOException;
69 import java.io.InputStream;
70 import java.util.ArrayList;
71
72
78
79 public class BiffViewer
80 {
81 String filename;
82 private boolean dump;
83
84
89
90 public BiffViewer(String[] args)
91 {
92 if (args.length > 0)
93 {
94 filename = args[0];
95 } else
96 {
97 System.out.println("BIFFVIEWER REQUIRES A FILENAME***");
98 }
99 }
100
101
106
107 public void run()
108 {
109 try
110 {
111 POIFSFileSystem fs =
112 new POIFSFileSystem(new FileInputStream(filename));
113 InputStream stream =
114 fs.createDocumentInputStream("Workbook");
115 Record[] records = createRecords(stream, dump);
116 } catch (Exception e)
117 {
118 e.printStackTrace();
119 }
120 }
121
122
134
135 public static Record[] createRecords(InputStream in, boolean dump)
136 throws RecordFormatException
137 {
138 ArrayList records = new ArrayList();
139 Record last_record = null;
140 int loc = 0;
141
142 try
143 {
144
145 short rectype = 0;
146
147 do
148 {
149 rectype = LittleEndian.readShort(in);
150 System.out.println("============================================");
151 System.out.println("Offset 0x" + Integer.toHexString(loc) + " (" + loc + ")");
152 loc += 2;
153 if (rectype != 0)
154 {
155 short recsize = LittleEndian.readShort(in);
156
157 loc += 2;
158 byte[] data = new byte[(int) recsize];
159
160 in.read(data);
161 if ((rectype == WSBoolRecord.sid) && (recsize == 0))
162 {
163 System.out.println(loc);
164 }
165 loc += recsize;
166
167 if (dump)
168 {
169 dump(rectype, recsize, data);
170 }
171 Record[] recs = createRecord(rectype, recsize,
172 data);
173
174 Record record = recs[0];
175
176 if ((record instanceof UnknownRecord)
177 && !dump)
178 {
179 dumpUnknownRecord(data);
180 }
181 if (record != null)
182 {
183 if (rectype == ContinueRecord.sid)
184 {
185 dumpContinueRecord(last_record, dump, data);
186 } else
187 {
188 last_record = record;
189 records.add(record);
190 }
191 }
192 }
193 } while (rectype != 0);
194 } catch (IOException e)
195 {
196 throw new RecordFormatException("Error reading bytes");
197 }
198 Record[] retval = new Record[records.size()];
199
200 retval = (Record[]) records.toArray(retval);
201 return retval;
202 }
203
204 private static void dumpContinueRecord(Record last_record, boolean dump, byte[] data) throws IOException
205 {
206 if (last_record == null)
207 {
208 throw new RecordFormatException(
209 "First record is a ContinueRecord??");
210 }
211 if (dump)
212 {
213 System.out.println(
214 "-----PRECONTINUED LAST RECORD WOULD SERIALIZE LIKE:");
215 byte[] lr = last_record.serialize();
216
217 if (lr != null)
218 {
219 HexDump.dump(last_record.serialize(),
220 0, System.out, 0);
221 }
222 System.out.println();
223 System.out.println(
224 "-----PRECONTINUED----------------------------------");
225 }
226 last_record.processContinueRecord(data);
227 if (dump)
228 {
229 System.out.println(
230 "-----CONTINUED LAST RECORD WOULD SERIALIZE LIKE:");
231 HexDump.dump(last_record.serialize(), 0,
232 System.out, 0);
233 System.out.println();
234 System.out.println(
235 "-----CONTINUED----------------------------------");
236 }
237 }
238
239 private static void dumpUnknownRecord(byte[] data) throws IOException
240 {
241
242 System.out.println(
243 "-----UNKNOWN----------------------------------");
244 if (data.length > 0)
245 {
246 HexDump.dump(data, 0, System.out, 0);
247 } else
248 {
249 System.out.print("**NO RECORD DATA**");
250 }
251 System.out.println();
252 System.out.println(
253 "-----UNKNOWN----------------------------------");
254 }
255
256 private static void dump(short rectype, short recsize, byte[] data) throws IOException
257 {
258
259
260 System.out.print("rectype = 0x"
261 + Integer.toHexString(rectype));
262 System.out.println(", recsize = 0x"
263 + Integer.toHexString(recsize));
264 System.out.println(
265 "-BEGIN DUMP---------------------------------");
266 if (data.length > 0)
267 {
268 HexDump.dump(data, 0, System.out, 0);
269 } else
270 {
271 System.out.println("**NO RECORD DATA**");
272 }
273
274 System.out.println(
275 "-END DUMP-----------------------------------");
276 }
277
278
283
284 private static Record[] createRecord(short rectype, short size,
285 byte[] data)
286 {
287 Record retval = null;
288 Record[] realretval = null;
289
290
291 switch (rectype)
292 {
293
294 case ChartRecord.sid:
295 retval = new ChartRecord(rectype, size, data);
296 break;
297
298 case ChartFormatRecord.sid:
299 retval = new ChartFormatRecord(rectype, size, data);
300 break;
301
302 case SeriesRecord.sid:
303 retval = new SeriesRecord(rectype, size, data);
304 break;
305
306 case BeginRecord.sid:
307 retval = new BeginRecord(rectype, size, data);
308 break;
309
310 case EndRecord.sid:
311 retval = new EndRecord(rectype, size, data);
312 break;
313
314 case BOFRecord.sid:
315 retval = new BOFRecord(rectype, size, data);
316 break;
317
318 case InterfaceHdrRecord.sid:
319 retval = new InterfaceHdrRecord(rectype, size, data);
320 break;
321
322 case MMSRecord.sid:
323 retval = new MMSRecord(rectype, size, data);
324 break;
325
326 case InterfaceEndRecord.sid:
327 retval = new InterfaceEndRecord(rectype, size, data);
328 break;
329
330 case WriteAccessRecord.sid:
331 retval = new WriteAccessRecord(rectype, size, data);
332 break;
333
334 case CodepageRecord.sid:
335 retval = new CodepageRecord(rectype, size, data);
336 break;
337
338 case DSFRecord.sid:
339 retval = new DSFRecord(rectype, size, data);
340 break;
341
342 case TabIdRecord.sid:
343 retval = new TabIdRecord(rectype, size, data);
344 break;
345
346 case FnGroupCountRecord.sid:
347 retval = new FnGroupCountRecord(rectype, size, data);
348 break;
349
350 case WindowProtectRecord.sid:
351 retval = new WindowProtectRecord(rectype, size, data);
352 break;
353
354 case ProtectRecord.sid:
355 retval = new ProtectRecord(rectype, size, data);
356 break;
357
358 case PasswordRecord.sid:
359 retval = new PasswordRecord(rectype, size, data);
360 break;
361
362 case ProtectionRev4Record.sid:
363 retval = new ProtectionRev4Record(rectype, size, data);
364 break;
365
366 case PasswordRev4Record.sid:
367 retval = new PasswordRev4Record(rectype, size, data);
368 break;
369
370 case WindowOneRecord.sid:
371 retval = new WindowOneRecord(rectype, size, data);
372 break;
373
374 case BackupRecord.sid:
375 retval = new BackupRecord(rectype, size, data);
376 break;
377
378 case HideObjRecord.sid:
379 retval = new HideObjRecord(rectype, size, data);
380 break;
381
382 case DateWindow1904Record.sid:
383 retval = new DateWindow1904Record(rectype, size, data);
384 break;
385
386 case PrecisionRecord.sid:
387 retval = new PrecisionRecord(rectype, size, data);
388 break;
389
390 case RefreshAllRecord.sid:
391 retval = new RefreshAllRecord(rectype, size, data);
392 break;
393
394 case BookBoolRecord.sid:
395 retval = new BookBoolRecord(rectype, size, data);
396 break;
397
398 case FontRecord.sid:
399 retval = new FontRecord(rectype, size, data);
400 break;
401
402 case FormatRecord.sid:
403 retval = new FormatRecord(rectype, size, data);
404 break;
405
406 case ExtendedFormatRecord.sid:
407 retval = new ExtendedFormatRecord(rectype, size, data);
408 break;
409
410 case StyleRecord.sid:
411 retval = new StyleRecord(rectype, size, data);
412 break;
413
414 case UseSelFSRecord.sid:
415 retval = new UseSelFSRecord(rectype, size, data);
416 break;
417
418 case BoundSheetRecord.sid:
419 retval = new BoundSheetRecord(rectype, size, data);
420 break;
421
422 case CountryRecord.sid:
423 retval = new CountryRecord(rectype, size, data);
424 break;
425
426 case SSTRecord.sid:
427 retval = new SSTRecord(rectype, size, data);
428 break;
429
430 case ExtSSTRecord.sid:
431 retval = new ExtSSTRecord(rectype, size, data);
432 break;
433
434 case EOFRecord.sid:
435 retval = new EOFRecord(rectype, size, data);
436 break;
437
438 case IndexRecord.sid:
439 retval = new IndexRecord(rectype, size, data);
440 break;
441
442 case CalcModeRecord.sid:
443 retval = new CalcModeRecord(rectype, size, data);
444 break;
445
446 case CalcCountRecord.sid:
447 retval = new CalcCountRecord(rectype, size, data);
448 break;
449
450 case RefModeRecord.sid:
451 retval = new RefModeRecord(rectype, size, data);
452 break;
453
454 case IterationRecord.sid:
455 retval = new IterationRecord(rectype, size, data);
456 break;
457
458 case DeltaRecord.sid:
459 retval = new DeltaRecord(rectype, size, data);
460 break;
461
462 case SaveRecalcRecord.sid:
463 retval = new SaveRecalcRecord(rectype, size, data);
464 break;
465
466 case PrintHeadersRecord.sid:
467 retval = new PrintHeadersRecord(rectype, size, data);
468 break;
469
470 case PrintGridlinesRecord.sid:
471 retval = new PrintGridlinesRecord(rectype, size, data);
472 break;
473
474 case GridsetRecord.sid:
475 retval = new GridsetRecord(rectype, size, data);
476 break;
477
478 case GutsRecord.sid:
479 retval = new GutsRecord(rectype, size, data);
480 break;
481
482 case DefaultRowHeightRecord.sid:
483 retval = new DefaultRowHeightRecord(rectype, size, data);
484 break;
485
486 case WSBoolRecord.sid:
487 retval = new WSBoolRecord(rectype, size, data);
488 break;
489
490 case HeaderRecord.sid:
491 retval = new HeaderRecord(rectype, size, data);
492 break;
493
494 case FooterRecord.sid:
495 retval = new FooterRecord(rectype, size, data);
496 break;
497
498 case HCenterRecord.sid:
499 retval = new HCenterRecord(rectype, size, data);
500 break;
501
502 case VCenterRecord.sid:
503 retval = new VCenterRecord(rectype, size, data);
504 break;
505
506 case PrintSetupRecord.sid:
507 retval = new PrintSetupRecord(rectype, size, data);
508 break;
509
510 case DefaultColWidthRecord.sid:
511 retval = new DefaultColWidthRecord(rectype, size, data);
512 break;
513
514 case DimensionsRecord.sid:
515 retval = new DimensionsRecord(rectype, size, data);
516 break;
517
518 case RowRecord.sid:
519 retval = new RowRecord(rectype, size, data);
520 break;
521
522 case LabelSSTRecord.sid:
523 retval = new LabelSSTRecord(rectype, size, data);
524 break;
525
526 case RKRecord.sid:
527 retval = new RKRecord(rectype, size, data);
528 break;
529
530 case NumberRecord.sid:
531 retval = new NumberRecord(rectype, size, data);
532 break;
533
534 case DBCellRecord.sid:
535 retval = new DBCellRecord(rectype, size, data);
536 break;
537
538 case WindowTwoRecord.sid:
539 retval = new WindowTwoRecord(rectype, size, data);
540 break;
541
542 case SelectionRecord.sid:
543 retval = new SelectionRecord(rectype, size, data);
544 break;
545
546 case ContinueRecord.sid:
547 retval = new ContinueRecord(rectype, size, data);
548 break;
549
550 case LabelRecord.sid:
551 retval = new LabelRecord(rectype, size, data);
552 break;
553
554 case MulRKRecord.sid:
555 retval = new MulRKRecord(rectype, size, data);
556 break;
557
558 case MulBlankRecord.sid:
559 retval = new MulBlankRecord(rectype, size, data);
560 break;
561
562 case BlankRecord.sid:
563 retval = new BlankRecord(rectype, size, data);
564 break;
565
566 case BoolErrRecord.sid:
567 retval = new BoolErrRecord(rectype, size, data);
568 break;
569
570 case ColumnInfoRecord.sid:
571 retval = new ColumnInfoRecord(rectype, size, data);
572 break;
573
574 case MergeCellsRecord.sid:
575 retval = new MergeCellsRecord(rectype, size, data);
576 break;
577
578 case AreaRecord.sid:
579 retval = new AreaRecord(rectype, size, data);
580 break;
581
582 case DataFormatRecord.sid:
583 retval = new DataFormatRecord(rectype, size, data);
584 break;
585
586 case BarRecord.sid:
587 retval = new BarRecord(rectype, size, data);
588 break;
589
590 case DatRecord.sid:
591 retval = new DatRecord(rectype, size, data);
592 break;
593
594 case PlotGrowthRecord.sid:
595 retval = new PlotGrowthRecord(rectype, size, data);
596 break;
597
598 case UnitsRecord.sid:
599 retval = new UnitsRecord(rectype, size, data);
600 break;
601
602 case FrameRecord.sid:
603 retval = new FrameRecord(rectype, size, data);
604 break;
605
606 case ValueRangeRecord.sid:
607 retval = new ValueRangeRecord(rectype, size, data);
608 break;
609
610 case SeriesListRecord.sid:
611 retval = new SeriesListRecord(rectype, size, data);
612 break;
613
614 case FontBasisRecord.sid:
615 retval = new FontBasisRecord(rectype, size, data);
616 break;
617
618 case FontIndexRecord.sid:
619 retval = new FontIndexRecord(rectype, size, data);
620 break;
621
622 case LineFormatRecord.sid:
623 retval = new LineFormatRecord(rectype, size, data);
624 break;
625
626 case AreaFormatRecord.sid:
627 retval = new AreaFormatRecord(rectype, size, data);
628 break;
629
630 case LinkedDataRecord.sid:
631 retval = new LinkedDataRecord(rectype, size, data);
632 break;
633
634 case FormulaRecord.sid:
635 retval = new FormulaRecord(rectype, size, data);
636 break;
637
638 case SheetPropertiesRecord.sid:
639 retval = new SheetPropertiesRecord(rectype, size, data);
640 break;
641
642 case DefaultDataLabelTextPropertiesRecord.sid:
643 retval = new DefaultDataLabelTextPropertiesRecord(rectype, size, data);
644 break;
645
646 case TextRecord.sid:
647 retval = new TextRecord(rectype, size, data);
648 break;
649
650 case AxisParentRecord.sid:
651 retval = new AxisParentRecord(rectype, size, data);
652 break;
653
654 case AxisLineFormatRecord.sid:
655 retval = new AxisLineFormatRecord(rectype, size, data);
656 break;
657
658
659 default :
660 retval = new UnknownRecord(rectype, size, data);
661 }
662 if (realretval == null)
663 {
664 realretval = new Record[1];
665 realretval[0] = retval;
666 System.out.println("recordid = 0x" + Integer.toHexString(rectype) + ", size =" + size);
667 System.out.println(realretval[0].toString());
668 }
669 return realretval;
670 }
671
672
679
680 public void setDump(boolean dump)
681 {
682 this.dump = dump;
683 }
684
685
698
699 public static void main(String[] args)
700 {
701 try
702 {
703 BiffViewer viewer = new BiffViewer(args);
704
705 if ((args.length > 1) && args[1].equals("on"))
706 {
707 viewer.setDump(true);
708 }
709 if ((args.length > 1) && args[1].equals("bfd"))
710 {
711 POIFSFileSystem fs =
712 new POIFSFileSystem(new FileInputStream(args[0]));
713 InputStream stream =
714 fs.createDocumentInputStream("Workbook");
715 int size = stream.available();
716 byte[] data = new byte[size];
717
718 stream.read(data);
719 HexDump.dump(data, 0, System.out, 0);
720 } else
721 {
722 viewer.run();
723 }
724 } catch (Exception e)
725 {
726 e.printStackTrace();
727 }
728 }
729 }
730