1*04ea5bd4SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 3*04ea5bd4SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 4*04ea5bd4SAndrew Rist * or more contributor license agreements. See the NOTICE file 5*04ea5bd4SAndrew Rist * distributed with this work for additional information 6*04ea5bd4SAndrew Rist * regarding copyright ownership. The ASF licenses this file 7*04ea5bd4SAndrew Rist * to you under the Apache License, Version 2.0 (the 8*04ea5bd4SAndrew Rist * "License"); you may not use this file except in compliance 9*04ea5bd4SAndrew Rist * with the License. You may obtain a copy of the License at 10*04ea5bd4SAndrew Rist * 11*04ea5bd4SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 12*04ea5bd4SAndrew Rist * 13*04ea5bd4SAndrew Rist * Unless required by applicable law or agreed to in writing, 14*04ea5bd4SAndrew Rist * software distributed under the License is distributed on an 15*04ea5bd4SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16*04ea5bd4SAndrew Rist * KIND, either express or implied. See the License for the 17*04ea5bd4SAndrew Rist * specific language governing permissions and limitations 18*04ea5bd4SAndrew Rist * under the License. 19*04ea5bd4SAndrew Rist * 20*04ea5bd4SAndrew Rist *************************************************************/ 21*04ea5bd4SAndrew Rist 22*04ea5bd4SAndrew Rist 23cdf0e10cSrcweir 24cdf0e10cSrcweir import java.util.List; 25cdf0e10cSrcweir import java.util.ListIterator; 26cdf0e10cSrcweir import java.util.LinkedList; 27cdf0e10cSrcweir import java.util.zip.ZipInputStream; 28cdf0e10cSrcweir import java.util.zip.ZipOutputStream; 29cdf0e10cSrcweir import java.util.zip.ZipEntry; 30cdf0e10cSrcweir import java.util.zip.CRC32; 31cdf0e10cSrcweir import java.io.InputStream; 32cdf0e10cSrcweir import java.io.OutputStream; 33cdf0e10cSrcweir import java.io.IOException; 34cdf0e10cSrcweir import java.io.ByteArrayOutputStream; 35cdf0e10cSrcweir import org.openoffice.xmerge.util.Debug; 36cdf0e10cSrcweir 37cdf0e10cSrcweir /** 38cdf0e10cSrcweir * Class used by OfficeDocument to handle zip reading and writing, 39cdf0e10cSrcweir * as well as storing zip entries. 40cdf0e10cSrcweir * 41cdf0e10cSrcweir * @author Herbie Ong 42cdf0e10cSrcweir */ 43cdf0e10cSrcweir 44cdf0e10cSrcweir class OfficeZip { 45cdf0e10cSrcweir 46cdf0e10cSrcweir /** file name of the xml file in a zipped document. */ 47cdf0e10cSrcweir private final static String XMLFILE = "content.xml"; 48cdf0e10cSrcweir 49cdf0e10cSrcweir private final static int BUFFERSIZE = 1024; 50cdf0e10cSrcweir 51cdf0e10cSrcweir private List entryList = null; 52cdf0e10cSrcweir 53cdf0e10cSrcweir private int contentIndex = -1; 54cdf0e10cSrcweir 55cdf0e10cSrcweir private String filename = null; 56cdf0e10cSrcweir 57cdf0e10cSrcweir private class Entry { 58cdf0e10cSrcweir 59cdf0e10cSrcweir ZipEntry zipEntry = null; 60cdf0e10cSrcweir byte bytes[] = null; 61cdf0e10cSrcweir } 62cdf0e10cSrcweir 63cdf0e10cSrcweir /** 64cdf0e10cSrcweir * Constructor 65cdf0e10cSrcweir * 66cdf0e10cSrcweir * @param filename Full Path to Zip file to process 67cdf0e10cSrcweir * 68cdf0e10cSrcweir */ OfficeZip(String filename)69cdf0e10cSrcweir public OfficeZip(String filename) { 70cdf0e10cSrcweir this.filename = filename; 71cdf0e10cSrcweir } 72cdf0e10cSrcweir 73cdf0e10cSrcweir 74cdf0e10cSrcweir /** 75cdf0e10cSrcweir * Read each zip entry in the given InputStream object 76cdf0e10cSrcweir * and store in entryList both the ZipEntry object as well 77cdf0e10cSrcweir * as the bits of each entry. Return the bytes for the 78cdf0e10cSrcweir * entry of XMLFILE. 79cdf0e10cSrcweir * 80cdf0e10cSrcweir * @param is InputStream object to read from 81cdf0e10cSrcweir * @return byte[] byte array of XML file 82cdf0e10cSrcweir * @throws IOException if any I/O error occurs 83cdf0e10cSrcweir */ 84cdf0e10cSrcweir read(InputStream is)85cdf0e10cSrcweir byte[] read(InputStream is) throws IOException { 86cdf0e10cSrcweir 87cdf0e10cSrcweir ZipInputStream zis = new ZipInputStream(is); 88cdf0e10cSrcweir ZipEntry ze = null; 89cdf0e10cSrcweir int i = -1; 90cdf0e10cSrcweir 91cdf0e10cSrcweir entryList = new LinkedList(); 92cdf0e10cSrcweir 93cdf0e10cSrcweir while ((ze = zis.getNextEntry()) != null) { 94cdf0e10cSrcweir 95cdf0e10cSrcweir String name = ze.getName(); 96cdf0e10cSrcweir 97cdf0e10cSrcweir Entry entry = new Entry(); 98cdf0e10cSrcweir entry.zipEntry = ze; 99cdf0e10cSrcweir 100cdf0e10cSrcweir Debug.log(Debug.TRACE, "reading entry: " + name); 101cdf0e10cSrcweir 102cdf0e10cSrcweir ByteArrayOutputStream baos = new ByteArrayOutputStream(); 103cdf0e10cSrcweir 104cdf0e10cSrcweir int len = 0; 105cdf0e10cSrcweir byte bytes[] = new byte[BUFFERSIZE]; 106cdf0e10cSrcweir 107cdf0e10cSrcweir while ((len = zis.read(bytes)) > 0) { 108cdf0e10cSrcweir baos.write(bytes, 0, len); 109cdf0e10cSrcweir } 110cdf0e10cSrcweir 111cdf0e10cSrcweir entry.bytes = baos.toByteArray(); 112cdf0e10cSrcweir 113cdf0e10cSrcweir entryList.add(entry); 114cdf0e10cSrcweir 115cdf0e10cSrcweir i++; 116cdf0e10cSrcweir 117cdf0e10cSrcweir if (isContentXML(name)) { 118cdf0e10cSrcweir contentIndex = i; 119cdf0e10cSrcweir } 120cdf0e10cSrcweir } 121cdf0e10cSrcweir 122cdf0e10cSrcweir if (contentIndex == -1) { 123cdf0e10cSrcweir throw new IOException(XMLFILE + " not found."); 124cdf0e10cSrcweir } 125cdf0e10cSrcweir 126cdf0e10cSrcweir Entry contentEntry = (Entry) entryList.get(contentIndex); 127cdf0e10cSrcweir 128cdf0e10cSrcweir return contentEntry.bytes; 129cdf0e10cSrcweir } 130cdf0e10cSrcweir 131cdf0e10cSrcweir /** 132cdf0e10cSrcweir * Write out the XMLFILE as a zip into the OutputStream object. 133cdf0e10cSrcweir * 134cdf0e10cSrcweir * If a zip inputstream was previously read, then use 135cdf0e10cSrcweir * those zip contents to recreate the zip, except for XMLFILE, 136cdf0e10cSrcweir * update it using the new content from xmlBytes. 137cdf0e10cSrcweir * 138cdf0e10cSrcweir * If there was no zip inputstream previously read, write 139cdf0e10cSrcweir * XMLFILE out into the zip outputstream. 140cdf0e10cSrcweir * 141cdf0e10cSrcweir * @param os OutputStream object to write zip 142cdf0e10cSrcweir * @param xmlBytes bytes of XMLFILE 143cdf0e10cSrcweir * @throws IOException if any I/O errors occur. 144cdf0e10cSrcweir */ 145cdf0e10cSrcweir write(OutputStream os, byte xmlBytes[])146cdf0e10cSrcweir void write(OutputStream os, byte xmlBytes[]) throws IOException { 147cdf0e10cSrcweir 148cdf0e10cSrcweir ZipOutputStream zos = new ZipOutputStream(os); 149cdf0e10cSrcweir 150cdf0e10cSrcweir // if read was not invoked previously, store the bytes directly. 151cdf0e10cSrcweir if (contentIndex == -1) { 152cdf0e10cSrcweir 153cdf0e10cSrcweir Debug.log(Debug.TRACE, "Writing out " + XMLFILE + " into zip."); 154cdf0e10cSrcweir 155cdf0e10cSrcweir ZipEntry ze = new ZipEntry(XMLFILE); 156cdf0e10cSrcweir ze.setSize(xmlBytes.length); 157cdf0e10cSrcweir 158cdf0e10cSrcweir CRC32 crc = new CRC32(); 159cdf0e10cSrcweir crc.reset(); 160cdf0e10cSrcweir crc.update(xmlBytes); 161cdf0e10cSrcweir ze.setCrc(crc.getValue()); 162cdf0e10cSrcweir 163cdf0e10cSrcweir ze.setTime(System.currentTimeMillis()); 164cdf0e10cSrcweir ze.setMethod(ZipEntry.DEFLATED); 165cdf0e10cSrcweir 166cdf0e10cSrcweir zos.putNextEntry(ze); 167cdf0e10cSrcweir zos.write(xmlBytes); 168cdf0e10cSrcweir 169cdf0e10cSrcweir } else { 170cdf0e10cSrcweir 171cdf0e10cSrcweir saveEntries(zos, xmlBytes); 172cdf0e10cSrcweir } 173cdf0e10cSrcweir 174cdf0e10cSrcweir zos.close(); 175cdf0e10cSrcweir } 176cdf0e10cSrcweir 177cdf0e10cSrcweir /** 178cdf0e10cSrcweir * Used by write method if there was a zip inputstream 179cdf0e10cSrcweir * previously read. It would write out each ZipEntry of 180cdf0e10cSrcweir * the previously read zip, except for XMLFILE, it would 181cdf0e10cSrcweir * update it with new values and with the content from 182cdf0e10cSrcweir * xmlBytes. 183cdf0e10cSrcweir * 184cdf0e10cSrcweir * @param os OutputStream object to write zip 185cdf0e10cSrcweir * @param xmlBytes bytes of XMLFILE 186cdf0e10cSrcweir * @throws ZipException if any zip I/O errors occur. 187cdf0e10cSrcweir */ 188cdf0e10cSrcweir saveEntries(ZipOutputStream zos, byte xmlBytes[])189cdf0e10cSrcweir private void saveEntries(ZipOutputStream zos, byte xmlBytes[]) 190cdf0e10cSrcweir throws IOException { 191cdf0e10cSrcweir 192cdf0e10cSrcweir Debug.log(Debug.TRACE, "Writing out the following entries into zip."); 193cdf0e10cSrcweir 194cdf0e10cSrcweir ListIterator iterator = entryList.listIterator(); 195cdf0e10cSrcweir 196cdf0e10cSrcweir while (iterator.hasNext()) { 197cdf0e10cSrcweir 198cdf0e10cSrcweir Entry entry = (Entry) iterator.next(); 199cdf0e10cSrcweir ZipEntry ze = entry.zipEntry; 200cdf0e10cSrcweir 201cdf0e10cSrcweir String name = ze.getName(); 202cdf0e10cSrcweir 203cdf0e10cSrcweir Debug.log(Debug.TRACE, "... " + name); 204cdf0e10cSrcweir 205cdf0e10cSrcweir if (isContentXML(name)) { 206cdf0e10cSrcweir 207cdf0e10cSrcweir // set new values for this ZipEntry 208cdf0e10cSrcweir 209cdf0e10cSrcweir ZipEntry zipEntry = new ZipEntry(name); 210cdf0e10cSrcweir 211cdf0e10cSrcweir zipEntry.setMethod(ze.getMethod()); 212cdf0e10cSrcweir zipEntry.setSize(xmlBytes.length); 213cdf0e10cSrcweir 214cdf0e10cSrcweir CRC32 crc = new CRC32(); 215cdf0e10cSrcweir crc.reset(); 216cdf0e10cSrcweir crc.update(xmlBytes); 217cdf0e10cSrcweir zipEntry.setCrc(crc.getValue()); 218cdf0e10cSrcweir 219cdf0e10cSrcweir zipEntry.setTime(System.currentTimeMillis()); 220cdf0e10cSrcweir 221cdf0e10cSrcweir zos.putNextEntry(zipEntry); 222cdf0e10cSrcweir zos.write(xmlBytes); 223cdf0e10cSrcweir 224cdf0e10cSrcweir } else { 225cdf0e10cSrcweir 226cdf0e10cSrcweir zos.putNextEntry(ze); 227cdf0e10cSrcweir zos.write(entry.bytes); 228cdf0e10cSrcweir } 229cdf0e10cSrcweir } 230cdf0e10cSrcweir } 231cdf0e10cSrcweir isContentXML(String name)232cdf0e10cSrcweir private boolean isContentXML(String name) { 233cdf0e10cSrcweir 234cdf0e10cSrcweir String lname = name.toLowerCase(); 235cdf0e10cSrcweir return lname.equals(XMLFILE); 236cdf0e10cSrcweir } 237cdf0e10cSrcweir } 238