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 }