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