001    /*
002     * Copyright 2005 The Apache Software Foundation.
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     * 
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     * 
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    package org.vafer.jdeb.ar;
017    
018    import java.io.IOException;
019    import java.io.InputStream;
020    
021    /**
022     * To be replace by commons compress once released
023     * 
024     * @author Torsten Curdt <tcurdt@vafer.org>
025     */
026    public class ArInputStream extends InputStream implements ArConstants {
027    
028            private final InputStream input;
029            private long offset = 0;
030            
031            public ArInputStream( final InputStream pInput ) {
032                    input = pInput;
033            }
034            
035            public ArEntry getNextEntry() throws IOException {
036                    
037                    if (offset == 0) {
038                            final byte[] expected = HEADER;
039                            final byte[] realized = new byte[expected.length]; 
040                            final int read = input.read(realized);
041                            if (read != expected.length) {
042                                    throw new IOException("failed to read header");
043                            }
044                            for (int i = 0; i < expected.length; i++) {
045                                    if (expected[i] != realized[i]) {
046                                            throw new IOException("invalid header " + new String(realized));
047                                    }
048                            }
049                    }
050    
051                    if (input.available() == 0) {
052                            return null;
053                    }
054                                    
055                    if (offset % 2 != 0) {
056                            read();
057                    }
058    
059                    final byte[] name = new byte[FIELD_SIZE_NAME];
060                    final byte[] lastmodified = new byte[FIELD_SIZE_LASTMODIFIED];
061                    final byte[] userid = new byte[FIELD_SIZE_UID];
062                    final byte[] groupid = new byte[FIELD_SIZE_GID];
063                    final byte[] filemode = new byte[FIELD_SIZE_MODE];
064                    final byte[] length = new byte[FIELD_SIZE_LENGTH];
065                    
066                    read(name);
067                    read(lastmodified);
068                    read(userid);
069                    read(groupid);
070                    read(filemode);
071                    read(length);
072    
073                    final byte[] expected = ENTRY_TERMINATOR;
074                    final byte[] realized = new byte[expected.length];
075                    final int read = input.read(realized);
076                    if (read != expected.length) {
077                            throw new IOException("failed to read entry header");
078                    }
079                    for (int i = 0; i < expected.length; i++) {
080                            if (expected[i] != realized[i]) {
081                                    throw new IOException("invalid entry header. not read the content?");
082                            }
083                    }
084                    
085                    return new ArEntry(new String(name).trim(), Long.parseLong(new String(length).trim()));
086            }
087            
088            
089            public int read() throws IOException {
090                    final int ret = input.read();
091                    offset++;
092                    return ret;
093            }
094    
095            public void close() throws IOException {
096                    input.close();
097                    super.close();
098            }
099    
100    }