![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.commons.compress.harmony.unpack200.BandSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of commons-compress Show documentation
Show all versions of commons-compress Show documentation
Apache Commons Compress defines an API for working with
compression and archive formats. These include bzip2, gzip, pack200,
LZMA, XZ, Snappy, traditional Unix Compress, DEFLATE, DEFLATE64, LZ4,
Brotli, Zstandard and ar, cpio, jar, tar, zip, dump, 7z, arj.
/*
* 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.IOException;
import java.io.InputStream;
import java.util.Arrays;
import org.apache.commons.compress.harmony.pack200.BHSDCodec;
import org.apache.commons.compress.harmony.pack200.Codec;
import org.apache.commons.compress.harmony.pack200.CodecEncoding;
import org.apache.commons.compress.harmony.pack200.Pack200Exception;
import org.apache.commons.compress.harmony.pack200.PopulationCodec;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPClass;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPFieldRef;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPInterfaceMethodRef;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPMethodRef;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPNameAndType;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPString;
import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
import org.apache.commons.compress.utils.ExactMath;
/**
* Abstract superclass for a set of bands.
*/
public abstract class BandSet {
protected Segment segment;
protected SegmentHeader header;
public BandSet(final Segment segment) {
this.segment = segment;
this.header = segment.getSegmentHeader();
}
/**
* Decodes a band and return an array of {@code int} values.
*
* @param name the name of the band (primarily for logging/debugging purposes)
* @param in the InputStream to decode from
* @param codec the default Codec for this band
* @param count the number of elements to read
* @return an array of decoded {@code int} 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
*/
public int[] decodeBandInt(final String name, final InputStream in, final BHSDCodec codec, final int count) throws IOException, Pack200Exception {
if (count < 0) {
throw new Pack200Exception("count < 0");
}
// Useful for debugging
// if (count > 0) {
// System.out.println("decoding " + name + " " + count);
// }
Codec codecUsed = codec;
if (codec.getB() == 1 || count == 0) {
return codec.decodeInts(count, in);
}
final int[] getFirst = codec.decodeInts(1, in);
if (getFirst.length == 0) {
return getFirst;
}
final int first = getFirst[0];
int[] band;
if (codec.isSigned() && first >= -256 && first <= -1) {
// Non-default codec should be used
codecUsed = CodecEncoding.getCodec(-1 - first, header.getBandHeadersInputStream(), codec);
band = codecUsed.decodeInts(count, in);
} else if (!codec.isSigned() && first >= codec.getL() && first <= codec.getL() + 255) {
// Non-default codec should be used
codecUsed = CodecEncoding.getCodec(first - codec.getL(), header.getBandHeadersInputStream(), codec);
band = codecUsed.decodeInts(count, in);
} else {
// First element should not be discarded
band = codec.decodeInts(count - 1, in, first);
}
// Useful for debugging -E options:
// if (!codecUsed.equals(codec)) {
// int bytes = codecUsed.lastBandLength;
// System.out.println(count + " " + name + " encoded with " + codecUsed + " " + bytes);
// }
if (codecUsed instanceof PopulationCodec) {
final PopulationCodec popCodec = (PopulationCodec) codecUsed;
final int[] favoured = popCodec.getFavoured().clone();
Arrays.sort(favoured);
for (int i = 0; i < band.length; i++) {
final boolean favouredValue = Arrays.binarySearch(favoured, band[i]) > -1;
final Codec theCodec = favouredValue ? popCodec.getFavouredCodec() : popCodec.getUnfavouredCodec();
if (theCodec instanceof BHSDCodec && ((BHSDCodec) theCodec).isDelta()) {
final BHSDCodec bhsd = (BHSDCodec) theCodec;
final long cardinality = bhsd.cardinality();
while (band[i] > bhsd.largest()) {
band[i] -= cardinality;
}
while (band[i] < bhsd.smallest()) {
band[i] = ExactMath.add(band[i], cardinality);
}
}
}
}
return band;
}
/**
* Decodes a band and return an array of {@code int[]} values.
*
* @param name the name of the band (primarily for logging/debugging purposes)
* @param in the InputStream to decode from
* @param defaultCodec the default codec for this band
* @param counts the numbers of elements to read for each int array within the array to be returned
* @return an array of decoded {@code int[]} 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
*/
public int[][] decodeBandInt(final String name, final InputStream in, final BHSDCodec defaultCodec, final int[] counts)
throws IOException, Pack200Exception {
final int[][] result = new int[counts.length][];
int totalCount = 0;
for (final int count : counts) {
totalCount += count;
}
final int[] twoDResult = decodeBandInt(name, in, defaultCodec, totalCount);
int index = 0;
for (int i = 0; i < result.length; i++) {
if (counts[i] > twoDResult.length) {
throw new IOException("Counts value exceeds length of twoDResult");
}
result[i] = new int[counts[i]];
for (int j = 0; j < result[i].length; j++) {
result[i][j] = twoDResult[index];
index++;
}
}
return result;
}
protected String[] getReferences(final int[] ints, final String[] reference) {
final String[] result = new String[ints.length];
Arrays.setAll(result, i -> reference[ints[i]]);
return result;
}
protected String[][] getReferences(final int[][] ints, final String[] reference) {
final String[][] result = new String[ints.length][];
for (int i = 0; i < result.length; i++) {
result[i] = new String[ints[i].length];
for (int j = 0; j < result[i].length; j++) {
result[i][j] = reference[ints[i][j]];
}
}
return result;
}
public CPClass[] parseCPClassReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] indices = decodeBandInt(name, in, codec, count);
final CPClass[] result = new CPClass[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = segment.getCpBands().cpClassValue(indices[i1]);
}
return result;
}
public CPNameAndType[] parseCPDescriptorReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final CpBands cpBands = segment.getCpBands();
final int[] indices = decodeBandInt(name, in, codec, count);
final CPNameAndType[] result = new CPNameAndType[indices.length];
for (int i1 = 0; i1 < count; i1++) {
final int index = indices[i1];
result[i1] = cpBands.cpNameAndTypeValue(index);
}
return result;
}
public CPDouble[] parseCPDoubleReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] indices = decodeBandInt(name, in, codec, count);
final CPDouble[] result = new CPDouble[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = segment.getCpBands().cpDoubleValue(indices[i1]);
}
return result;
}
public CPFieldRef[] parseCPFieldRefReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final CpBands cpBands = segment.getCpBands();
final int[] indices = decodeBandInt(name, in, codec, count);
final CPFieldRef[] result = new CPFieldRef[indices.length];
for (int i1 = 0; i1 < count; i1++) {
final int index = indices[i1];
result[i1] = cpBands.cpFieldValue(index);
}
return result;
}
public CPFloat[] parseCPFloatReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] indices = decodeBandInt(name, in, codec, count);
final CPFloat[] result = new CPFloat[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = segment.getCpBands().cpFloatValue(indices[i1]);
}
return result;
}
public CPInterfaceMethodRef[] parseCPInterfaceMethodRefReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final CpBands cpBands = segment.getCpBands();
final int[] indices = decodeBandInt(name, in, codec, count);
final CPInterfaceMethodRef[] result = new CPInterfaceMethodRef[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = cpBands.cpIMethodValue(indices[i1]);
}
return result;
}
public CPInteger[] parseCPIntReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] reference = segment.getCpBands().getCpInt();
final int[] indices = decodeBandInt(name, in, codec, count);
final CPInteger[] result = new CPInteger[indices.length];
for (int i1 = 0; i1 < count; i1++) {
final int index = indices[i1];
if (index < 0 || index >= reference.length) {
throw new Pack200Exception("Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
}
result[i1] = segment.getCpBands().cpIntegerValue(index);
}
return result;
}
public CPLong[] parseCPLongReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final long[] reference = segment.getCpBands().getCpLong();
final int[] indices = decodeBandInt(name, in, codec, count);
final CPLong[] result = new CPLong[indices.length];
for (int i1 = 0; i1 < count; i1++) {
final int index = indices[i1];
if (index < 0 || index >= reference.length) {
throw new Pack200Exception("Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
}
result[i1] = segment.getCpBands().cpLongValue(index);
}
return result;
}
public CPMethodRef[] parseCPMethodRefReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final CpBands cpBands = segment.getCpBands();
final int[] indices = decodeBandInt(name, in, codec, count);
final CPMethodRef[] result = new CPMethodRef[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = cpBands.cpMethodValue(indices[i1]);
}
return result;
}
public CPUTF8[] parseCPSignatureReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] indices = decodeBandInt(name, in, codec, count);
final CPUTF8[] result = new CPUTF8[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = segment.getCpBands().cpSignatureValue(indices[i1]);
}
return result;
}
protected CPUTF8[][] parseCPSignatureReferences(final String name, final InputStream in, final BHSDCodec codec, final int[] counts)
throws IOException, Pack200Exception {
int sum = 0;
for (int i = 0; i < counts.length; i++) {
sum += counts[i];
}
final int[] indices = decodeBandInt(name, in, codec, sum);
final CPUTF8[] result1 = new CPUTF8[sum];
for (int i1 = 0; i1 < sum; i1++) {
result1[i1] = segment.getCpBands().cpSignatureValue(indices[i1]);
}
int pos = 0;
final CPUTF8[][] result = new CPUTF8[counts.length][];
for (int i = 0; i < counts.length; i++) {
final int num = counts[i];
result[i] = new CPUTF8[num];
System.arraycopy(result1, pos, result[i], 0, num);
pos += num;
}
return result;
}
public CPString[] parseCPStringReferences(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] indices = decodeBandInt(name, in, codec, count);
final CPString[] result = new CPString[indices.length];
for (int i1 = 0; i1 < count; i1++) {
result[i1] = segment.getCpBands().cpStringValue(indices[i1]);
}
return result;
}
public CPUTF8[] parseCPUTF8References(final String name, final InputStream in, final BHSDCodec codec, final int count)
throws IOException, Pack200Exception {
final int[] indices = decodeBandInt(name, in, codec, count);
final CPUTF8[] result = new CPUTF8[indices.length];
for (int i1 = 0; i1 < count; i1++) {
final int index = indices[i1];
result[i1] = segment.getCpBands().cpUTF8Value(index);
}
return result;
}
public CPUTF8[][] parseCPUTF8References(final String name, final InputStream in, final BHSDCodec codec, final int[] counts)
throws IOException, Pack200Exception {
final CPUTF8[][] result = new CPUTF8[counts.length][];
int sum = 0;
for (int i = 0; i < counts.length; i++) {
result[i] = new CPUTF8[counts[i]];
sum += counts[i];
}
final CPUTF8[] result1 = new CPUTF8[sum];
final int[] indices = decodeBandInt(name, in, codec, sum);
for (int i1 = 0; i1 < sum; i1++) {
final int index = indices[i1];
result1[i1] = segment.getCpBands().cpUTF8Value(index);
}
int pos = 0;
for (int i = 0; i < counts.length; i++) {
final int num = counts[i];
result[i] = new CPUTF8[num];
System.arraycopy(result1, pos, result[i], 0, num);
pos += num;
}
return result;
}
public long[] parseFlags(final String name, final InputStream in, final int count, final BHSDCodec hiCodec, final BHSDCodec loCodec)
throws IOException, Pack200Exception {
return parseFlags(name, in, new int[] { count }, hiCodec, loCodec)[0];
}
public long[] parseFlags(final String name, final InputStream in, final int count, final BHSDCodec codec, final boolean hasHi)
throws IOException, Pack200Exception {
return parseFlags(name, in, new int[] { count }, hasHi ? codec : null, codec)[0];
}
public long[][] parseFlags(final String name, final InputStream in, final int[] counts, final BHSDCodec hiCodec, final BHSDCodec loCodec)
throws IOException, Pack200Exception {
final int count = counts.length;
if (count == 0) {
return new long[][] { {} };
}
int sum = 0;
final long[][] result = new long[count][];
for (int i = 0; i < count; i++) {
sum += counts[i];
}
int[] hi = null;
int[] lo;
if (hiCodec != null) {
hi = decodeBandInt(name, in, hiCodec, sum);
}
lo = decodeBandInt(name, in, loCodec, sum);
int index = 0;
for (int i = 0; i < count; i++) {
result[i] = new long[counts[i]];
for (int j = 0; j < result[i].length; j++) {
if (hi != null) {
result[i][j] = (long) hi[index] << 32 | lo[index] & 4294967295L;
} else {
result[i][j] = lo[index];
}
index++;
}
}
return result;
}
public long[][] parseFlags(final String name, final InputStream in, final int[] counts, final BHSDCodec codec, final boolean hasHi)
throws IOException, Pack200Exception {
return parseFlags(name, in, counts, hasHi ? codec : null, codec);
}
/**
* Parses count references from {@code in}, using {@code codec} to decode the values as indexes into {@code reference} (which is populated prior to
* this call). An exception is thrown if a decoded index falls outside the range [0..reference.length-1].
*
* @param name the band name
* @param in the input stream to read from
* @param codec the BHSDCodec to use for decoding
* @param count the number of references to decode
* @param reference the array of values to use for the references
* @return Parsed references.
*
* @throws IOException if a problem occurs during reading from the underlying stream
* @throws Pack200Exception if a problem occurs with an unexpected value or unsupported Codec
*/
public String[] parseReferences(final String name, final InputStream in, final BHSDCodec codec, final int count, final String[] reference)
throws IOException, Pack200Exception {
return parseReferences(name, in, codec, new int[] { count }, reference)[0];
}
/**
* Parses count references from {@code in}, using {@code codec} to decode the values as indexes into {@code reference} (which is populated prior to
* this call). An exception is thrown if a decoded index falls outside the range [0..reference.length-1]. Unlike the other parseReferences, this
* post-processes the result into an array of results.
*
* @param name TODO
* @param in the input stream to read from
* @param codec the BHSDCodec to use for decoding
* @param counts the numbers of references to decode for each array entry
* @param reference the array of values to use for the references
* @return Parsed references.
*
* @throws IOException if a problem occurs during reading from the underlying stream
* @throws Pack200Exception if a problem occurs with an unexpected value or unsupported Codec
*/
public String[][] parseReferences(final String name, final InputStream in, final BHSDCodec codec, final int[] counts, final String[] reference)
throws IOException, Pack200Exception {
final int count = counts.length;
if (count == 0) {
return new String[][] { {} };
}
int sum = 0;
for (int i = 0; i < count; i++) {
sum += counts[i];
}
// TODO Merge the decode and parsing of a multiple structure into one
final int[] indices = decodeBandInt(name, in, codec, sum);
final String[] result1 = new String[sum];
for (int i1 = 0; i1 < sum; i1++) {
final int index = indices[i1];
if (index < 0 || index >= reference.length) {
throw new Pack200Exception("Something has gone wrong during parsing references, index = " + index + ", array size = " + reference.length);
}
result1[i1] = reference[index];
}
// TODO Merge the decode and parsing of a multiple structure into one
final String[][] result = new String[count][];
int pos = 0;
for (int i = 0; i < count; i++) {
final int num = counts[i];
result[i] = new String[num];
System.arraycopy(result1, pos, result[i], 0, num);
pos += num;
}
return result;
}
public abstract void read(InputStream inputStream) throws IOException, Pack200Exception;
public abstract void unpack() throws IOException, Pack200Exception;
public void unpack(final InputStream in) throws IOException, Pack200Exception {
read(in);
unpack();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy