From: Nick Burch Date: Fri, 18 Jul 2008 18:22:25 +0000 (+0000) Subject: Partial support for .xlsm files (bug #45431), but still not quite there as they seem... X-Git-Tag: REL_3_5_BETA2~53 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=c7f924e3773c18640262ba073335f5cf1df2548b;p=poi.git Partial support for .xlsm files (bug #45431), but still not quite there as they seem to have some hidden reference we don't know about to update git-svn-id: https://svn.apache.org/repos/asf/poi/branches/ooxml@677990 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/src/ooxml/java/org/apache/poi/xssf/model/BinaryPart.java b/src/ooxml/java/org/apache/poi/xssf/model/BinaryPart.java new file mode 100644 index 0000000000..9582b8a61d --- /dev/null +++ b/src/ooxml/java/org/apache/poi/xssf/model/BinaryPart.java @@ -0,0 +1,67 @@ +/* ==================================================================== + 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.xssf.model; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * An implementation of XSSFModel for binary parts of + * the file, eg images or vba macros + */ +public class BinaryPart implements XSSFModel { + private byte[] data; + + public BinaryPart(InputStream in) throws IOException { + readFrom(in); + } + + /** + * Fetch the contents of the binary part + */ + public byte[] getContents() { + return data; + } + /** + * Changes the contents of the binary part + */ + public void setContents(byte[] data) { + this.data = data; + } + + /** + * Reads the contents of the binary part in. + */ + public void readFrom(InputStream is) throws IOException { + int read = 0; + byte[] buffer = new byte[4096]; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + while( (read = is.read(buffer)) != -1 ) { + if(read > 0) { + baos.write(buffer, 0, read); + } + } + data = baos.toByteArray(); + } + + public void writeTo(OutputStream out) throws IOException { + out.write(data); + } +} diff --git a/src/ooxml/java/org/apache/poi/xssf/model/XSSFModel.java b/src/ooxml/java/org/apache/poi/xssf/model/XSSFModel.java index eedf391179..03d08c030f 100644 --- a/src/ooxml/java/org/apache/poi/xssf/model/XSSFModel.java +++ b/src/ooxml/java/org/apache/poi/xssf/model/XSSFModel.java @@ -20,6 +20,15 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import org.apache.poi.xssf.usermodel.XSSFWorkbook.XSSFRelation; + +/** + * Common interface for XSSF models, which deal with + * parts of the xssf file. + * These should also implement a constructor of + * (InputStream is), so they can be used with + * {@link XSSFRelation} + */ public interface XSSFModel { /** Read from the given InputStream */ public void readFrom(InputStream is) throws IOException; diff --git a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java index 719fc63a1d..c98135d585 100644 --- a/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java +++ b/src/ooxml/java/org/apache/poi/xssf/usermodel/XSSFWorkbook.java @@ -44,6 +44,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy; import org.apache.poi.ss.util.SheetReferences; import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogger; +import org.apache.poi.xssf.model.BinaryPart; import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.StylesTable; @@ -125,14 +126,19 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { null, OLE_OBJECT_REL_TYPE, null, - null + BinaryPart.class ); - public static final XSSFRelation PACKEMBEDDINGS = new XSSFRelation( null, PACK_OBJECT_REL_TYPE, null, - null + BinaryPart.class + ); + public static final XSSFRelation VBA_MACROS = new XSSFRelation( + "application/vnd.ms-office.vbaProject", + "http://schemas.microsoft.com/office/2006/relationships/vbaProject", + "/xl/vbaProject.bin", + BinaryPart.class ); @@ -151,6 +157,26 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { public String getRelation() { return REL; } public String getDefaultFileName() { return DEFAULT_NAME; } + /** + * Does one of these exist for the given core + * package part? + */ + public boolean exists(PackagePart corePart) throws IOException, InvalidFormatException { + if(corePart == null) { + // new file, can't exist + return false; + } + + PackageRelationshipCollection prc = + corePart.getRelationshipsByType(REL); + Iterator it = prc.iterator(); + if(it.hasNext()) { + return true; + } else { + return false; + } + } + /** * Returns the filename for the nth one of these, * eg /xl/comments4.xml @@ -813,6 +839,17 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook { workbook.setDefinedNames(null); } } + + // VBA Macros + if(VBA_MACROS.exists( getCorePart() )) { + // Copy over + try { + XSSFModel vba = VBA_MACROS.load(getCorePart()); + VBA_MACROS.save(vba, corePart); + } catch(Exception e) { + throw new RuntimeException("Unable to copy vba macros over", e); + } + } // Now we can write out the main Workbook, with // the correct references to the other parts diff --git a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java index e3d6745734..642b723a5a 100644 --- a/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java +++ b/src/ooxml/testcases/org/apache/poi/xssf/usermodel/TestXSSFBugs.java @@ -17,7 +17,14 @@ package org.apache.poi.xssf.usermodel; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileOutputStream; + +import org.openxml4j.opc.Package; +import org.openxml4j.opc.PackagePart; +import org.openxml4j.opc.PackagingURIHelper; import junit.framework.TestCase; @@ -32,6 +39,16 @@ public class TestXSSFBugs extends TestCase { return xml.toString(); } + private Package saveAndOpen(XSSFWorkbook wb) throws Exception { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + wb.write(baos); + ByteArrayInputStream inp = new ByteArrayInputStream( + baos.toByteArray() + ); + Package pkg = Package.open(inp); + return pkg; + } + /** * Named ranges had the right reference, but * the wrong sheet name @@ -55,4 +72,38 @@ public class TestXSSFBugs extends TestCase { assertEquals("SheetC!$A$1", wb.getNameAt(2).getReference()); assertEquals("SheetC", wb.getNameAt(2).getSheetName()); } + + /** + * We should carry vba macros over after save + */ + public void test45431() throws Exception { + Package pkg = Package.open(getFilePath("45431.xlsm")); + XSSFWorkbook wb = new XSSFWorkbook(pkg); + + PackagePart vba = pkg.getPart( + PackagingURIHelper.createPartName("/xl/vbaProject.bin") + ); + assertNotNull(vba); + + // Save and re-open, is still there + Package nPkg = saveAndOpen(wb); + XSSFWorkbook nwb = new XSSFWorkbook(nPkg); + vba = nPkg.getPart( + PackagingURIHelper.createPartName("/xl/vbaProject.bin") + ); + assertNotNull(vba); + + // And again, just to be sure + nPkg = saveAndOpen(nwb); + nwb = new XSSFWorkbook(nPkg); + vba = nPkg.getPart( + PackagingURIHelper.createPartName("/xl/vbaProject.bin") + ); + assertNotNull(vba); + + // For testing with excel +// FileOutputStream fout = new FileOutputStream("/tmp/foo.xlsm"); +// nwb.write(fout); +// fout.close(); + } } diff --git a/src/testcases/org/apache/poi/hssf/data/45431.xlsm b/src/testcases/org/apache/poi/hssf/data/45431.xlsm new file mode 100644 index 0000000000..fabbd0df39 Binary files /dev/null and b/src/testcases/org/apache/poi/hssf/data/45431.xlsm differ