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