Example #1
0
        private void init() //throws IOException
        {
            if (null == inJ)
            {
                throw new java.io.IOException("No InputStream");
            }
            if (inJ.available() == 0)
            {
                throw new java.io.IOException("Empty InputStream");
            }
            checkMagicChar('B', "first");
            checkMagicChar('Z', "second");
            checkMagicChar('h', "third");

            int blockSize = this.inJ.read();

            if ((blockSize < '1') || (blockSize > '9'))
            {
                throw new java.io.IOException("Stream is not BZip2 formatted: illegal " + "blocksize " + (char)blockSize);
            }

            this.blockSize100k = blockSize - '0';

            initBlock();
            setupBlock();
        }
        /**
         * Returns the next AR entry in this stream.
         *
         * @return the next AR entry.
         * @throws IOException
         *             if the entry could not be read
         */
        public ArArchiveEntry getNextArEntry()   // throws IOException
        {
            if (currentEntry != null)
            {
                long entryEnd = entryOffset + currentEntry.getLength();
                while (offset < entryEnd)
                {
                    int x = read();
                    if (x == -1)
                    {
                        // hit EOF before previous entry was complete
                        // TODO: throw an exception instead?
                        return(null);
                    }
                }
                currentEntry = null;
            }

            if (offset == 0)
            {
                byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.HEADER);
                byte[] realized = new byte[expected.Length];
                int    readJ    = read(realized);
                if (readJ != expected.Length)
                {
                    throw new java.io.IOException("failed to read header. Occured at byte: " + getBytesRead());
                }
                for (int i = 0; i < expected.Length; i++)
                {
                    if (expected[i] != realized[i])
                    {
                        throw new java.io.IOException("invalid header " + ArchiveUtils.toAsciiString(realized));
                    }
                }
            }

            if (offset % 2 != 0)
            {
                if (read() < 0)
                {
                    // hit eof
                    return(null);
                }
            }

            if (input.available() == 0)
            {
                return(null);
            }

            byte[] name         = new byte[16];
            byte[] lastmodified = new byte[12];
            byte[] userid       = new byte[6];
            byte[] groupid      = new byte[6];
            byte[] filemode     = new byte[8];
            byte[] length       = new byte[10];

            read(name);
            read(lastmodified);
            read(userid);
            read(groupid);
            read(filemode);
            read(length);

            {
                byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.TRAILER);
                byte[] realized = new byte[expected.Length];
                int    readJ    = read(realized);
                if (readJ != expected.Length)
                {
                    throw new java.io.IOException("failed to read entry trailer. Occured at byte: " + getBytesRead());
                }
                for (int i = 0; i < expected.Length; i++)
                {
                    if (expected[i] != realized[i])
                    {
                        throw new java.io.IOException("invalid entry trailer. not read the content? Occured at byte: " + getBytesRead());
                    }
                }
            }

            entryOffset = offset;

            //        GNU ar stores multiple extended filenames in the data section of a file with the name "//", this record is referred to by future headers. A header references an extended filename by storing a "/" followed by a decimal offset to the start of the filename in the extended filename data section. The format of this "//" file itself is simply a list of the long filenames, each separated by one or more LF characters. Note that the decimal offsets are number of characters, not line or string number within the "//" file.
            //
            //        GNU ar uses a '/' to mark the end of the filename; this allows for the use of spaces without the use of an extended filename.

            // entry name is stored as ASCII string
            String temp = ArchiveUtils.toAsciiString(name).trim();

            if (temp.equals("//"))           // GNU extended filenames entry
            {
                int bufflen = asInt(length); // Assume length will fit in an int
                namebuffer = new byte[bufflen];
                int readJ = read(namebuffer, 0, bufflen);
                if (readJ != bufflen)
                {
                    throw new java.io.IOException("Failed to read complete // record: expected=" + bufflen + " read=" + readJ);
                }
                currentEntry = new ArArchiveEntry(temp, bufflen);
                return(getNextArEntry());
            }
            else if (temp.EndsWith("/"))     // GNU terminator
            {
                temp = temp.substring(0, temp.length() - 1);
            }
            else if (temp.matches("^/\\d+"))                                 // GNU long filename ref.
            {
                int offsetJ = java.lang.Integer.parseInt(temp.substring(1)); // get the offset
                temp = getExtendedName(offsetJ);                             // convert to the long name
            }
            currentEntry = new ArArchiveEntry(temp, asLong(length), asInt(userid),
                                              asInt(groupid), asInt(filemode, 8),
                                              asLong(lastmodified));
            return(currentEntry);
        }