1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.commons.compress.archivers.zip;
20
21 import static org.apache.commons.compress.archivers.zip.ZipConstants.DWORD;
22 import static org.apache.commons.compress.archivers.zip.ZipConstants.WORD;
23
24 import java.util.zip.ZipException;
25
26 import org.apache.commons.compress.utils.ByteUtils;
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 public class Zip64ExtendedInformationExtraField implements ZipExtraField {
45
46 static final ZipShort HEADER_ID = new ZipShort(0x0001);
47
48 private static final String LFH_MUST_HAVE_BOTH_SIZES_MSG = "Zip64 extended information must contain" + " both size values in the local file header.";
49 private ZipEightByteInteger size, compressedSize, relativeHeaderOffset;
50 private ZipLong diskStart;
51
52
53
54
55
56
57
58
59
60
61
62 private byte[] rawCentralDirectoryData;
63
64
65
66
67 public Zip64ExtendedInformationExtraField() {
68 }
69
70
71
72
73
74
75
76
77
78 public Zip64ExtendedInformationExtraField(final ZipEightByteInteger size, final ZipEightByteInteger compressedSize) {
79 this(size, compressedSize, null, null);
80 }
81
82
83
84
85
86
87
88
89
90
91
92 public Zip64ExtendedInformationExtraField(final ZipEightByteInteger size, final ZipEightByteInteger compressedSize,
93 final ZipEightByteInteger relativeHeaderOffset, final ZipLong diskStart) {
94 this.size = size;
95 this.compressedSize = compressedSize;
96 this.relativeHeaderOffset = relativeHeaderOffset;
97 this.diskStart = diskStart;
98 }
99
100 private int addSizes(final byte[] data) {
101 int off = 0;
102 if (size != null) {
103 System.arraycopy(size.getBytes(), 0, data, 0, DWORD);
104 off += DWORD;
105 }
106 if (compressedSize != null) {
107 System.arraycopy(compressedSize.getBytes(), 0, data, off, DWORD);
108 off += DWORD;
109 }
110 return off;
111 }
112
113 @Override
114 public byte[] getCentralDirectoryData() {
115 final byte[] data = new byte[getCentralDirectoryLength().getValue()];
116 int off = addSizes(data);
117 if (relativeHeaderOffset != null) {
118 System.arraycopy(relativeHeaderOffset.getBytes(), 0, data, off, DWORD);
119 off += DWORD;
120 }
121 if (diskStart != null) {
122 System.arraycopy(diskStart.getBytes(), 0, data, off, WORD);
123 off += WORD;
124 }
125 return data;
126 }
127
128 @Override
129 public ZipShort getCentralDirectoryLength() {
130 return new ZipShort((size != null ? DWORD : 0) + (compressedSize != null ? DWORD : 0) + (relativeHeaderOffset != null ? DWORD : 0)
131 + (diskStart != null ? WORD : 0));
132 }
133
134
135
136
137
138
139 public ZipEightByteInteger getCompressedSize() {
140 return compressedSize;
141 }
142
143
144
145
146
147
148 public ZipLong getDiskStartNumber() {
149 return diskStart;
150 }
151
152 @Override
153 public ZipShort getHeaderId() {
154 return HEADER_ID;
155 }
156
157 @Override
158 public byte[] getLocalFileDataData() {
159 if (size != null || compressedSize != null) {
160 if (size == null || compressedSize == null) {
161 throw new IllegalArgumentException(LFH_MUST_HAVE_BOTH_SIZES_MSG);
162 }
163 final byte[] data = new byte[2 * DWORD];
164 addSizes(data);
165 return data;
166 }
167 return ByteUtils.EMPTY_BYTE_ARRAY;
168 }
169
170 @Override
171 public ZipShort getLocalFileDataLength() {
172 return new ZipShort(size != null ? 2 * DWORD : 0);
173 }
174
175
176
177
178
179
180 public ZipEightByteInteger getRelativeHeaderOffset() {
181 return relativeHeaderOffset;
182 }
183
184
185
186
187
188
189 public ZipEightByteInteger getSize() {
190 return size;
191 }
192
193 @Override
194 public void parseFromCentralDirectoryData(final byte[] buffer, int offset, final int length) throws ZipException {
195
196 rawCentralDirectoryData = new byte[length];
197 System.arraycopy(buffer, offset, rawCentralDirectoryData, 0, length);
198
199
200
201
202
203
204
205 if (length >= 3 * DWORD + WORD) {
206 parseFromLocalFileData(buffer, offset, length);
207 } else if (length == 3 * DWORD) {
208 size = new ZipEightByteInteger(buffer, offset);
209 offset += DWORD;
210 compressedSize = new ZipEightByteInteger(buffer, offset);
211 offset += DWORD;
212 relativeHeaderOffset = new ZipEightByteInteger(buffer, offset);
213 } else if (length % DWORD == WORD) {
214 diskStart = new ZipLong(buffer, offset + length - WORD);
215 }
216 }
217
218 @Override
219 public void parseFromLocalFileData(final byte[] buffer, int offset, final int length) throws ZipException {
220 if (length == 0) {
221
222
223
224
225 return;
226 }
227 if (length < 2 * DWORD) {
228 throw new ZipException(LFH_MUST_HAVE_BOTH_SIZES_MSG);
229 }
230 size = new ZipEightByteInteger(buffer, offset);
231 offset += DWORD;
232 compressedSize = new ZipEightByteInteger(buffer, offset);
233 offset += DWORD;
234 int remaining = length - 2 * DWORD;
235 if (remaining >= DWORD) {
236 relativeHeaderOffset = new ZipEightByteInteger(buffer, offset);
237 offset += DWORD;
238 remaining -= DWORD;
239 }
240 if (remaining >= WORD) {
241 diskStart = new ZipLong(buffer, offset);
242 offset += WORD;
243 remaining -= WORD;
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261 public void reparseCentralDirectoryData(final boolean hasUncompressedSize, final boolean hasCompressedSize, final boolean hasRelativeHeaderOffset,
262 final boolean hasDiskStart) throws ZipException {
263 if (rawCentralDirectoryData != null) {
264 final int expectedLength = (hasUncompressedSize ? DWORD : 0) + (hasCompressedSize ? DWORD : 0) + (hasRelativeHeaderOffset ? DWORD : 0)
265 + (hasDiskStart ? WORD : 0);
266 if (rawCentralDirectoryData.length < expectedLength) {
267 throw new ZipException("Central directory zip64 extended" + " information extra field's length" + " doesn't match central directory"
268 + " data. Expected length " + expectedLength + " but is " + rawCentralDirectoryData.length);
269 }
270 int offset = 0;
271 if (hasUncompressedSize) {
272 size = new ZipEightByteInteger(rawCentralDirectoryData, offset);
273 offset += DWORD;
274 }
275 if (hasCompressedSize) {
276 compressedSize = new ZipEightByteInteger(rawCentralDirectoryData, offset);
277 offset += DWORD;
278 }
279 if (hasRelativeHeaderOffset) {
280 relativeHeaderOffset = new ZipEightByteInteger(rawCentralDirectoryData, offset);
281 offset += DWORD;
282 }
283 if (hasDiskStart) {
284 diskStart = new ZipLong(rawCentralDirectoryData, offset);
285 offset += WORD;
286 }
287 }
288 }
289
290
291
292
293
294
295 public void setCompressedSize(final ZipEightByteInteger compressedSize) {
296 this.compressedSize = compressedSize;
297 }
298
299
300
301
302
303
304 public void setDiskStartNumber(final ZipLong ds) {
305 diskStart = ds;
306 }
307
308
309
310
311
312
313 public void setRelativeHeaderOffset(final ZipEightByteInteger rho) {
314 relativeHeaderOffset = rho;
315 }
316
317
318
319
320
321
322 public void setSize(final ZipEightByteInteger size) {
323 this.size = size;
324 }
325 }