diff --git a/src/documentation/xdocs/poifs/fileformat.xml b/src/documentation/xdocs/poifs/fileformat.xml
index 7042b5959..5e17a0e4d 100644
--- a/src/documentation/xdocs/poifs/fileformat.xml
+++ b/src/documentation/xdocs/poifs/fileformat.xml
@@ -465,8 +465,8 @@ public int getShort (byte[] rec)
-2 |
- UK11 |
- Unknown Constant |
+ SBAT_Block_Count |
+ Number of big blocks holding the SBAT |
0x0040 |
Integer |
1 |
diff --git a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
index a345c4433..99ee6fb38 100644
--- a/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
+++ b/src/java/org/apache/poi/hssf/usermodel/HSSFWorkbook.java
@@ -64,6 +64,10 @@ import org.apache.poi.hssf.model.Sheet;
import org.apache.poi.hssf.model.Workbook;
import org.apache.poi.hssf.record.*;
import org.apache.poi.poifs.filesystem.POIFSFileSystem;
+import org.apache.poi.poifs.filesystem.Entry;
+import org.apache.poi.poifs.filesystem.DirectoryEntry;
+import org.apache.poi.poifs.filesystem.DocumentEntry;
+import org.apache.poi.poifs.filesystem.DocumentInputStream;
import org.apache.poi.util.POILogger;
import java.io.ByteArrayInputStream;
@@ -72,6 +76,7 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
+import java.util.Iterator;
/**
* High level representation of a workbook. This is the first object most users
@@ -117,6 +122,18 @@ public class HSSFWorkbook
*/
private ArrayList names;
+
+ /**
+ * holds whether or not to preserve other nodes in the POIFS. Used
+ * for macros and embedded objects.
+ */
+ private boolean preserveNodes;
+
+ /**
+ * if you do preserve the nodes, you'll need to hold the whole POIFS in
+ * memory.
+ */
+ private POIFSFileSystem poifs;
private static POILogger log = POILogFactory.getLogger(HSSFWorkbook.class);
@@ -132,18 +149,31 @@ public class HSSFWorkbook
names = new ArrayList(INITIAL_CAPACITY);
}
+ public HSSFWorkbook(POIFSFileSystem fs) throws IOException {
+ this(fs,true);
+ }
+
/**
* given a POI POIFSFileSystem object, read in its Workbook and populate the high and
* low level models. If you're reading in a workbook...start here.
*
* @param fs the POI filesystem that contains the Workbook stream.
+ * @param preserveNodes whether to preseve other nodes, such as
+ * macros. This takes more memory, so only say yes if you
+ * need to.
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @exception IOException if the stream cannot be read
*/
- public HSSFWorkbook(POIFSFileSystem fs)
+ public HSSFWorkbook(POIFSFileSystem fs, boolean preserveNodes)
throws IOException
{
+ this.preserveNodes = preserveNodes;
+
+ if (preserveNodes) {
+ this.poifs = fs;
+ }
+
sheets = new ArrayList(INITIAL_CAPACITY);
names = new ArrayList(INITIAL_CAPACITY);
@@ -175,20 +205,27 @@ public class HSSFWorkbook
}
}
+ public HSSFWorkbook(InputStream s) throws IOException {
+ this(s,true);
+ }
+
/**
* Companion to HSSFWorkbook(POIFSFileSystem), this constructs the POI filesystem around your
* inputstream.
*
* @param s the POI filesystem that contains the Workbook stream.
+ * @param preserveNodes whether to preseve other nodes, such as
+ * macros. This takes more memory, so only say yes if you
+ * need to.
* @see org.apache.poi.poifs.filesystem.POIFSFileSystem
* @see #HSSFWorkbook(POIFSFileSystem)
* @exception IOException if the stream cannot be read
*/
- public HSSFWorkbook(InputStream s)
+ public HSSFWorkbook(InputStream s, boolean preserveNodes)
throws IOException
{
- this((new POIFSFileSystem(s)));
+ this(new POIFSFileSystem(s), preserveNodes);
}
/**
@@ -515,9 +552,16 @@ public class HSSFWorkbook
{
byte[] bytes = getBytes();
POIFSFileSystem fs = new POIFSFileSystem();
-
+
fs.createDocument(new ByteArrayInputStream(bytes), "Workbook");
+
+ if (preserveNodes) {
+ List excepts = new ArrayList(1);
+ excepts.add("Workbook");
+ copyNodes(this.poifs,fs,excepts);
+ }
fs.writeFilesystem(stream);
+ //poifs.writeFilesystem(stream);
}
/**
@@ -548,12 +592,12 @@ public class HSSFWorkbook
// sheetbytes.add((( HSSFSheet ) sheets.get(k)).getSheet().getSize());
totalsize += ((HSSFSheet) sheets.get(k)).getSheet().getSize();
}
- if (totalsize < 4096)
+/* if (totalsize < 4096)
{
totalsize = 4096;
- }
- byte[] data = new byte[totalsize];
- int pos = workbook.serialize(0, data);
+ }*/
+ byte[] retval = new byte[totalsize];
+ int pos = workbook.serialize(0, retval);
// System.arraycopy(wb, 0, retval, 0, wb.length);
for (int k = 0; k < sheets.size(); k++)
@@ -562,13 +606,13 @@ public class HSSFWorkbook
// byte[] sb = (byte[])sheetbytes.get(k);
// System.arraycopy(sb, 0, retval, pos, sb.length);
pos += ((HSSFSheet) sheets.get(k)).getSheet().serialize(pos,
- data); // sb.length;
+ retval); // sb.length;
}
- for (int k = pos; k < totalsize; k++)
+/* for (int k = pos; k < totalsize; k++)
{
- data[k] = 0;
- }
- return data;
+ retval[k] = 0;
+ }*/
+ return retval;
}
public int addSSTString(String string)
@@ -677,5 +721,57 @@ public class HSSFWorkbook
removeName(index);
}
-
+
+ /**
+ * Copies nodes from one POIFS to the other minus the excepts
+ * @param source is the source POIFS to copy from
+ * @param target is the target POIFS to copy to
+ * @param excepts is a list of Strings specifying what nodes NOT to copy
+ */
+ private void copyNodes(POIFSFileSystem source, POIFSFileSystem target,
+ List excepts) throws IOException {
+ //System.err.println("CopyNodes called");
+
+ DirectoryEntry root = source.getRoot();
+ DirectoryEntry newRoot = target.getRoot();
+
+ Iterator entries = root.getEntries();
+
+ while (entries.hasNext()) {
+ Entry entry = (Entry)entries.next();
+ if (!isInList(entry.getName(), excepts)) {
+ copyNodeRecursively(entry,newRoot);
+ }
+ }
+ }
+
+ private boolean isInList(String entry, List list) {
+ for (int k = 0; k < list.size(); k++) {
+ if (((String)list.get(k)).equals(entry)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void copyNodeRecursively(Entry entry, DirectoryEntry target)
+ throws IOException {
+ //System.err.println("copyNodeRecursively called with "+entry.getName()+
+ // ","+target.getName());
+ DirectoryEntry newTarget = null;
+ if (entry.isDirectoryEntry()) {
+ newTarget = target.createDirectory(entry.getName());
+ Iterator entries = ((DirectoryEntry)entry).getEntries();
+
+ while (entries.hasNext()) {
+ copyNodeRecursively((Entry)entries.next(),newTarget);
+ }
+ } else {
+ DocumentEntry dentry = (DocumentEntry)entry;
+ DocumentInputStream dstream = new DocumentInputStream(dentry);
+ target.createDocument(dentry.getName(),dstream);
+ dstream.close();
+ }
+ }
+
}
diff --git a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
index dbd473f23..7652753f6 100644
--- a/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
+++ b/src/java/org/apache/poi/poifs/filesystem/POIFSFileSystem.java
@@ -269,6 +269,9 @@ public class POIFSFileSystem
// set the small block allocation table start block
header_block_writer.setSBATStart(sbtw.getSBAT().getStartBlock());
+ // set the small block allocation table block count
+ header_block_writer.setSBATBlockCount(sbtw.getSBATBlockCount());
+
// the header is now properly initialized. Make a list of
// writers (the header block, followed by the documents, the
// property table, the small block store, the small block
diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java
index c2c440160..cfe4729c4 100644
--- a/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java
+++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockConstants.java
@@ -70,18 +70,19 @@ import org.apache.poi.util.ShortField;
public interface HeaderBlockConstants
{
- public static final long _signature = 0xE11AB1A1E011CFD0L;
- public static final int _bat_array_offset = 0x4c;
- public static final int _max_bats_in_header =
+ public static final long _signature = 0xE11AB1A1E011CFD0L;
+ public static final int _bat_array_offset = 0x4c;
+ public static final int _max_bats_in_header =
(POIFSConstants.BIG_BLOCK_SIZE - _bat_array_offset)
/ LittleEndianConsts.INT_SIZE;
// useful offsets
- public static final int _signature_offset = 0;
- public static final int _bat_count_offset = 0x2C;
- public static final int _property_start_offset = 0x30;
- public static final int _sbat_start_offset = 0x3C;
- public static final int _xbat_start_offset = 0x44;
- public static final int _xbat_count_offset = 0x48;
+ public static final int _signature_offset = 0;
+ public static final int _bat_count_offset = 0x2C;
+ public static final int _property_start_offset = 0x30;
+ public static final int _sbat_start_offset = 0x3C;
+ public static final int _sbat_block_count_offset = 0x40;
+ public static final int _xbat_start_offset = 0x44;
+ public static final int _xbat_count_offset = 0x48;
} // end public interface HeaderBlockConstants
diff --git a/src/java/org/apache/poi/poifs/storage/HeaderBlockWriter.java b/src/java/org/apache/poi/poifs/storage/HeaderBlockWriter.java
index 9253d1c61..c0c7a512f 100644
--- a/src/java/org/apache/poi/poifs/storage/HeaderBlockWriter.java
+++ b/src/java/org/apache/poi/poifs/storage/HeaderBlockWriter.java
@@ -88,6 +88,9 @@ public class HeaderBlockWriter
// block allocation table's first big block)
private IntegerField _sbat_start;
+ // number of big blocks holding the small block allocation table
+ private IntegerField _sbat_block_count;
+
// big block index for extension to the big block allocation table
private IntegerField _xbat_start;
private IntegerField _xbat_count;
@@ -121,7 +124,8 @@ public class HeaderBlockWriter
new IntegerField(0x38, 0x1000, _data);
_sbat_start = new IntegerField(_sbat_start_offset,
POIFSConstants.END_OF_CHAIN, _data);
- new IntegerField(0x40, 1, _data);
+ _sbat_block_count = new IntegerField(_sbat_block_count_offset, 0,
+ _data);
_xbat_start = new IntegerField(_xbat_start_offset,
POIFSConstants.END_OF_CHAIN, _data);
_xbat_count = new IntegerField(_xbat_count_offset, 0, _data);
@@ -200,6 +204,17 @@ public class HeaderBlockWriter
_sbat_start.set(startBlock, _data);
}
+ /**
+ * Set count of SBAT blocks
+ *
+ * @param count the number of SBAT blocks
+ */
+
+ public void setSBATBlockCount(final int count)
+ {
+ _sbat_block_count.set(count, _data);
+ }
+
/**
* For a given number of BAT blocks, calculate how many XBAT
* blocks will be needed
diff --git a/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java b/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java
index 76b77b54b..80987d069 100644
--- a/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java
+++ b/src/java/org/apache/poi/poifs/storage/SmallBlockTableWriter.java
@@ -112,6 +112,17 @@ public class SmallBlockTableWriter
_big_block_count = SmallDocumentBlock.fill(_small_blocks);
}
+ /**
+ * Get the number of SBAT blocks
+ *
+ * @return number of SBAT big blocks
+ */
+
+ public int getSBATBlockCount()
+ {
+ return (_big_block_count + 15) / 16;
+ }
+
/**
* Get the SBAT
*
diff --git a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java
index 30a9f35c5..f52107394 100644
--- a/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java
+++ b/src/testcases/org/apache/poi/poifs/storage/TestHeaderBlockWriter.java
@@ -117,7 +117,7 @@ public class TestHeaderBlockWriter
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
- ( byte ) 0x01, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
+ ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
@@ -281,7 +281,7 @@ public class TestHeaderBlockWriter
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x67, ( byte ) 0x45, ( byte ) 0x23, ( byte ) 0x01,
- ( byte ) 0x01, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
+ ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
@@ -436,7 +436,7 @@ public class TestHeaderBlockWriter
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
- ( byte ) 0x01, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
+ ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
@@ -597,7 +597,7 @@ public class TestHeaderBlockWriter
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
- ( byte ) 0x01, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
+ ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x67, ( byte ) 0x45, ( byte ) 0x23, ( byte ) 0x01,
@@ -744,7 +744,7 @@ public class TestHeaderBlockWriter
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
- ( byte ) 0x01, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
+ ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x67, ( byte ) 0x45, ( byte ) 0x23, ( byte ) 0x01,
@@ -891,7 +891,7 @@ public class TestHeaderBlockWriter
( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x00, ( byte ) 0x10, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0xFE, ( byte ) 0xFF, ( byte ) 0xFF, ( byte ) 0xFF,
- ( byte ) 0x01, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
+ ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x67, ( byte ) 0x46, ( byte ) 0x23, ( byte ) 0x01,
( byte ) 0x02, ( byte ) 0x00, ( byte ) 0x00, ( byte ) 0x00,
( byte ) 0x67, ( byte ) 0x45, ( byte ) 0x23, ( byte ) 0x01,