001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018:
019: package org.apache.tools.zip;
020:
021: import java.util.Hashtable;
022: import java.util.Vector;
023: import java.util.zip.ZipException;
024:
025: /**
026: * ZipExtraField related methods
027: *
028: */
029: public class ExtraFieldUtils {
030:
031: /**
032: * Static registry of known extra fields.
033: *
034: * @since 1.1
035: */
036: private static Hashtable implementations;
037:
038: static {
039: implementations = new Hashtable();
040: register(AsiExtraField.class);
041: register(JarMarker.class);
042: }
043:
044: /**
045: * Register a ZipExtraField implementation.
046: *
047: * <p>The given class must have a no-arg constructor and implement
048: * the {@link ZipExtraField ZipExtraField interface}.</p>
049: * @param c the class to register
050: *
051: * @since 1.1
052: */
053: public static void register(Class c) {
054: try {
055: ZipExtraField ze = (ZipExtraField) c.newInstance();
056: implementations.put(ze.getHeaderId(), c);
057: } catch (ClassCastException cc) {
058: throw new RuntimeException(c
059: + " doesn\'t implement ZipExtraField");
060: } catch (InstantiationException ie) {
061: throw new RuntimeException(c + " is not a concrete class");
062: } catch (IllegalAccessException ie) {
063: throw new RuntimeException(c
064: + "\'s no-arg constructor is not public");
065: }
066: }
067:
068: /**
069: * Create an instance of the approriate ExtraField, falls back to
070: * {@link UnrecognizedExtraField UnrecognizedExtraField}.
071: * @param headerId the header identifier
072: * @return an instance of the appropiate ExtraField
073: * @exception InstantiationException if unable to instantiate the class
074: * @exception IllegalAccessException if not allowed to instatiate the class
075: * @since 1.1
076: */
077: public static ZipExtraField createExtraField(ZipShort headerId)
078: throws InstantiationException, IllegalAccessException {
079: Class c = (Class) implementations.get(headerId);
080: if (c != null) {
081: return (ZipExtraField) c.newInstance();
082: }
083: UnrecognizedExtraField u = new UnrecognizedExtraField();
084: u.setHeaderId(headerId);
085: return u;
086: }
087:
088: /**
089: * Split the array into ExtraFields and populate them with the
090: * give data.
091: * @param data an array of bytes
092: * @return an array of ExtraFields
093: * @since 1.1
094: * @throws ZipException on error
095: */
096: public static ZipExtraField[] parse(byte[] data)
097: throws ZipException {
098: Vector v = new Vector();
099: int start = 0;
100: while (start <= data.length - 4) {
101: ZipShort headerId = new ZipShort(data, start);
102: int length = (new ZipShort(data, start + 2)).getValue();
103: if (start + 4 + length > data.length) {
104: throw new ZipException("data starting at " + start
105: + " is in unknown format");
106: }
107: try {
108: ZipExtraField ze = createExtraField(headerId);
109: ze.parseFromLocalFileData(data, start + 4, length);
110: v.addElement(ze);
111: } catch (InstantiationException ie) {
112: throw new ZipException(ie.getMessage());
113: } catch (IllegalAccessException iae) {
114: throw new ZipException(iae.getMessage());
115: }
116: start += (length + 4);
117: }
118: if (start != data.length) { // array not exhausted
119: throw new ZipException("data starting at " + start
120: + " is in unknown format");
121: }
122:
123: ZipExtraField[] result = new ZipExtraField[v.size()];
124: v.copyInto(result);
125: return result;
126: }
127:
128: /**
129: * Merges the local file data fields of the given ZipExtraFields.
130: * @param data an array of ExtraFiles
131: * @return an array of bytes
132: * @since 1.1
133: */
134: public static byte[] mergeLocalFileDataData(ZipExtraField[] data) {
135: int sum = 4 * data.length;
136: for (int i = 0; i < data.length; i++) {
137: sum += data[i].getLocalFileDataLength().getValue();
138: }
139: byte[] result = new byte[sum];
140: int start = 0;
141: for (int i = 0; i < data.length; i++) {
142: System.arraycopy(data[i].getHeaderId().getBytes(), 0,
143: result, start, 2);
144: System.arraycopy(data[i].getLocalFileDataLength()
145: .getBytes(), 0, result, start + 2, 2);
146: byte[] local = data[i].getLocalFileDataData();
147: System.arraycopy(local, 0, result, start + 4, local.length);
148: start += (local.length + 4);
149: }
150: return result;
151: }
152:
153: /**
154: * Merges the central directory fields of the given ZipExtraFields.
155: * @param data an array of ExtraFields
156: * @return an array of bytes
157: * @since 1.1
158: */
159: public static byte[] mergeCentralDirectoryData(ZipExtraField[] data) {
160: int sum = 4 * data.length;
161: for (int i = 0; i < data.length; i++) {
162: sum += data[i].getCentralDirectoryLength().getValue();
163: }
164: byte[] result = new byte[sum];
165: int start = 0;
166: for (int i = 0; i < data.length; i++) {
167: System.arraycopy(data[i].getHeaderId().getBytes(), 0,
168: result, start, 2);
169: System.arraycopy(data[i].getCentralDirectoryLength()
170: .getBytes(), 0, result, start + 2, 2);
171: byte[] local = data[i].getCentralDirectoryData();
172: System.arraycopy(local, 0, result, start + 4, local.length);
173: start += (local.length + 4);
174: }
175: return result;
176: }
177: }
|