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