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:
parent
5d5982fb0f
commit
2591008752
67
src/ooxml/java/org/apache/poi/xssf/model/BinaryPart.java
Normal file
67
src/ooxml/java/org/apache/poi/xssf/model/BinaryPart.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
BIN
src/testcases/org/apache/poi/hssf/data/45431.xlsm
Normal file
BIN
src/testcases/org/apache/poi/hssf/data/45431.xlsm
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user