/** * The actual data to put into local file data - without Header-ID * or length specifier. * @return get the data */ public byte[] getLocalFileDataData() { // CRC will be added later byte[] data = new byte[getLocalFileDataLength().getValue() - WORD]; java.lang.SystemJ.arraycopy(ZipShort.getBytes(getMode()), 0, data, 0, 2); byte[] linkArray = getLinkedFile().getBytes(); // Uses default charset - see class Javadoc // CheckStyle:MagicNumber OFF java.lang.SystemJ.arraycopy(ZipLong.getBytes(linkArray.Length), 0, data, 2, WORD); java.lang.SystemJ.arraycopy(ZipShort.getBytes(getUserId()), 0, data, 6, 2); java.lang.SystemJ.arraycopy(ZipShort.getBytes(getGroupId()), 0, data, 8, 2); java.lang.SystemJ.arraycopy(linkArray, 0, data, 10, linkArray.Length); // CheckStyle:MagicNumber ON crc.reset(); crc.update(data); long checksum = crc.getValue(); byte[] result = new byte[data.Length + WORD]; java.lang.SystemJ.arraycopy(ZipLong.getBytes(checksum), 0, result, 0, WORD); java.lang.SystemJ.arraycopy(data, 0, result, WORD, data.Length); return(result); }
/** * Looks up an extra field by its header id. * * @return null if no such field exists. */ public ZipExtraField getExtraField(ZipShort type) { if (extraFields != null) { return((ZipExtraField)extraFields.get(type)); } return(null); }
/** * Encodes the set bits in a form suitable for ZIP archives. */ public byte[] encode() { return (ZipShort.getBytes((dataDescriptorFlag ? DATA_DESCRIPTOR_FLAG : 0) | (languageEncodingFlag ? UFT8_NAMES_FLAG : 0) | (encryptionFlag ? ENCRYPTION_FLAG : 0) | (strongEncryptionFlag ? STRONG_ENCRYPTION_FLAG : 0) )); }
/** * Parses the supported flags from the given archive data. * @param data local file header or a central directory entry. * @param offset offset at which the general purpose bit starts */ public static GeneralPurposeBit parse(byte[] data, int offset) { int generalPurposeFlag = ZipShort.getValue(data, offset); GeneralPurposeBit b = new GeneralPurposeBit(); b.useDataDescriptor((generalPurposeFlag & DATA_DESCRIPTOR_FLAG) != 0); b.useUTF8ForNames((generalPurposeFlag & UFT8_NAMES_FLAG) != 0); b.useStrongEncryption((generalPurposeFlag & STRONG_ENCRYPTION_FLAG) != 0); b.useEncryption((generalPurposeFlag & ENCRYPTION_FLAG) != 0); return(b); }
/** * Remove an extra field. * @param type the type of extra field to remove */ public void removeExtraField(ZipShort type) { if (extraFields == null) { throw new java.util.NoSuchElementException(); } if (extraFields.remove(type) == null) { throw new java.util.NoSuchElementException(); } setExtra(); }
/** * Create an instance of the approriate ExtraField, falls back to * {@link UnrecognizedExtraField UnrecognizedExtraField}. * @param headerId the header identifier * @return an instance of the appropiate ExtraField * @exception InstantiationException if unable to instantiate the class * @exception IllegalAccessException if not allowed to instatiate the class */ public static ZipExtraField createExtraField(ZipShort headerId) //throws InstantiationException, IllegalAccessException { Type c = (Type)implementations.get(headerId); if (c != null) { return((ZipExtraField)Activator.CreateInstance(c)); } UnrecognizedExtraField u = new UnrecognizedExtraField(); u.setHeaderId(headerId); return(u); }
/** * Walks through all recorded entries and adds the data available * from the local file header. * * <p>Also records the offsets for the data to read from the * entries.</p> */ private void resolveLocalFileHeaderData(java.util.Map <ZipArchiveEntry, IAC_NameAndComment> entriesWithoutUTF8Flag) //throws IOException { java.util.Enumeration <ZipArchiveEntry> e = getEntries(); while (e.hasMoreElements()) { ZipArchiveEntry ze = e.nextElement(); IAC_OffsetEntry offsetEntry = entries.get(ze); long offset = offsetEntry.headerOffset; archive.seek(offset + LFH_OFFSET_FOR_FILENAME_LENGTH); byte[] b = new byte[SHORT]; archive.readFully(b); int fileNameLen = ZipShort.getValue(b); archive.readFully(b); int extraFieldLen = ZipShort.getValue(b); int lenToSkip = fileNameLen; while (lenToSkip > 0) { int skipped = archive.skipBytes(lenToSkip); if (skipped <= 0) { throw new java.lang.RuntimeException("failed to skip file name in" + " local file header"); } lenToSkip -= skipped; } byte[] localExtraData = new byte[extraFieldLen]; archive.readFully(localExtraData); ze.setExtra(localExtraData); /*dataOffsets.put(ze, * new Long(offset + LFH_OFFSET_FOR_FILENAME_LENGTH + SHORT + SHORT + fileNameLen + extraFieldLen)); */ offsetEntry.dataOffset = offset + LFH_OFFSET_FOR_FILENAME_LENGTH + SHORT + SHORT + fileNameLen + extraFieldLen; if (entriesWithoutUTF8Flag.containsKey(ze)) { String orig = ze.getName(); IAC_NameAndComment nc = (IAC_NameAndComment)entriesWithoutUTF8Flag.get(ze); ZipUtil.setNameAndCommentFromExtraFields(ze, nc.name, nc.comment); if (!orig.equals(ze.getName())) { nameMap.remove(orig); nameMap.put(ze.getName(), ze); } } } }
/** * Populate data from this array as if it was in local file data. * @param data an array of bytes * @param offset the start offset * @param length the number of bytes in the array from offset * @throws ZipException on error */ public void parseFromLocalFileData(byte[] data, int offset, int length) //throws ZipException { long givenChecksum = ZipLong.getValue(data, offset); byte[] tmp = new byte[length - WORD]; java.lang.SystemJ.arraycopy(data, offset + WORD, tmp, 0, length - WORD); crc.reset(); crc.update(tmp); long realChecksum = crc.getValue(); if (givenChecksum != realChecksum) { throw new java.util.zip.ZipException("bad CRC checksum " + java.lang.Long.toHexString(givenChecksum) + " instead of " + java.lang.Long.toHexString(realChecksum)); } int newMode = ZipShort.getValue(tmp, 0); // CheckStyle:MagicNumber OFF byte[] linkArray = new byte[(int)ZipLong.getValue(tmp, 2)]; uid = ZipShort.getValue(tmp, 6); gid = ZipShort.getValue(tmp, 8); if (linkArray.Length == 0) { link = ""; } else { java.lang.SystemJ.arraycopy(tmp, 10, linkArray, 0, linkArray.Length); link = System.Text.ASCIIEncoding.ASCII.GetString(linkArray); // Uses default charset - see class Javadoc } // CheckStyle:MagicNumber ON setDirectory((newMode & UnixStat.DIR_FLAG) != 0); setMode(newMode); }
/** * Writes the "End of central dir record". * @throws IOException on error */ protected void writeCentralDirectoryEnd() //throws IOException { writeOut(EOCD_SIG); // disk numbers writeOut(ZERO); writeOut(ZERO); // number of entries byte[] num = ZipShort.getBytes(entries.size()); writeOut(num); writeOut(num); // length and location of CD writeOut(ZipLong.getBytes(cdLength)); writeOut(ZipLong.getBytes(cdOffset)); // ZIP file comment java.nio.ByteBuffer data = this.zipEncoding.encode(comment); writeOut(ZipShort.getBytes(data.limit())); writeOut((byte[])data.array(), data.arrayOffset(), data.limit()); }
private void writeVersionNeededToExtractAndGeneralPurposeBits(int zipMethod, bool utfFallback) //throws IOException { // CheckStyle:MagicNumber OFF int versionNeededToExtract = 10; GeneralPurposeBit b = new GeneralPurposeBit(); b.useUTF8ForNames(useUTF8Flag || utfFallback); if (zipMethod == DEFLATED && raf == null) { // requires version 2 as we are going to store length info // in the data descriptor versionNeededToExtract = 20; b.useDataDescriptor(true); } // CheckStyle:MagicNumber ON // version needed to extract writeOut(ZipShort.getBytes(versionNeededToExtract)); // general purpose bit flag writeOut(b.encode()); }
/** * Create instance from bytes. * @param bytes the bytes to store as a ZipShort */ public ZipShort(byte[] bytes) { value = ZipShort.getValue(bytes, 0); }
/** * Split the array into ExtraFields and populate them with the * given data. * @param data an array of bytes * @param local whether data originates from the local file data * or the central directory * @param onUnparseableData what to do if the extra field data * cannot be parsed. * @return an array of ExtraFields * @throws ZipException on error * * @since Apache Commons Compress 1.1 */ public static ZipExtraField[] parse(byte[] data, bool local, UnparseableExtraField onUnparseableData) //throws ZipException { java.util.List <ZipExtraField> v = new java.util.ArrayList <ZipExtraField>(); int start = 0; LOOP: while (start <= data.Length - WORD) { ZipShort headerId = new ZipShort(data, start); int length = (new ZipShort(data, start + 2)).getValue(); if (start + WORD + length > data.Length) { switch (onUnparseableData.getKey()) { case UnparseableExtraField.THROW_KEY: throw new java.util.zip.ZipException("bad extra field starting at " + start + ". Block length of " + length + " bytes exceeds remaining" + " data of " + (data.Length - start - WORD) + " bytes."); case UnparseableExtraField.READ_KEY: UnparseableExtraFieldData field = new UnparseableExtraFieldData(); if (local) { field.parseFromLocalFileData(data, start, data.Length - start); } else { field.parseFromCentralDirectoryData(data, start, data.Length - start); } v.add(field); #region case UnparseableExtraField.SKIP_KEY: goto LOOP; #endregion //$FALL-THROUGH$ case UnparseableExtraField.SKIP_KEY: // since we cannot parse the data we must assume // the extra field consumes the whole rest of the // available data goto LOOP; // Basties Note: Bad coder!!! default: throw new java.util.zip.ZipException("unknown UnparseableExtraField key: " + onUnparseableData.getKey()); } } try { ZipExtraField ze = createExtraField(headerId); if (local) { ze.parseFromLocalFileData(data, start + WORD, length); } else { ze.parseFromCentralDirectoryData(data, start + WORD, length); } v.add(ze); } catch (MethodAccessException iae) { throw new java.util.zip.ZipException(iae.getMessage()); } catch (MemberAccessException ie) { throw new java.util.zip.ZipException(ie.getMessage()); } start += (length + WORD); } ZipExtraField[] result = new ZipExtraField[v.size()]; return((ZipExtraField[])v.toArray(result)); }
/** * Set the header id. * @param headerId the header id to use */ public virtual void setHeaderId(ZipShort headerId) { this.headerId = headerId; }
public ZipArchiveEntry getNextZipEntry() //throws IOException { if (closed || hitCentralDirectory) { return(null); } if (current != null) { closeEntry(); } byte[] lfh = new byte[LFH_LEN]; try { readFully(lfh); } catch (java.io.EOFException) { return(null); } ZipLong sig = new ZipLong(lfh); if (sig.equals(ZipLong.CFH_SIG)) { hitCentralDirectory = true; return(null); } if (!sig.equals(ZipLong.LFH_SIG)) { return(null); } int off = WORD; current = new ZipArchiveEntry(); int versionMadeBy = ZipShort.getValue(lfh, off); off += SHORT; current.setPlatform((versionMadeBy >> ZipFile.BYTE_SHIFT) & ZipFile.NIBLET_MASK); GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(lfh, off); bool hasUTF8Flag = gpFlag.usesUTF8ForNames(); ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; hasDataDescriptor = gpFlag.usesDataDescriptor(); current.setGeneralPurposeBit(gpFlag); off += SHORT; current.setMethod(ZipShort.getValue(lfh, off)); off += SHORT; long time = ZipUtil.dosToJavaTime(ZipLong.getValue(lfh, off)); current.setTime(time); off += WORD; if (!hasDataDescriptor) { current.setCrc(ZipLong.getValue(lfh, off)); off += WORD; current.setCompressedSize(ZipLong.getValue(lfh, off)); off += WORD; current.setSize(ZipLong.getValue(lfh, off)); off += WORD; } else { off += 3 * WORD; } int fileNameLen = ZipShort.getValue(lfh, off); off += SHORT; int extraLen = ZipShort.getValue(lfh, off); off += SHORT; byte[] fileName = new byte[fileNameLen]; readFully(fileName); current.setName(entryEncoding.decode(fileName)); byte[] extraData = new byte[extraLen]; readFully(extraData); current.setExtra(extraData); if (!hasUTF8Flag && useUnicodeExtraFields) { ZipUtil.setNameAndCommentFromExtraFields(current, fileName, null); } return(current); }
/** * Writes the local file header entry * @param ze the entry to write * @throws IOException on error */ protected void writeLocalFileHeader(ZipArchiveEntry ze) //throws IOException { bool encodable = zipEncoding.canEncode(ze.getName()); ZipEncoding entryEncoding; if (!encodable && fallbackToUTF8) { entryEncoding = ZipEncodingHelper.UTF8_ZIP_ENCODING; } else { entryEncoding = zipEncoding; } java.nio.ByteBuffer name = entryEncoding.encode(ze.getName()); if (createUnicodeExtraFields != UnicodeExtraFieldPolicy.NEVER) { if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS || !encodable) { ze.addExtraField(new UnicodePathExtraField(ze.getName(), (byte[])name.array(), name.arrayOffset(), name.limit())); } String comm = ze.getComment(); if (comm != null && !"".equals(comm)) { bool commentEncodable = this.zipEncoding.canEncode(comm); if (createUnicodeExtraFields == UnicodeExtraFieldPolicy.ALWAYS || !commentEncodable) { java.nio.ByteBuffer commentB = entryEncoding.encode(comm); ze.addExtraField(new UnicodeCommentExtraField(comm, (byte[])commentB.array(), commentB.arrayOffset(), commentB.limit()) ); } } } offsets.put(ze, ZipLong.getBytes(written)); writeOut(LFH_SIG); written += WORD; //store method in local variable to prevent multiple method calls int zipMethod = ze.getMethod(); writeVersionNeededToExtractAndGeneralPurposeBits(zipMethod, !encodable && fallbackToUTF8); written += WORD; // compression method writeOut(ZipShort.getBytes(zipMethod)); written += SHORT; // last mod. time and date writeOut(ZipUtil.toDosTime(ze.getTime())); written += WORD; // CRC // compressed length // uncompressed length localDataStart = written; if (zipMethod == DEFLATED || raf != null) { writeOut(LZERO); writeOut(LZERO); writeOut(LZERO); } else { writeOut(ZipLong.getBytes(ze.getCrc())); writeOut(ZipLong.getBytes(ze.getSize())); writeOut(ZipLong.getBytes(ze.getSize())); } // CheckStyle:MagicNumber OFF written += 12; // CheckStyle:MagicNumber ON // file name length writeOut(ZipShort.getBytes(name.limit())); written += SHORT; // extra field length byte[] extra = ze.getLocalFileDataExtra(); writeOut(ZipShort.getBytes(extra.Length)); written += SHORT; // file name writeOut((byte[])name.array(), name.arrayOffset(), name.limit()); written += name.limit(); // extra field writeOut(extra); written += extra.Length; dataStart = written; }
/** * Reads the central directory of the given archive and populates * the internal tables with ZipArchiveEntry instances. * * <p>The ZipArchiveEntrys will know all data that can be obtained from * the central directory alone, but not the data that requires the * local file header or additional data to be read.</p> * * @return a Map<ZipArchiveEntry, NameAndComment>> of * zipentries that didn't have the language encoding flag set when * read. */ private java.util.Map <ZipArchiveEntry, IAC_NameAndComment> populateFromCentralDirectory() //throws IOException { java.util.HashMap <ZipArchiveEntry, IAC_NameAndComment> noUTF8Flag = new java.util.HashMap <ZipArchiveEntry, IAC_NameAndComment>(); positionAtCentralDirectory(); byte[] cfh = new byte[CFH_LEN]; byte[] signatureBytes = new byte[WORD]; archive.readFully(signatureBytes); long sig = ZipLong.getValue(signatureBytes); long cfhSig = ZipLong.getValue(ZipArchiveOutputStream.CFH_SIG); if (sig != cfhSig && startsWithLocalFileHeader()) { throw new java.io.IOException("central directory is empty, can't expand" + " corrupt archive."); } while (sig == cfhSig) { archive.readFully(cfh); int off = 0; ZipArchiveEntry ze = new ZipArchiveEntry(); int versionMadeBy = ZipShort.getValue(cfh, off); off += SHORT; ze.setPlatform((versionMadeBy >> BYTE_SHIFT) & NIBLET_MASK); off += SHORT; // skip version info GeneralPurposeBit gpFlag = GeneralPurposeBit.parse(cfh, off); bool hasUTF8Flag = gpFlag.usesUTF8ForNames(); ZipEncoding entryEncoding = hasUTF8Flag ? ZipEncodingHelper.UTF8_ZIP_ENCODING : zipEncoding; ze.setGeneralPurposeBit(gpFlag); off += SHORT; ze.setMethod(ZipShort.getValue(cfh, off)); off += SHORT; // FIXME this is actually not very cpu cycles friendly as we are converting from // dos to java while the underlying Sun implementation will convert // from java to dos time for internal storage... long time = ZipUtil.dosToJavaTime(ZipLong.getValue(cfh, off)); ze.setTime(time); off += WORD; ze.setCrc(ZipLong.getValue(cfh, off)); off += WORD; ze.setCompressedSize(ZipLong.getValue(cfh, off)); off += WORD; ze.setSize(ZipLong.getValue(cfh, off)); off += WORD; int fileNameLen = ZipShort.getValue(cfh, off); off += SHORT; int extraLen = ZipShort.getValue(cfh, off); off += SHORT; int commentLen = ZipShort.getValue(cfh, off); off += SHORT; off += SHORT; // disk number ze.setInternalAttributes(ZipShort.getValue(cfh, off)); off += SHORT; ze.setExternalAttributes(ZipLong.getValue(cfh, off)); off += WORD; byte[] fileName = new byte[fileNameLen]; archive.readFully(fileName); ze.setName(entryEncoding.decode(fileName)); // LFH offset, IAC_OffsetEntry offset = new IAC_OffsetEntry(); offset.headerOffset = ZipLong.getValue(cfh, off); // data offset will be filled later entries.put(ze, offset); nameMap.put(ze.getName(), ze); byte[] cdExtraData = new byte[extraLen]; archive.readFully(cdExtraData); ze.setCentralDirectoryExtra(cdExtraData); byte[] comment = new byte[commentLen]; archive.readFully(comment); ze.setComment(entryEncoding.decode(comment)); archive.readFully(signatureBytes); sig = ZipLong.getValue(signatureBytes); if (!hasUTF8Flag && useUnicodeExtraFields) { noUTF8Flag.put(ze, new IAC_NameAndComment(fileName, comment)); } } return(noUTF8Flag); }
/** * Create instance from the two bytes starting at offset. * @param bytes the bytes to store as a ZipShort * @param offset the offset to start */ public ZipShort(byte[] bytes, int offset) { value = ZipShort.getValue(bytes, offset); }
/** * Writes the central file header entry. * @param ze the entry to write * @throws IOException on error */ protected void writeCentralFileHeader(ZipArchiveEntry ze) //throws IOException { writeOut(CFH_SIG); written += WORD; // version made by // CheckStyle:MagicNumber OFF writeOut(ZipShort.getBytes((ze.getPlatform() << 8) | 20)); written += SHORT; int zipMethod = ze.getMethod(); bool encodable = zipEncoding.canEncode(ze.getName()); writeVersionNeededToExtractAndGeneralPurposeBits(zipMethod, !encodable && fallbackToUTF8); written += WORD; // compression method writeOut(ZipShort.getBytes(zipMethod)); written += SHORT; // last mod. time and date writeOut(ZipUtil.toDosTime(ze.getTime())); written += WORD; // CRC // compressed length // uncompressed length writeOut(ZipLong.getBytes(ze.getCrc())); writeOut(ZipLong.getBytes(ze.getCompressedSize())); writeOut(ZipLong.getBytes(ze.getSize())); // CheckStyle:MagicNumber OFF written += 12; // CheckStyle:MagicNumber ON // file name length ZipEncoding entryEncoding; if (!encodable && fallbackToUTF8) { entryEncoding = ZipEncodingHelper.UTF8_ZIP_ENCODING; } else { entryEncoding = zipEncoding; } java.nio.ByteBuffer name = entryEncoding.encode(ze.getName()); writeOut(ZipShort.getBytes(name.limit())); written += SHORT; // extra field length byte[] extra = ze.getCentralDirectoryExtra(); writeOut(ZipShort.getBytes(extra.Length)); written += SHORT; // file comment length String comm = ze.getComment(); if (comm == null) { comm = ""; } java.nio.ByteBuffer commentB = entryEncoding.encode(comm); writeOut(ZipShort.getBytes(commentB.limit())); written += SHORT; // disk number start writeOut(ZERO); written += SHORT; // internal file attributes writeOut(ZipShort.getBytes(ze.getInternalAttributes())); written += SHORT; // external file attributes writeOut(ZipLong.getBytes(ze.getExternalAttributes())); written += WORD; // relative offset of LFH writeOut((byte[])offsets.get(ze)); written += WORD; // file name writeOut((byte[])name.array(), name.arrayOffset(), name.limit()); written += name.limit(); // extra field writeOut(extra); written += extra.Length; // file comment writeOut((byte[])commentB.array(), commentB.arrayOffset(), commentB.limit()); written += commentB.limit(); }