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
This commit is contained in:
Nick Burch 2008-07-18 18:22:25 +00:00
parent 5d5982fb0f
commit 2591008752
5 changed files with 167 additions and 3 deletions

View File

@ -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);
}
}

View File

@ -20,6 +20,15 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; 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 { public interface XSSFModel {
/** Read from the given InputStream */ /** Read from the given InputStream */
public void readFrom(InputStream is) throws IOException; public void readFrom(InputStream is) throws IOException;

View File

@ -44,6 +44,7 @@ import org.apache.poi.ss.usermodel.Row.MissingCellPolicy;
import org.apache.poi.ss.util.SheetReferences; import org.apache.poi.ss.util.SheetReferences;
import org.apache.poi.util.POILogFactory; import org.apache.poi.util.POILogFactory;
import org.apache.poi.util.POILogger; 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.CommentsTable;
import org.apache.poi.xssf.model.SharedStringsTable; import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.model.StylesTable;
@ -125,14 +126,19 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
null, null,
OLE_OBJECT_REL_TYPE, OLE_OBJECT_REL_TYPE,
null, null,
null BinaryPart.class
); );
public static final XSSFRelation PACKEMBEDDINGS = new XSSFRelation( public static final XSSFRelation PACKEMBEDDINGS = new XSSFRelation(
null, null,
PACK_OBJECT_REL_TYPE, PACK_OBJECT_REL_TYPE,
null, 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 getRelation() { return REL; }
public String getDefaultFileName() { return DEFAULT_NAME; } 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<PackageRelationship> it = prc.iterator();
if(it.hasNext()) {
return true;
} else {
return false;
}
}
/** /**
* Returns the filename for the nth one of these, * Returns the filename for the nth one of these,
* eg /xl/comments4.xml * eg /xl/comments4.xml
@ -814,6 +840,17 @@ public class XSSFWorkbook extends POIXMLDocument implements Workbook {
} }
} }
// 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 // Now we can write out the main Workbook, with
// the correct references to the other parts // the correct references to the other parts
out = corePart.getOutputStream(); out = corePart.getOutputStream();

View File

@ -17,7 +17,14 @@
package org.apache.poi.xssf.usermodel; package org.apache.poi.xssf.usermodel;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File; 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; import junit.framework.TestCase;
@ -32,6 +39,16 @@ public class TestXSSFBugs extends TestCase {
return xml.toString(); 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 * Named ranges had the right reference, but
* the wrong sheet name * the wrong sheet name
@ -55,4 +72,38 @@ public class TestXSSFBugs extends TestCase {
assertEquals("SheetC!$A$1", wb.getNameAt(2).getReference()); assertEquals("SheetC!$A$1", wb.getNameAt(2).getReference());
assertEquals("SheetC", wb.getNameAt(2).getSheetName()); 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();
}
} }

Binary file not shown.