001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one or more
003 *  contributor license agreements.  See the NOTICE file distributed with
004 *  this work for additional information regarding copyright ownership.
005 *  The ASF licenses this file to You under the Apache License, Version 2.0
006 *  (the "License"); you may not use this file except in compliance with
007 *  the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017package org.apache.commons.compress.harmony.unpack200;
018
019import java.io.IOException;
020import java.io.InputStream;
021
022import org.apache.commons.compress.harmony.pack200.Codec;
023import org.apache.commons.compress.harmony.pack200.Pack200Exception;
024
025/**
026 * Parses the file band headers (not including the actual bits themselves). At the end of this parse call, the input
027 * stream will be positioned at the start of the file_bits themselves, and there will be Sum(file_size) bits remaining
028 * in the stream with BYTE1 compression. A decent implementation will probably just stream the bytes out to the
029 * reconstituted Jar rather than caching them.
030 */
031public class FileBands extends BandSet {
032
033    private byte[][] fileBits;
034
035    private int[] fileModtime;
036
037    private String[] fileName;
038
039    private int[] fileOptions;
040
041    private long[] fileSize;
042
043    private final String[] cpUTF8;
044
045    private InputStream in;
046
047    /**
048     * @param segment TODO
049     */
050    public FileBands(final Segment segment) {
051        super(segment);
052        this.cpUTF8 = segment.getCpBands().getCpUTF8();
053    }
054
055    /*
056     * (non-Javadoc)
057     *
058     * @see org.apache.commons.compress.harmony.unpack200.BandSet#unpack(java.io.InputStream)
059     */
060    @Override
061    public void read(final InputStream in) throws IOException, Pack200Exception {
062        final int numberOfFiles = header.getNumberOfFiles();
063        final SegmentOptions options = header.getOptions();
064
065        fileName = parseReferences("file_name", in, Codec.UNSIGNED5, numberOfFiles, cpUTF8);
066        fileSize = parseFlags("file_size", in, numberOfFiles, Codec.UNSIGNED5, options.hasFileSizeHi());
067        if (options.hasFileModtime()) {
068            fileModtime = decodeBandInt("file_modtime", in, Codec.DELTA5, numberOfFiles);
069        } else {
070            fileModtime = new int[numberOfFiles];
071        }
072        if (options.hasFileOptions()) {
073            fileOptions = decodeBandInt("file_options", in, Codec.UNSIGNED5, numberOfFiles);
074        } else {
075            fileOptions = new int[numberOfFiles];
076        }
077        this.in = in; // store for use by processFileBits(), which is called
078        // later
079    }
080
081    // TODO: stream the file bits directly somehow
082    public void processFileBits() throws IOException, Pack200Exception {
083        // now read in the bytes
084        final int numberOfFiles = header.getNumberOfFiles();
085        fileBits = new byte[numberOfFiles][];
086        for (int i = 0; i < numberOfFiles; i++) {
087            final int size = (int) fileSize[i];
088            // TODO This breaks if file_size > 2^32. Probably an array is
089            // not the right choice, and we should just serialize it here?
090            fileBits[i] = new byte[size];
091            final int read = in.read(fileBits[i]);
092            if (size != 0 && read < size) {
093                throw new Pack200Exception("Expected to read " + size + " bytes but read " + read);
094            }
095        }
096    }
097
098    @Override
099    public void unpack() {
100
101    }
102
103    public byte[][] getFileBits() {
104        return fileBits;
105    }
106
107    public int[] getFileModtime() {
108        return fileModtime;
109    }
110
111    public String[] getFileName() {
112        return fileName;
113    }
114
115    public int[] getFileOptions() {
116        return fileOptions;
117    }
118
119    public long[] getFileSize() {
120        return fileSize;
121    }
122
123}