/************************************************************************ * * The Contents of this file are made available subject to the terms of * * - GNU Lesser General Public License Version 2.1 * * Sun Microsystems Inc., October, 2000 * * GNU Lesser General Public License Version 2.1 * ============================================= * Copyright 2000 by Sun Microsystems, Inc. * 901 San Antonio Road, Palo Alto, CA 94303, USA * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software Foundation. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * The Initial Developer of the Original Code is: Sun Microsystems, Inc. * * Copyright: 2000 by Sun Microsystems, Inc. * * All Rights Reserved. * * Contributor(s): _______________________________________ * * ************************************************************************/ // This version is adapted for Writer2LaTeX // Version 1.0 (2008-11-22) package writer2latex.xmerge; import java.util.List; import java.util.ListIterator; import java.util.LinkedList; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import java.util.zip.ZipEntry; import java.util.zip.CRC32; import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; import java.io.ByteArrayOutputStream; //import org.openoffice.xmerge.util.Debug; /** * Class used by {@link * org.openoffice.xmerge.converter.OfficeDocument * OfficeDocument} to handle reading and writing * from a ZIP file, as well as storing ZIP entries. * * @author Herbie Ong */ class OfficeZip { /** File name of the XML file in a zipped document. */ private final static String CONTENTXML = "content.xml"; private final static String STYLEXML = "styles.xml"; private final static String METAXML = "meta.xml"; private final static String SETTINGSXML = "settings.xml"; private final static String MANIFESTXML = "META-INF/manifest.xml"; private final static int BUFFERSIZE = 1024; private List entryList = null; private int contentIndex = -1; private int styleIndex = -1; private int metaIndex = -1; private int settingsIndex = -1; private int manifestIndex = -1; /** Default constructor. */ OfficeZip() { entryList = new LinkedList(); } /** *
Read each zip entry in the InputStream
object
* and store in entryList both the ZipEntry
object
* as well as the bits of each entry. Call this method before
* calling the getContentXMLBytes
method or the
* getStyleXMLBytes
method.
Keep track of the CONTENTXML and STYLEXML using * contentIndex and styleIndex, respectively.
* * @param isInputStream
object to read.
*
* @throws IOException If any I/O error occurs.
*/
void read(InputStream is) throws IOException {
ZipInputStream zis = new ZipInputStream(is);
ZipEntry ze = null;
int i = -1;
while ((ze = zis.getNextEntry()) != null) {
String name = ze.getName();
//System.out.println("Found "+name);
// Debug.log(Debug.TRACE, "reading entry: " + name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len = 0;
byte buffer[] = new byte[BUFFERSIZE];
while ((len = zis.read(buffer)) > 0) {
baos.write(buffer, 0, len);
}
byte bytes[] = baos.toByteArray();
Entry entry = new Entry(ze,bytes);
entryList.add(entry);
i++;
if (name.equalsIgnoreCase(CONTENTXML)) {
contentIndex = i;
}
else if (name.equalsIgnoreCase(STYLEXML)) {
styleIndex = i;
}
else if (name.equalsIgnoreCase(METAXML)) {
metaIndex = i;
}
else if (name.equalsIgnoreCase(SETTINGSXML)) {
settingsIndex = i;
}
else if (name.equalsIgnoreCase(MANIFESTXML)) {
manifestIndex = i;
}
}
zis.close();
}
/**
* This method returns the CONTENTXML file in a
* byte
array. It returns null if there is no
* CONTENTXML in this zip file.
*
* @return CONTENTXML in a byte
array.
*/
byte[] getContentXMLBytes() {
return getEntryBytes(contentIndex);
}
/**
* This method returns the STYLEXML file in a
* byte
array. It returns null if there is
* no STYLEXML in this zip file.
*
* @return STYLEXML in a byte
array.
*/
byte[] getStyleXMLBytes() {
return getEntryBytes(styleIndex);
}
/**
* This method returns the METAXML file in a
* byte
array. It returns null if there is
* no METAXML in this zip file.
*
* @return METAXML in a byte
array.
*/
byte[] getMetaXMLBytes() {
return getEntryBytes(metaIndex);
}
/**
* This method returns the SETTINGSXML file in a
* byte
array. It returns null if there is
* no SETTINGSXML in this zip file.
*
* @return SETTINGSXML in a byte
array.
*/
byte[] getSettingsXMLBytes() {
return getEntryBytes(settingsIndex);
}
/**
* This method returns the MANIFESTXML file in a byte
array.
* It returns null if there is no MANIFESTXML in this zip file.
*
* @return MANIFESTXML in a byte
array.
*/
byte[] getManifestXMLBytes() {
return getEntryBytes(manifestIndex);
}
/**
* This method returns the bytes corresponding to the entry named in the
* parameter.
*
* @param name The name of the entry in the Zip file to retrieve.
*
* @return The data for the named entry in a byte
array or
* null
if no entry is found.
*/
byte[] getNamedBytes(String name) {
// The list is not sorted, and sorting it for a binary search would
// invalidate the indices stored for the main files.
// Could improve performance by caching the name and index when
// iterating through the ZipFile in read().
for (int i = 0; i < entryList.size(); i++) {
Entry e = (Entry)entryList.get(i);
if (e.zipEntry.getName().equals(name)) {
return getEntryBytes(i);
}
}
return null;
}
/**
* This method sets the bytes for the named entry. It searches for a
* matching entry in the LinkedList. If no entry is found, a new one is
* created.
*
* Writing of data is defferred to setEntryBytes().
*
* @param name The name of the entry to search for.
* @param bytes The new data to write.
*/
void setNamedBytes(String name, byte[] bytes) {
for (int i = 0; i < entryList.size(); i++) {
Entry e = (Entry)entryList.get(i);
if (e.zipEntry.getName().equals(name)) {
setEntryBytes(i, bytes, name);
return;
}
}
// If we're here, no entry was found. Call setEntryBytes with an index
// of -1 to insert a new entry.
setEntryBytes(-1, bytes, name);
}
/**
* Used by the getContentXMLBytes
method and the
* getStyleXMLBytes
method to return the
* byte
array from the corresponding
* entry
in the entryList
.
*
* @param index Index of Entry
object in
* entryList
.
*
* @return byte
array associated in that
* Entry
object or null, if there is
* not such Entry
.
*/
private byte[] getEntryBytes(int index) {
byte[] bytes = null;
if (index > -1) {
Entry entry = (Entry) entryList.get(index);
bytes = entry.bytes;
}
return bytes;
}
/**
* Set or replace the byte
array for the
* CONTENTXML file.
*
* @param bytes byte
array for the
* CONTENTXML file.
*/
void setContentXMLBytes(byte bytes[]) {
contentIndex = setEntryBytes(contentIndex, bytes, CONTENTXML);
}
/**
* Set or replace the byte
array for the
* STYLEXML file.
*
* @param bytes byte
array for the
* STYLEXML file.
*/
void setStyleXMLBytes(byte bytes[]) {
styleIndex = setEntryBytes(styleIndex, bytes, STYLEXML);
}
/**
* Set or replace the byte
array for the
* METAXML file.
*
* @param bytes byte
array for the
* METAXML file.
*/
void setMetaXMLBytes(byte bytes[]) {
metaIndex = setEntryBytes(metaIndex, bytes, METAXML);
}
/**
* Set or replace the byte
array for the
* SETTINGSXML file.
*
* @param bytes byte
array for the
* SETTINGSXML file.
*/
void setSettingsXMLBytes(byte bytes[]) {
settingsIndex = setEntryBytes(settingsIndex, bytes, SETTINGSXML);
}
/**
* Set or replace the byte
array for the MANIFESTXML file.
*
* @param bytes byte
array for the MANIFESTXML file.
*/
void setManifestXMLBytes(byte bytes[]) {
manifestIndex = setEntryBytes(manifestIndex, bytes, MANIFESTXML);
}
/**
* Used by the setContentXMLBytes
method and
* the setStyleXMLBytes
to either replace an
* existing Entry
, or create a new entry in
* entryList
.
If there is an Entry
object within
* entryList that corresponds to the index, replace the
* ZipEntry
info.
Entry
to modify.
* @param bytes Entry
value.
* @param name Name of Entry
.
*
* @return Index of value added or modified in entryList
*/
private int setEntryBytes(int index, byte bytes[], String name) {
if (index > -1) {
// replace existing entry in entryList
Entry entry = (Entry) entryList.get(index);
name = entry.zipEntry.getName();
int method = entry.zipEntry.getMethod();
ZipEntry ze = createZipEntry(name, bytes, method);
entry.zipEntry = ze;
entry.bytes= bytes;
} else {
// add a new entry into entryList
ZipEntry ze = createZipEntry(name, bytes, ZipEntry.DEFLATED);
Entry entry = new Entry(ze, bytes);
entryList.add(entry);
index = entryList.size() - 1;
}
return index;
}
/**
* Write out the ZIP entries into the OutputStream
* object.
*
* @param os OutputStream
object to write ZIP.
*
* @throws IOException If any ZIP I/O error occurs.
*/
void write(OutputStream os) throws IOException {
// Debug.log(Debug.TRACE, "Writing out the following entries into zip.");
ZipOutputStream zos = new ZipOutputStream(os);
ListIterator iterator = entryList.listIterator();
while (iterator.hasNext()) {
Entry entry = (Entry) iterator.next();
ZipEntry ze = entry.zipEntry;
//String name = ze.getName();
// Debug.log(Debug.TRACE, "... " + name);
zos.putNextEntry(ze);
zos.write(entry.bytes);
}
zos.close();
}
/**
* Creates a ZipEntry
object based on the given params.
*
* @param name Name for the ZipEntry
.
* @param bytes byte
array for ZipEntry
.
* @param method ZIP method to be used for ZipEntry
.
*
* @return A ZipEntry
object.
*/
private ZipEntry createZipEntry(String name, byte bytes[], int method) {
ZipEntry ze = new ZipEntry(name);
ze.setMethod(method);
ze.setSize(bytes.length);
CRC32 crc = new CRC32();
crc.reset();
crc.update(bytes);
ze.setCrc(crc.getValue());
ze.setTime(System.currentTimeMillis());
return ze;
}
/**
* This inner class is used as a data structure for holding
* a ZipEntry
info and its corresponding bytes.
* These are stored in entryList.
*/
private class Entry {
ZipEntry zipEntry = null;
byte bytes[] = null;
Entry(ZipEntry zipEntry, byte bytes[]) {
this.zipEntry = zipEntry;
this.bytes = bytes;
}
}
}