All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.compress.harmony.unpack200.IcTuple Maven / Gradle / Ivy

Go to download

Apache Commons Compress software 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.

There is a newer version: 1.27.1
Show newest version
/*
 *  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;
import java.util.Objects;

/**
 * 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 other = (IcTuple) object; return Objects.equals(C, other.C) && Objects.equals(C2, other.C2) && Objects.equals(N, other.N); } 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() { // @formatter:off return new StringBuilder() .append("IcTuple ") .append('(') .append(simpleClassName()) .append(" in ") .append(outerClassString()) .append(')') .toString(); // @formatter:on } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy