123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- /* ====================================================================
- Licensed to the Apache Software Foundation (ASF) under one or more
- contributor license agreements. See the NOTICE file distributed with
- this work for additional information regarding copyright ownership.
- The ASF licenses this file to You under the Apache License, Version 2.0
- (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- ==================================================================== */
-
- package org.apache.poi.poifs.filesystem;
-
- import org.apache.poi.util.*;
-
- import java.io.ByteArrayOutputStream;
- import java.io.FileNotFoundException;
- import java.io.IOException;
- import java.util.Arrays;
-
- /**
- * Represents an Ole10Native record which is wrapped around certain binary
- * files being embedded in OLE2 documents.
- *
- * @author Rainer Schwarze
- */
- public class Ole10Native {
- // (the fields as they appear in the raw record:)
- private final int totalSize; // 4 bytes, total size of record not including this field
- private short flags1; // 2 bytes, unknown, mostly [02 00]
- private final String label; // ASCIIZ, stored in this field without the terminating zero
- private final String fileName; // ASCIIZ, stored in this field without the terminating zero
- private short flags2; // 2 bytes, unknown, mostly [00 00]
- // private byte unknown1Length; // 1 byte, specifying the length of the following byte array (unknown1)
- private byte[] unknown1; // see below
- private byte[] unknown2; // 3 bytes, unknown, mostly [00 00 00]
- private final String command; // ASCIIZ, stored in this field without the terminating zero
- private final int dataSize; // 4 bytes (if space), size of following buffer
- private final byte[] dataBuffer; // varying size, the actual native data
- private short flags3; // some final flags? or zero terminators?, sometimes not there
- public static final String OLE10_NATIVE = "\u0001Ole10Native";
-
- /**
- * Creates an instance of this class from an embedded OLE Object. The OLE Object is expected
- * to include a stream "{01}Ole10Native" which contains the actual
- * data relevant for this class.
- *
- * @param poifs POI Filesystem object
- * @return Returns an instance of this class
- * @throws IOException on IO error
- * @throws Ole10NativeException on invalid or unexcepted data format
- */
- public static Ole10Native createFromEmbeddedOleObject(POIFSFileSystem poifs) throws IOException, Ole10NativeException {
- boolean plain = false;
-
- try {
- poifs.getRoot().getEntry("\u0001Ole10ItemName");
- plain = true;
- } catch (FileNotFoundException ex) {
- plain = false;
- }
-
- DocumentInputStream dis = poifs.createDocumentInputStream(OLE10_NATIVE);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- IOUtils.copy(dis, bos);
- byte[] data = bos.toByteArray();
-
- return new Ole10Native(data, 0, plain);
- }
-
- /**
- * Creates an instance and fills the fields based on the data in the given buffer.
- *
- * @param data The buffer containing the Ole10Native record
- * @param offset The start offset of the record in the buffer
- * @throws Ole10NativeException on invalid or unexcepted data format
- */
- public Ole10Native(byte[] data, int offset) throws Ole10NativeException {
- this(data, offset, false);
- }
- /**
- * Creates an instance and fills the fields based on the data in the given buffer.
- *
- * @param data The buffer containing the Ole10Native record
- * @param offset The start offset of the record in the buffer
- * @param plain Specified 'plain' format without filename
- * @throws Ole10NativeException on invalid or unexcepted data format
- */
- public Ole10Native(byte[] data, int offset, boolean plain) throws Ole10NativeException {
- int ofs = offset; // current offset, initialized to start
-
- if (data.length<offset+2) {
- throw new Ole10NativeException("data is too small");
- }
-
- totalSize = LittleEndian.getInt(data, ofs);
- ofs += LittleEndianConsts.INT_SIZE;
-
- if (plain) {
- dataBuffer = new byte[totalSize-4];
- System.arraycopy(data, 4, dataBuffer, 0, dataBuffer.length);
- dataSize = totalSize - 4;
-
- byte[] oleLabel = new byte[8];
- System.arraycopy(dataBuffer, 0, oleLabel, 0, Math.min(dataBuffer.length, 8));
- label = "ole-"+ HexDump.toHex(oleLabel);
- fileName = label;
- command = label;
- } else {
- flags1 = LittleEndian.getShort(data, ofs);
- ofs += LittleEndianConsts.SHORT_SIZE;
- int len = getStringLength(data, ofs);
- label = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
- ofs += len;
- len = getStringLength(data, ofs);
- fileName = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
- ofs += len;
- flags2 = LittleEndian.getShort(data, ofs);
- ofs += LittleEndianConsts.SHORT_SIZE;
- len = LittleEndian.getUnsignedByte(data, ofs);
- unknown1 = new byte[len];
- ofs += len;
- len = 3;
- unknown2 = new byte[len];
- ofs += len;
- len = getStringLength(data, ofs);
- command = StringUtil.getFromCompressedUnicode(data, ofs, len - 1);
- ofs += len;
-
- if (totalSize + LittleEndianConsts.INT_SIZE - ofs > LittleEndianConsts.INT_SIZE) {
- dataSize = LittleEndian.getInt(data, ofs);
- ofs += LittleEndianConsts.INT_SIZE;
-
- if (dataSize > totalSize || dataSize<0) {
- throw new Ole10NativeException("Invalid Ole10Native");
- }
-
- dataBuffer = new byte[dataSize];
- System.arraycopy(data, ofs, dataBuffer, 0, dataSize);
- ofs += dataSize;
-
- if (unknown1.length > 0) {
- flags3 = LittleEndian.getShort(data, ofs);
- ofs += LittleEndianConsts.SHORT_SIZE;
- } else {
- flags3 = 0;
- }
- } else {
- throw new Ole10NativeException("Invalid Ole10Native");
- }
- }
- }
-
- /*
- * Helper - determine length of zero terminated string (ASCIIZ).
- */
- private static int getStringLength(byte[] data, int ofs) {
- int len = 0;
- while (len+ofs<data.length && data[ofs + len] != 0) {
- len++;
- }
- len++;
- return len;
- }
-
- /**
- * Returns the value of the totalSize field - the total length of the structure
- * is totalSize + 4 (value of this field + size of this field).
- *
- * @return the totalSize
- */
- public int getTotalSize() {
- return totalSize;
- }
-
- /**
- * Returns flags1 - currently unknown - usually 0x0002.
- *
- * @return the flags1
- */
- public short getFlags1() {
- return flags1;
- }
-
- /**
- * Returns the label field - usually the name of the file (without directory) but
- * probably may be any name specified during packaging/embedding the data.
- *
- * @return the label
- */
- public String getLabel() {
- return label;
- }
-
- /**
- * Returns the fileName field - usually the name of the file being embedded
- * including the full path.
- *
- * @return the fileName
- */
- public String getFileName() {
- return fileName;
- }
-
- /**
- * Returns flags2 - currently unknown - mostly 0x0000.
- *
- * @return the flags2
- */
- public short getFlags2() {
- return flags2;
- }
-
- /**
- * Returns unknown1 field - currently unknown.
- *
- * @return the unknown1
- */
- public byte[] getUnknown1() {
- return unknown1;
- }
-
- /**
- * Returns the unknown2 field - currently being a byte[3] - mostly {0, 0, 0}.
- *
- * @return the unknown2
- */
- public byte[] getUnknown2() {
- return unknown2;
- }
-
- /**
- * Returns the command field - usually the name of the file being embedded
- * including the full path, may be a command specified during embedding the file.
- *
- * @return the command
- */
- public String getCommand() {
- return command;
- }
-
- /**
- * Returns the size of the embedded file. If the size is 0 (zero), no data has been
- * embedded. To be sure, that no data has been embedded, check whether
- * {@link #getDataBuffer()} returns <code>null</code>.
- *
- * @return the dataSize
- */
- public int getDataSize() {
- return dataSize;
- }
-
- /**
- * Returns the buffer containing the embedded file's data, or <code>null</code>
- * if no data was embedded. Note that an embedding may provide information about
- * the data, but the actual data is not included. (So label, filename etc. are
- * available, but this method returns <code>null</code>.)
- *
- * @return the dataBuffer
- */
- public byte[] getDataBuffer() {
- return dataBuffer;
- }
-
- /**
- * Returns the flags3 - currently unknown.
- *
- * @return the flags3
- */
- public short getFlags3() {
- return flags3;
- }
- }
|