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