applied LGPLv3 and source code formatting.
[vamsas.git] / src / org / apache / tools / zip / ExtraFieldUtils.java
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  */
18
19 package org.apache.tools.zip;
20
21 import java.util.Hashtable;
22 import java.util.Vector;
23 import java.util.zip.ZipException;
24
25 /**
26  * ZipExtraField related methods
27  * 
28  */
29 public class ExtraFieldUtils {
30
31   /**
32    * Static registry of known extra fields.
33    * 
34    * @since 1.1
35    */
36   private static Hashtable implementations;
37
38   static {
39     implementations = new Hashtable();
40     register(AsiExtraField.class);
41     register(JarMarker.class);
42   }
43
44   /**
45    * Register a ZipExtraField implementation.
46    * 
47    * <p>
48    * The given class must have a no-arg constructor and implement the
49    * {@link ZipExtraField ZipExtraField interface}.
50    * </p>
51    * 
52    * @param c
53    *          the class to register
54    * 
55    * @since 1.1
56    */
57   public static void register(Class c) {
58     try {
59       ZipExtraField ze = (ZipExtraField) c.newInstance();
60       implementations.put(ze.getHeaderId(), c);
61     } catch (ClassCastException cc) {
62       throw new RuntimeException(c + " doesn\'t implement ZipExtraField");
63     } catch (InstantiationException ie) {
64       throw new RuntimeException(c + " is not a concrete class");
65     } catch (IllegalAccessException ie) {
66       throw new RuntimeException(c + "\'s no-arg constructor is not public");
67     }
68   }
69
70   /**
71    * Create an instance of the approriate ExtraField, falls back to
72    * {@link UnrecognizedExtraField UnrecognizedExtraField}.
73    * 
74    * @param headerId
75    *          the header identifier
76    * @return an instance of the appropiate ExtraField
77    * @exception InstantiationException
78    *              if unable to instantiate the class
79    * @exception IllegalAccessException
80    *              if not allowed to instatiate the class
81    * @since 1.1
82    */
83   public static ZipExtraField createExtraField(ZipShort headerId)
84       throws InstantiationException, IllegalAccessException {
85     Class c = (Class) implementations.get(headerId);
86     if (c != null) {
87       return (ZipExtraField) c.newInstance();
88     }
89     UnrecognizedExtraField u = new UnrecognizedExtraField();
90     u.setHeaderId(headerId);
91     return u;
92   }
93
94   /**
95    * Split the array into ExtraFields and populate them with the give data.
96    * 
97    * @param data
98    *          an array of bytes
99    * @return an array of ExtraFields
100    * @since 1.1
101    * @throws ZipException
102    *           on error
103    */
104   public static ZipExtraField[] parse(byte[] data) throws ZipException {
105     Vector v = new Vector();
106     int start = 0;
107     while (start <= data.length - 4) {
108       ZipShort headerId = new ZipShort(data, start);
109       int length = (new ZipShort(data, start + 2)).getValue();
110       if (start + 4 + length > data.length) {
111         throw new ZipException("data starting at " + start
112             + " is in unknown format");
113       }
114       try {
115         ZipExtraField ze = createExtraField(headerId);
116         ze.parseFromLocalFileData(data, start + 4, length);
117         v.addElement(ze);
118       } catch (InstantiationException ie) {
119         throw new ZipException(ie.getMessage());
120       } catch (IllegalAccessException iae) {
121         throw new ZipException(iae.getMessage());
122       }
123       start += (length + 4);
124     }
125     if (start != data.length) { // array not exhausted
126       throw new ZipException("data starting at " + start
127           + " is in unknown format");
128     }
129
130     ZipExtraField[] result = new ZipExtraField[v.size()];
131     v.copyInto(result);
132     return result;
133   }
134
135   /**
136    * Merges the local file data fields of the given ZipExtraFields.
137    * 
138    * @param data
139    *          an array of ExtraFiles
140    * @return an array of bytes
141    * @since 1.1
142    */
143   public static byte[] mergeLocalFileDataData(ZipExtraField[] data) {
144     int sum = 4 * data.length;
145     for (int i = 0; i < data.length; i++) {
146       sum += data[i].getLocalFileDataLength().getValue();
147     }
148     byte[] result = new byte[sum];
149     int start = 0;
150     for (int i = 0; i < data.length; i++) {
151       System.arraycopy(data[i].getHeaderId().getBytes(), 0, result, start, 2);
152       System.arraycopy(data[i].getLocalFileDataLength().getBytes(), 0, result,
153           start + 2, 2);
154       byte[] local = data[i].getLocalFileDataData();
155       System.arraycopy(local, 0, result, start + 4, local.length);
156       start += (local.length + 4);
157     }
158     return result;
159   }
160
161   /**
162    * Merges the central directory fields of the given ZipExtraFields.
163    * 
164    * @param data
165    *          an array of ExtraFields
166    * @return an array of bytes
167    * @since 1.1
168    */
169   public static byte[] mergeCentralDirectoryData(ZipExtraField[] data) {
170     int sum = 4 * data.length;
171     for (int i = 0; i < data.length; i++) {
172       sum += data[i].getCentralDirectoryLength().getValue();
173     }
174     byte[] result = new byte[sum];
175     int start = 0;
176     for (int i = 0; i < data.length; i++) {
177       System.arraycopy(data[i].getHeaderId().getBytes(), 0, result, start, 2);
178       System.arraycopy(data[i].getCentralDirectoryLength().getBytes(), 0,
179           result, start + 2, 2);
180       byte[] local = data[i].getCentralDirectoryData();
181       System.arraycopy(local, 0, result, start + 4, local.length);
182       start += (local.length + 4);
183     }
184     return result;
185   }
186 }