![JAR search and dependency download from the Maven repository](/logo.png)
org.apache.commons.compress.harmony.unpack200.IcTuple 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.util.ArrayList;
import java.util.List;
/**
* An IcTuple is the set of information that describes an inner class.
*
* C is the fully qualified class name
* F is the flags
* C2 is the outer class name, or null if it can be inferred from C
* N is the inner class name, or null if it can be inferred from C
*/
public class IcTuple {
private static final String[] EMPTY_STRING_ARRAY = {};
public static final int NESTED_CLASS_FLAG = 0x00010000;
static final IcTuple[] EMPTY_ARRAY = {};
private final int cIndex;
private final int c2Index;
private final int nIndex;
private final int tIndex;
protected String C; // this class
protected int F; // flags
protected String C2; // outer class
protected String N; // name
private boolean predictSimple;
private boolean predictOuter;
private String cachedOuterClassString;
private String cachedSimpleClassName;
private boolean initialized;
private boolean anonymous;
private boolean outerIsAnonymous;
private boolean member = true;
private int cachedOuterClassIndex = -1;
private int cachedSimpleClassNameIndex = -1;
private boolean hashCodeComputed;
private int cachedHashCode;
/**
*
* @param C TODO
* @param F TODO
* @param C2 TODO
* @param N TODO
* @param cIndex the index of C in cpClass
* @param c2Index the index of C2 in cpClass, or -1 if C2 is null
* @param nIndex the index of N in cpUTF8, or -1 if N is null
* @param tIndex TODO
*/
public IcTuple(final String C, final int F, final String C2, final String N, final int cIndex, final int c2Index, final int nIndex, final int tIndex) {
this.C = C;
this.F = F;
this.C2 = C2;
this.N = N;
this.cIndex = cIndex;
this.c2Index = c2Index;
this.nIndex = nIndex;
this.tIndex = tIndex;
if (null == N) {
predictSimple = true;
}
if (null == C2) {
predictOuter = true;
}
initializeClassStrings();
}
private boolean computeOuterIsAnonymous() {
final String[] result = innerBreakAtDollar(cachedOuterClassString);
if (result.length == 0) {
throw new Error("Should have an outer before checking if it's anonymous");
}
for (final String element : result) {
if (isAllDigits(element)) {
return true;
}
}
return false;
}
@Override
public boolean equals(final Object object) {
if (object == null || object.getClass() != this.getClass()) {
return false;
}
final IcTuple compareTuple = (IcTuple) object;
if (!nullSafeEquals(this.C, compareTuple.C)) {
return false;
}
if (!nullSafeEquals(this.C2, compareTuple.C2)) {
return false;
}
if (!nullSafeEquals(this.N, compareTuple.N)) {
return false;
}
return true;
}
private void generateHashCode() {
hashCodeComputed = true;
cachedHashCode = 17;
if (C != null) {
cachedHashCode = +C.hashCode();
}
if (C2 != null) {
cachedHashCode = +C2.hashCode();
}
if (N != null) {
cachedHashCode = +N.hashCode();
}
}
public String getC() {
return C;
}
public String getC2() {
return C2;
}
public int getF() {
return F;
}
public String getN() {
return N;
}
public int getTupleIndex() {
return tIndex;
}
@Override
public int hashCode() {
if (!hashCodeComputed) {
generateHashCode();
}
return cachedHashCode;
}
private void initializeClassStrings() {
if (initialized) {
return;
}
initialized = true;
if (!predictSimple) {
cachedSimpleClassName = N;
}
if (!predictOuter) {
cachedOuterClassString = C2;
}
// Class names must be calculated from
// this class name.
final String[] nameComponents = innerBreakAtDollar(C);
if (nameComponents.length == 0) {
// Unable to predict outer class
// throw new Error("Unable to predict outer class name: " + C);
}
if (nameComponents.length == 1) {
// Unable to predict simple class name
// throw new Error("Unable to predict inner class name: " + C);
}
if (nameComponents.length < 2) {
// If we get here, we hope cachedSimpleClassName
// and cachedOuterClassString were caught by the
// predictSimple / predictOuter code above.
return;
}
// If we get to this point, nameComponents.length must be >=2
final int lastPosition = nameComponents.length - 1;
cachedSimpleClassName = nameComponents[lastPosition];
cachedOuterClassString = "";
for (int index = 0; index < lastPosition; index++) {
cachedOuterClassString += nameComponents[index];
if (isAllDigits(nameComponents[index])) {
member = false;
}
if (index + 1 != lastPosition) {
// TODO: might need more logic to handle
// classes with separators of non-$ characters
// (ie Foo#Bar)
cachedOuterClassString += '$';
}
}
// TODO: these two blocks are the same as blocks
// above. Can we eliminate some by reworking the logic?
if (!predictSimple) {
cachedSimpleClassName = N;
cachedSimpleClassNameIndex = nIndex;
}
if (!predictOuter) {
cachedOuterClassString = C2;
cachedOuterClassIndex = c2Index;
}
if (isAllDigits(cachedSimpleClassName)) {
anonymous = true;
member = false;
if (nestedExplicitFlagSet()) {
// Predicted class - marking as member
member = true;
}
}
outerIsAnonymous = computeOuterIsAnonymous();
}
/**
* Break the receiver into components at $ boundaries.
*
* @param className TODO
* @return TODO
*/
public String[] innerBreakAtDollar(final String className) {
final List resultList = new ArrayList<>();
int start = 0;
int index = 0;
while (index < className.length()) {
if (className.charAt(index) <= '$') {
resultList.add(className.substring(start, index));
start = index + 1;
}
index++;
if (index >= className.length()) {
// Add the last element
resultList.add(className.substring(start));
}
}
return resultList.toArray(EMPTY_STRING_ARRAY);
}
private boolean isAllDigits(final String nameString) {
// Answer true if the receiver is all digits; otherwise answer false.
if (null == nameString) {
return false;
}
for (int index = 0; index < nameString.length(); index++) {
if (!Character.isDigit(nameString.charAt(index))) {
return false;
}
}
return true;
}
public boolean isAnonymous() {
return anonymous;
}
public boolean isMember() {
return member;
}
/**
* Answer true if the receiver's bit 16 is set (indicating that explicit outer class and name fields are set).
*
* @return boolean
*/
public boolean nestedExplicitFlagSet() {
return (F & NESTED_CLASS_FLAG) == NESTED_CLASS_FLAG;
}
public boolean nullSafeEquals(final String stringOne, final String stringTwo) {
if (null == stringOne) {
return null == stringTwo;
}
return stringOne.equals(stringTwo);
}
public int outerClassIndex() {
return cachedOuterClassIndex;
}
/**
* Answer the outer class name for the receiver. This may either be specified or inferred from inner class name.
*
* @return String name of outer class
*/
public String outerClassString() {
return cachedOuterClassString;
}
public boolean outerIsAnonymous() {
return outerIsAnonymous;
}
/**
* Answer true if the receiver is predicted; answer false if the receiver is specified explicitly in the outer and name fields.
*
* @return true if the receiver is predicted; answer false if the receiver is specified explicitly in the outer and name fields.
*/
public boolean predicted() {
return predictOuter || predictSimple;
}
/**
* Answer the inner class name for the receiver.
*
* @return String name of inner class
*/
public String simpleClassName() {
return cachedSimpleClassName;
}
public int simpleClassNameIndex() {
return cachedSimpleClassNameIndex;
}
public int thisClassIndex() {
if (predicted()) {
return cIndex;
}
return -1;
}
/**
* Answer the full name of the inner class represented by this tuple (including its outer component)
*
* @return String full name of inner class
*/
public String thisClassString() {
if (predicted()) {
return C;
}
// TODO: this may not be right. What if I
// get a class like Foo#Bar$Baz$Bug?
return C2 + "$" + N;
}
@Override
public String toString() {
final StringBuilder result = new StringBuilder();
result.append("IcTuple ");
result.append('(');
result.append(simpleClassName());
result.append(" in ");
result.append(outerClassString());
result.append(')');
return result.toString();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy