biffviewer.java
来自「EXCEL read and write」· Java 代码 · 共 531 行 · 第 1/2 页
JAVA
531 行
} else { ps = System.out; } if (args.length > 1 && args[1].equals("bfd")) { POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile)); InputStream stream = fs.createDocumentInputStream("Workbook"); int size = stream.available(); byte[] data = new byte[size]; stream.read(data); HexDump.dump(data, 0, System.out, 0); } else { boolean dumpInterpretedRecords = true; boolean dumpHex = args.length > 1 && args[1].equals("on"); POIFSFileSystem fs = new POIFSFileSystem(new FileInputStream(inputFile)); InputStream is = fs.createDocumentInputStream("Workbook"); BiffRecordListener recListener = new BiffRecordListener(dumpHex ? new OutputStreamWriter(ps) : null); is = new BiffDumpingStream(is, recListener); createRecords(is, ps, recListener, dumpInterpretedRecords); } ps.close(); } catch (Exception e) { e.printStackTrace(); } } private static final class BiffRecordListener implements IBiffRecordListener { private final Writer _hexDumpWriter; private final List _headers; public BiffRecordListener(Writer hexDumpWriter) { _hexDumpWriter = hexDumpWriter; _headers = new ArrayList(); } public void processRecord(int globalOffset, int recordCounter, int sid, int dataSize, byte[] data) { String header = formatRecordDetails(globalOffset, sid, dataSize, recordCounter); _headers.add(header); Writer w = _hexDumpWriter; if (w != null) { try { w.write(header); w.write(NEW_LINE_CHARS); hexDumpAligned(w, data, 0, dataSize+4, globalOffset); w.flush(); } catch (IOException e) { throw new RuntimeException(e); } } } public String[] getRecentHeaders() { String[] result = new String[_headers.size()]; _headers.toArray(result); _headers.clear(); return result; } private static String formatRecordDetails(int globalOffset, int sid, int size, int recordCounter) { StringBuffer sb = new StringBuffer(64); sb.append("Offset=").append(HexDump.intToHex(globalOffset)).append("(").append(globalOffset).append(")"); sb.append(" recno=").append(recordCounter); sb.append( " sid=").append(HexDump.shortToHex(sid)); sb.append( " size=").append(HexDump.shortToHex(size)).append("(").append(size).append(")"); return sb.toString(); } } private static interface IBiffRecordListener { void processRecord(int globalOffset, int recordCounter, int sid, int dataSize, byte[] data); } /** * Wraps a plain {@link InputStream} and allows BIFF record information to be tapped off * */ private static final class BiffDumpingStream extends InputStream { private final DataInputStream _is; private final IBiffRecordListener _listener; private final byte[] _data; private int _recordCounter; private int _overallStreamPos; private int _currentPos; private int _currentSize; private boolean _innerHasReachedEOF; public BiffDumpingStream(InputStream is, IBiffRecordListener listener) { _is = new DataInputStream(is); _listener = listener; _data = new byte[RecordInputStream.MAX_RECORD_DATA_SIZE + 4]; _recordCounter = 0; _overallStreamPos = 0; _currentSize = 0; _currentPos = 0; } public int read() throws IOException { if (_currentPos >= _currentSize) { fillNextBuffer(); } if (_currentPos >= _currentSize) { return -1; } int result = _data[_currentPos] & 0x00FF; _currentPos ++; _overallStreamPos ++; formatBufferIfAtEndOfRec(); return result; } public int read(byte[] b, int off, int len) throws IOException { if (_currentPos >= _currentSize) { fillNextBuffer(); } if (_currentPos >= _currentSize) { return -1; } int availSize = _currentSize - _currentPos; int result; if (len > availSize) { System.err.println("Unexpected request to read past end of current biff record"); result = availSize; } else { result = len; } System.arraycopy(_data, _currentPos, b, off, result); _currentPos += result; _overallStreamPos += result; formatBufferIfAtEndOfRec(); return result; } public int available() throws IOException { return _currentSize - _currentPos + _is.available(); } private void fillNextBuffer() throws IOException { if (_innerHasReachedEOF) { return; } int b0 = _is.read(); if (b0 == -1) { _innerHasReachedEOF = true; return; } _data[0] = (byte) b0; _is.readFully(_data, 1, 3); int len = LittleEndian.getShort(_data, 2); _is.readFully(_data, 4, len); _currentPos = 0; _currentSize = len + 4; _recordCounter++; } private void formatBufferIfAtEndOfRec() { if (_currentPos != _currentSize) { return; } int dataSize = _currentSize-4; int sid = LittleEndian.getShort(_data, 0); int globalOffset = _overallStreamPos-_currentSize; _listener.processRecord(globalOffset, _recordCounter, sid, dataSize, _data); } public void close() throws IOException { _is.close(); } } private static final int DUMP_LINE_LEN = 16; private static final char[] COLUMN_SEPARATOR = " | ".toCharArray(); /** * Hex-dumps a portion of a byte array in typical format, also preserving dump-line alignment * @param globalOffset (somewhat arbitrary) used to calculate the addresses printed at the * start of each line */ static void hexDumpAligned(Writer w, byte[] data, int baseDataOffset, int dumpLen, int globalOffset) { // perhaps this code should be moved to HexDump int globalStart = globalOffset + baseDataOffset; int globalEnd = globalOffset + baseDataOffset + dumpLen; int startDelta = globalStart % DUMP_LINE_LEN; int endDelta = globalEnd % DUMP_LINE_LEN; int startLineAddr = globalStart - startDelta; int endLineAddr = globalEnd - endDelta; int lineDataOffset = baseDataOffset - startDelta; int lineAddr = startLineAddr; // output (possibly incomplete) first line if (startLineAddr == endLineAddr) { hexDumpLine(w, data, lineAddr, lineDataOffset, startDelta, endDelta); return; } hexDumpLine(w, data, lineAddr, lineDataOffset, startDelta, DUMP_LINE_LEN); // output all full lines in the middle while (true) { lineAddr += DUMP_LINE_LEN; lineDataOffset += DUMP_LINE_LEN; if (lineAddr >= endLineAddr) { break; } hexDumpLine(w, data, lineAddr, lineDataOffset, 0, DUMP_LINE_LEN); } // output (possibly incomplete) last line if (endDelta != 0) { hexDumpLine(w, data, lineAddr, lineDataOffset, 0, endDelta); } } private static void hexDumpLine(Writer w, byte[] data, int lineStartAddress, int lineDataOffset, int startDelta, int endDelta) { if (startDelta >= endDelta) { throw new IllegalArgumentException("Bad start/end delta"); } try { writeHex(w, lineStartAddress, 8); w.write(COLUMN_SEPARATOR); // raw hex data for (int i=0; i< DUMP_LINE_LEN; i++) { if (i>0) { w.write(" "); } if (i >= startDelta && i < endDelta) { writeHex(w, data[lineDataOffset+i], 2); } else { w.write(" "); } } w.write(COLUMN_SEPARATOR); // interpreted ascii for (int i=0; i< DUMP_LINE_LEN; i++) { if (i >= startDelta && i < endDelta) { w.write(getPrintableChar(data[lineDataOffset+i])); } else { w.write(" "); } } w.write(NEW_LINE_CHARS); } catch (IOException e) { throw new RuntimeException(e); } } private static char getPrintableChar(byte b) { char ib = (char) (b & 0x00FF); if (ib < 32 || ib > 126) { return '.'; } return ib; } private static void writeHex(Writer w, int value, int nDigits) throws IOException { char[] buf = new char[nDigits]; int acc = value; for(int i=nDigits-1; i>=0; i--) { int digit = acc & 0x0F; buf[i] = (char) (digit < 10 ? ('0' + digit) : ('A' + digit - 10)); acc >>= 4; } w.write(buf); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?