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