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