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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 package org.apache.tools.zip;
21 import java.util.Hashtable;
22 import java.util.Vector;
23 import java.util.zip.ZipException;
26 * ZipExtraField related methods
29 public class ExtraFieldUtils {
32 * Static registry of known extra fields.
36 private static Hashtable implementations;
39 implementations = new Hashtable();
40 register(AsiExtraField.class);
41 register(JarMarker.class);
45 * Register a ZipExtraField implementation.
48 * The given class must have a no-arg constructor and implement the
49 * {@link ZipExtraField ZipExtraField interface}.
53 * the class to register
57 public static void register(Class c) {
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");
71 * Create an instance of the approriate ExtraField, falls back to
72 * {@link UnrecognizedExtraField UnrecognizedExtraField}.
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
83 public static ZipExtraField createExtraField(ZipShort headerId)
84 throws InstantiationException, IllegalAccessException {
85 Class c = (Class) implementations.get(headerId);
87 return (ZipExtraField) c.newInstance();
89 UnrecognizedExtraField u = new UnrecognizedExtraField();
90 u.setHeaderId(headerId);
95 * Split the array into ExtraFields and populate them with the give data.
99 * @return an array of ExtraFields
101 * @throws ZipException
104 public static ZipExtraField[] parse(byte[] data) throws ZipException {
105 Vector v = new Vector();
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");
115 ZipExtraField ze = createExtraField(headerId);
116 ze.parseFromLocalFileData(data, start + 4, length);
118 } catch (InstantiationException ie) {
119 throw new ZipException(ie.getMessage());
120 } catch (IllegalAccessException iae) {
121 throw new ZipException(iae.getMessage());
123 start += (length + 4);
125 if (start != data.length) { // array not exhausted
126 throw new ZipException("data starting at " + start
127 + " is in unknown format");
130 ZipExtraField[] result = new ZipExtraField[v.size()];
136 * Merges the local file data fields of the given ZipExtraFields.
139 * an array of ExtraFiles
140 * @return an array of bytes
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();
148 byte[] result = new byte[sum];
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,
154 byte[] local = data[i].getLocalFileDataData();
155 System.arraycopy(local, 0, result, start + 4, local.length);
156 start += (local.length + 4);
162 * Merges the central directory fields of the given ZipExtraFields.
165 * an array of ExtraFields
166 * @return an array of bytes
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();
174 byte[] result = new byte[sum];
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);