001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * https://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.harmony.unpack200; 020 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Iterator; 024import java.util.List; 025 026import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationDefaultAttribute; 027import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.Annotation; 028import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.ElementValue; 029import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute; 030import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble; 031import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat; 032import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger; 033import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong; 034import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8; 035import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleAnnotationsAttribute; 036import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute; 037import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute.ParameterAnnotation; 038 039/** 040 * A group of metadata bands, such as class_RVA_bands, method_AD_bands etc. 041 */ 042public class MetadataBandGroup { 043 044 private static CPUTF8 rvaUTF8; 045 private static CPUTF8 riaUTF8; 046 047 private static CPUTF8 rvpaUTF8; 048 private static CPUTF8 ripaUTF8; 049 050 public static void setRiaAttributeName(final CPUTF8 cpUTF8Value) { 051 riaUTF8 = cpUTF8Value; 052 } 053 054 public static void setRipaAttributeName(final CPUTF8 cpUTF8Value) { 055 ripaUTF8 = cpUTF8Value; 056 } 057 058 public static void setRvaAttributeName(final CPUTF8 cpUTF8Value) { 059 rvaUTF8 = cpUTF8Value; 060 } 061 062 public static void setRvpaAttributeName(final CPUTF8 cpUTF8Value) { 063 rvpaUTF8 = cpUTF8Value; 064 } 065 066 private final String type; 067 068 private final CpBands cpBands; 069 070 private List<Attribute> attributes; 071 072 public int[] param_NB; 073 074 public int[] anno_N; 075 public CPUTF8[][] type_RS; 076 public int[][] pair_N; 077 public CPUTF8[] name_RU; 078 public int[] T; 079 public CPInteger[] caseI_KI; 080 public CPDouble[] caseD_KD; 081 public CPFloat[] caseF_KF; 082 public CPLong[] caseJ_KJ; 083 public CPUTF8[] casec_RS; 084 public String[] caseet_RS; 085 public String[] caseec_RU; 086 public CPUTF8[] cases_RU; 087 public int[] casearray_N; 088 public CPUTF8[] nesttype_RS; 089 public int[] nestpair_N; 090 public CPUTF8[] nestname_RU; 091 private int caseI_KI_Index; 092 093 private int caseD_KD_Index; 094 095 private int caseF_KF_Index; 096 097 private int caseJ_KJ_Index; 098 099 private int casec_RS_Index; 100 101 private int caseet_RS_Index; 102 103 private int caseec_RU_Index; 104 105 private int cases_RU_Index; 106 107 private int casearray_N_Index; 108 109 private int T_index; 110 111 private int nesttype_RS_Index; 112 113 private int nestpair_N_Index; 114 115 private Iterator<CPUTF8> nestname_RU_Iterator; 116 117 private int anno_N_Index; 118 119 private int pair_N_Index; 120 121 public MetadataBandGroup(final String type, final CpBands cpBands) { 122 this.type = type; 123 this.cpBands = cpBands; 124 } 125 126 /** 127 * Gets a new Annotation. 128 * 129 * @param numPairs Number of pairs, matches the lengths of {@code elementNames} and {@code elementValues} in the new Annotation. 130 * @param type Type. 131 * @param namesIterator Iterates names to create pairs. 132 */ 133 private Annotation getAnnotation(final CPUTF8 type, final int pairCount, final Iterator<CPUTF8> namesIterator) { 134 final CPUTF8[] elementNames = new CPUTF8[pairCount]; 135 final ElementValue[] elementValues = new ElementValue[pairCount]; 136 for (int j = 0; j < elementNames.length; j++) { 137 elementNames[j] = namesIterator.next(); 138 final int t = T[T_index++]; 139 elementValues[j] = new ElementValue(t, getNextValue(t)); 140 } 141 return new Annotation(pairCount, type, elementNames, elementValues); 142 } 143 144 private Attribute getAttribute(final int numAnnotations, final CPUTF8[] types, final int[] pairCounts, final Iterator<CPUTF8> namesIterator) { 145 final Annotation[] annotations = new Annotation[numAnnotations]; 146 Arrays.setAll(annotations, i -> getAnnotation(types[i], pairCounts[i], namesIterator)); 147 return new RuntimeVisibleorInvisibleAnnotationsAttribute(type.equals("RVA") ? rvaUTF8 : riaUTF8, annotations); 148 } 149 150 public List<Attribute> getAttributes() { 151 // TODO: Optimize iterators! 152 if (attributes == null) { 153 attributes = new ArrayList<>(); 154 if (name_RU != null) { 155 final Iterator<CPUTF8> name_RU_Iterator = Arrays.asList(name_RU).iterator(); 156 if (!type.equals("AD")) { 157 T_index = 0; 158 } 159 caseI_KI_Index = 0; 160 caseD_KD_Index = 0; 161 caseF_KF_Index = 0; 162 caseJ_KJ_Index = 0; 163 casec_RS_Index = 0; 164 caseet_RS_Index = 0; 165 caseec_RU_Index = 0; 166 cases_RU_Index = 0; 167 casearray_N_Index = 0; 168 nesttype_RS_Index = 0; 169 nestpair_N_Index = 0; 170 nestname_RU_Iterator = Arrays.asList(nestname_RU).iterator(); 171 if (type.equals("RVA") || type.equals("RIA")) { 172 for (int i = 0; i < anno_N.length; i++) { 173 attributes.add(getAttribute(anno_N[i], type_RS[i], pair_N[i], name_RU_Iterator)); 174 } 175 } else if (type.equals("RVPA") || type.equals("RIPA")) { 176 anno_N_Index = 0; 177 pair_N_Index = 0; 178 for (final int element : param_NB) { 179 attributes.add(getParameterAttribute(element, name_RU_Iterator)); 180 } 181 } 182 } else if (type.equals("AD")) { 183 for (final int element : T) { 184 attributes.add(new AnnotationDefaultAttribute(new ElementValue(element, getNextValue(element)))); 185 } 186 } 187 } 188 return attributes; 189 } 190 191 private Object getNextValue(final int t) { 192 switch (t) { 193 case 'B': 194 case 'C': 195 case 'I': 196 case 'S': 197 case 'Z': 198 return caseI_KI[caseI_KI_Index++]; 199 case 'D': 200 return caseD_KD[caseD_KD_Index++]; 201 case 'F': 202 return caseF_KF[caseF_KF_Index++]; 203 case 'J': 204 return caseJ_KJ[caseJ_KJ_Index++]; 205 case 'c': 206 return casec_RS[casec_RS_Index++]; 207 case 'e': 208 // TODO: check this - it may not work if the first string already 209 // has a colon in it 210 final String enumString = caseet_RS[caseet_RS_Index++] + ":" + caseec_RU[caseec_RU_Index++]; 211 return cpBands.cpNameAndTypeValue(enumString); 212 case 's': 213 return cases_RU[cases_RU_Index++]; 214 case '[': 215 final int arraySize = casearray_N[casearray_N_Index++]; 216 final ElementValue[] nestedArray = new ElementValue[arraySize]; 217 for (int i = 0; i < arraySize; i++) { 218 final int nextT = T[T_index++]; 219 nestedArray[i] = new ElementValue(nextT, getNextValue(nextT)); 220 } 221 return nestedArray; 222 case '@': 223 final CPUTF8 type = nesttype_RS[nesttype_RS_Index++]; 224 final int numPairs = nestpair_N[nestpair_N_Index++]; 225 226 return getAnnotation(type, numPairs, nestname_RU_Iterator); 227 } 228 return null; 229 } 230 231 private Attribute getParameterAttribute(final int numParameters, final Iterator<CPUTF8> namesIterator) { 232 final ParameterAnnotation[] parameterAnnotations = new ParameterAnnotation[numParameters]; 233 for (int i = 0; i < numParameters; i++) { 234 final int numAnnotations = anno_N[anno_N_Index++]; 235 final int[] pairCounts = pair_N[pair_N_Index++]; 236 final Annotation[] annotations = new Annotation[numAnnotations]; 237 Arrays.setAll(annotations, j -> getAnnotation(type_RS[anno_N_Index - 1][j], pairCounts[j], namesIterator)); 238 parameterAnnotations[i] = new ParameterAnnotation(annotations); 239 } 240 return new RuntimeVisibleorInvisibleParameterAnnotationsAttribute(type.equals("RVPA") ? rvpaUTF8 : ripaUTF8, parameterAnnotations); 241 } 242 243}