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 + -
显示快捷键?