Пример #1
0
        /**
         * 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);
        }
Пример #2
0
 /**
  * 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);
 }
Пример #3
0
 /**
  * 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)
                            ));
 }
Пример #4
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);
        }
Пример #5
0
 /**
  * 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();
 }
Пример #6
0
        /**
         * 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);
        }
Пример #7
0
        /**
         * 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);
                    }
                }
            }
        }
Пример #8
0
        /**
         * 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);
        }
Пример #9
0
        /**
         * Writes the &quot;End of central dir record&quot;.
         * @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());
        }
Пример #10
0
        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());
        }
Пример #11
0
 /**
  * Create instance from bytes.
  * @param bytes the bytes to store as a ZipShort
  */
 public ZipShort(byte[] bytes)
 {
     value = ZipShort.getValue(bytes, 0);
 }
Пример #12
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));
        }
Пример #13
0
 /**
  * Set the header id.
  * @param headerId the header id to use
  */
 public virtual void setHeaderId(ZipShort headerId)
 {
     this.headerId = headerId;
 }
Пример #14
0
        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);
        }
Пример #15
0
        /**
         * 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;
        }
Пример #16
0
        /**
         * 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&lt;ZipArchiveEntry, NameAndComment>&gt; 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);
        }
Пример #17
0
 /**
  * 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);
 }
Пример #18
0
        /**
         * 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();
        }