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