SegmentHeader.java
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.apache.commons.compress.harmony.unpack200;
- import java.io.ByteArrayInputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import org.apache.commons.compress.harmony.pack200.BHSDCodec;
- import org.apache.commons.compress.harmony.pack200.Codec;
- import org.apache.commons.compress.harmony.pack200.Pack200Exception;
- import org.apache.commons.compress.utils.IOUtils;
- /**
- * SegmentHeader is the header band of a {@link Segment}
- */
- public class SegmentHeader {
- private static final byte[] EMPTY_BYTE_ARRAY = {};
- /**
- * The magic header for a Pack200 Segment is 0xCAFED00D. I wonder where they get their inspiration from ...
- */
- private static final int[] magic = { 0xCA, 0xFE, 0xD0, 0x0D };
- private int archiveMajor;
- private int archiveMinor;
- private long archiveModtime;
- private long archiveSize;
- private int attributeDefinitionCount;
- private InputStream bandHeadersInputStream;
- private int bandHeadersSize;
- private int classCount;
- private int cpClassCount;
- private int cpDescriptorCount;
- private int cpDoubleCount;
- private int cpFieldCount;
- private int cpFloatCount;
- private int cpIMethodCount;
- private int cpIntCount;
- private int cpLongCount;
- private int cpMethodCount;
- private int cpSignatureCount;
- private int cpStringCount;
- private int cpUTF8Count;
- private int defaultClassMajorVersion;
- private int defaultClassMinorVersion;
- private int innerClassCount;
- private int numberOfFiles;
- private int segmentsRemaining;
- private SegmentOptions options;
- private final Segment segment;
- private int archiveSizeOffset;
- public SegmentHeader(final Segment segment) {
- this.segment = segment;
- }
- /**
- * Decode a scalar from the band file. A scalar is like a band, but does not perform any band code switching.
- *
- * @param name the name of the scalar (primarily for logging/debugging purposes)
- * @param in the input stream to read from
- * @param codec the codec for this scalar
- * @return the decoded value
- * @throws IOException if there is a problem reading from the underlying input stream
- * @throws Pack200Exception if there is a problem decoding the value or that the value is invalid
- */
- private int decodeScalar(final String name, final InputStream in, final BHSDCodec codec) throws IOException, Pack200Exception {
- final int ret = codec.decode(in);
- segment.log(Segment.LOG_LEVEL_VERBOSE, "Parsed #" + name + " as " + ret);
- return ret;
- }
- /**
- * Decode a number of scalars from the band file. A scalar is like a band, but does not perform any band code switching.
- *
- * @param name the name of the scalar (primarily for logging/debugging purposes)
- * @param in the input stream to read from
- * @param codec the codec for this scalar
- * @return an array of decoded {@code long[]} values
- * @throws IOException if there is a problem reading from the underlying input stream
- * @throws Pack200Exception if there is a problem decoding the value or that the value is invalid
- */
- private int[] decodeScalar(final String name, final InputStream in, final BHSDCodec codec, final int n) throws IOException, Pack200Exception {
- segment.log(Segment.LOG_LEVEL_VERBOSE, "Parsed #" + name + " (" + n + ")");
- return codec.decodeInts(n, in);
- }
- public long getArchiveModtime() {
- return archiveModtime;
- }
- public long getArchiveSize() {
- return archiveSize;
- }
- public int getArchiveSizeOffset() {
- return archiveSizeOffset;
- }
- public int getAttributeDefinitionCount() {
- return attributeDefinitionCount;
- }
- /**
- * Obtain the band headers data as an input stream. If no band headers are present, this will return an empty input stream to prevent any further reads
- * taking place.
- *
- * Note that as a stream, data consumed from this input stream can't be re-used. Data is only read from this stream if the encoding is such that additional
- * information needs to be decoded from the stream itself.
- *
- * @return the band headers input stream
- */
- public InputStream getBandHeadersInputStream() {
- if (bandHeadersInputStream == null) {
- bandHeadersInputStream = new ByteArrayInputStream(EMPTY_BYTE_ARRAY);
- }
- return bandHeadersInputStream;
- }
- public int getBandHeadersSize() {
- return bandHeadersSize;
- }
- public int getClassCount() {
- return classCount;
- }
- public int getCpClassCount() {
- return cpClassCount;
- }
- public int getCpDescriptorCount() {
- return cpDescriptorCount;
- }
- public int getCpDoubleCount() {
- return cpDoubleCount;
- }
- public int getCpFieldCount() {
- return cpFieldCount;
- }
- public int getCpFloatCount() {
- return cpFloatCount;
- }
- public int getCpIMethodCount() {
- return cpIMethodCount;
- }
- public int getCpIntCount() {
- return cpIntCount;
- }
- public int getCpLongCount() {
- return cpLongCount;
- }
- public int getCpMethodCount() {
- return cpMethodCount;
- }
- public int getCpSignatureCount() {
- return cpSignatureCount;
- }
- public int getCpStringCount() {
- return cpStringCount;
- }
- public int getCpUTF8Count() {
- return cpUTF8Count;
- }
- public int getDefaultClassMajorVersion() {
- return defaultClassMajorVersion;
- }
- public int getDefaultClassMinorVersion() {
- return defaultClassMinorVersion;
- }
- public int getInnerClassCount() {
- return innerClassCount;
- }
- public int getNumberOfFiles() {
- return numberOfFiles;
- }
- public SegmentOptions getOptions() {
- return options;
- }
- public int getSegmentsRemaining() {
- return segmentsRemaining;
- }
- private void parseArchiveFileCounts(final InputStream in) throws IOException, Pack200Exception {
- if (options.hasArchiveFileCounts()) {
- setArchiveSize((long) decodeScalar("archive_size_hi", in, Codec.UNSIGNED5) << 32 | decodeScalar("archive_size_lo", in, Codec.UNSIGNED5));
- archiveSizeOffset = in.available();
- setSegmentsRemaining(decodeScalar("archive_next_count", in, Codec.UNSIGNED5));
- setArchiveModtime(decodeScalar("archive_modtime", in, Codec.UNSIGNED5));
- numberOfFiles = decodeScalar("file_count", in, Codec.UNSIGNED5);
- }
- }
- private void parseArchiveSpecialCounts(final InputStream in) throws IOException, Pack200Exception {
- if (getOptions().hasSpecialFormats()) {
- bandHeadersSize = decodeScalar("band_headers_size", in, Codec.UNSIGNED5);
- setAttributeDefinitionCount(decodeScalar("attr_definition_count", in, Codec.UNSIGNED5));
- }
- }
- private void parseClassCounts(final InputStream in) throws IOException, Pack200Exception {
- innerClassCount = decodeScalar("ic_count", in, Codec.UNSIGNED5);
- defaultClassMinorVersion = decodeScalar("default_class_minver", in, Codec.UNSIGNED5);
- defaultClassMajorVersion = decodeScalar("default_class_majver", in, Codec.UNSIGNED5);
- classCount = decodeScalar("class_count", in, Codec.UNSIGNED5);
- }
- private void parseCpCounts(final InputStream in) throws IOException, Pack200Exception {
- cpUTF8Count = decodeScalar("cp_Utf8_count", in, Codec.UNSIGNED5);
- if (getOptions().hasCPNumberCounts()) {
- cpIntCount = decodeScalar("cp_Int_count", in, Codec.UNSIGNED5);
- cpFloatCount = decodeScalar("cp_Float_count", in, Codec.UNSIGNED5);
- cpLongCount = decodeScalar("cp_Long_count", in, Codec.UNSIGNED5);
- cpDoubleCount = decodeScalar("cp_Double_count", in, Codec.UNSIGNED5);
- }
- cpStringCount = decodeScalar("cp_String_count", in, Codec.UNSIGNED5);
- cpClassCount = decodeScalar("cp_Class_count", in, Codec.UNSIGNED5);
- cpSignatureCount = decodeScalar("cp_Signature_count", in, Codec.UNSIGNED5);
- cpDescriptorCount = decodeScalar("cp_Descr_count", in, Codec.UNSIGNED5);
- cpFieldCount = decodeScalar("cp_Field_count", in, Codec.UNSIGNED5);
- cpMethodCount = decodeScalar("cp_Method_count", in, Codec.UNSIGNED5);
- cpIMethodCount = decodeScalar("cp_Imethod_count", in, Codec.UNSIGNED5);
- }
- public void read(final InputStream in) throws IOException, Error, Pack200Exception {
- final int[] word = decodeScalar("archive_magic_word", in, Codec.BYTE1, magic.length);
- for (int m = 0; m < magic.length; m++) {
- if (word[m] != magic[m]) {
- throw new Error("Bad header");
- }
- }
- setArchiveMinorVersion(decodeScalar("archive_minver", in, Codec.UNSIGNED5));
- setArchiveMajorVersion(decodeScalar("archive_majver", in, Codec.UNSIGNED5));
- options = new SegmentOptions(decodeScalar("archive_options", in, Codec.UNSIGNED5));
- parseArchiveFileCounts(in);
- parseArchiveSpecialCounts(in);
- parseCpCounts(in);
- parseClassCounts(in);
- if (getBandHeadersSize() > 0) {
- setBandHeadersData(IOUtils.readRange(in, getBandHeadersSize()));
- }
- archiveSizeOffset -= in.available();
- }
- /**
- * Sets the major version of this archive.
- *
- * @param version the minor version of the archive
- * @throws Pack200Exception if the major version is not 150
- */
- private void setArchiveMajorVersion(final int version) throws Pack200Exception {
- if (version != 150) {
- throw new Pack200Exception("Invalid segment major version: " + version);
- }
- archiveMajor = version;
- }
- /**
- * Sets the minor version of this archive
- *
- * @param version the minor version of the archive
- * @throws Pack200Exception if the minor version is not 7
- */
- private void setArchiveMinorVersion(final int version) throws Pack200Exception {
- if (version != 7) {
- throw new Pack200Exception("Invalid segment minor version");
- }
- archiveMinor = version;
- }
- public void setArchiveModtime(final long archiveModtime) {
- this.archiveModtime = archiveModtime;
- }
- public void setArchiveSize(final long archiveSize) {
- this.archiveSize = archiveSize;
- }
- private void setAttributeDefinitionCount(final long valuie) {
- this.attributeDefinitionCount = (int) valuie;
- }
- private void setBandHeadersData(final byte[] bandHeaders) {
- this.bandHeadersInputStream = new ByteArrayInputStream(bandHeaders);
- }
- public void setSegmentsRemaining(final long value) {
- segmentsRemaining = (int) value;
- }
- public void unpack() {
- }
- }