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 */ 019 020package org.apache.commons.compress.harmony.pack200; 021 022import java.io.IOException; 023import java.io.OutputStream; 024import java.util.ArrayList; 025import java.util.Iterator; 026import java.util.List; 027 028/** 029 * A group of metadata (annotation) bands, such as class_RVA_bands, method_AD_bands etc. 030 */ 031public class MetadataBandGroup extends BandSet { 032 033 public static final int CONTEXT_CLASS = 0; 034 public static final int CONTEXT_FIELD = 1; 035 public static final int CONTEXT_METHOD = 2; 036 037 private final String type; 038 private int numBackwardsCalls; 039 040 public IntList param_NB = new IntList(); // TODO: Lazy instantiation? 041 public IntList anno_N = new IntList(); 042 public List<CPSignature> type_RS = new ArrayList<>(); 043 public IntList pair_N = new IntList(); 044 public List<CPUTF8> name_RU = new ArrayList<>(); 045 public List<String> T = new ArrayList<>(); 046 public List<CPConstant<?>> caseI_KI = new ArrayList<>(); 047 public List<CPConstant<?>> caseD_KD = new ArrayList<>(); 048 public List<CPConstant<?>> caseF_KF = new ArrayList<>(); 049 public List<CPConstant<?>> caseJ_KJ = new ArrayList<>(); 050 public List<CPSignature> casec_RS = new ArrayList<>(); 051 public List<CPSignature> caseet_RS = new ArrayList<>(); 052 public List<CPUTF8> caseec_RU = new ArrayList<>(); 053 public List<CPUTF8> cases_RU = new ArrayList<>(); 054 public IntList casearray_N = new IntList(); 055 public List<CPSignature> nesttype_RS = new ArrayList<>(); 056 public IntList nestpair_N = new IntList(); 057 public List<CPUTF8> nestname_RU = new ArrayList<>(); 058 059 private final CpBands cpBands; 060 private final int context; 061 062 /** 063 * Constructs a new MetadataBandGroup 064 * 065 * @param type must be either AD, RVA, RIA, RVPA or RIPA. 066 * @param context {@code CONTEXT_CLASS}, {@code CONTEXT_METHOD} or {@code CONTEXT_FIELD} 067 * @param cpBands constant pool bands 068 * @param segmentHeader segment header 069 * @param effort packing effort 070 */ 071 public MetadataBandGroup(final String type, final int context, final CpBands cpBands, final SegmentHeader segmentHeader, final int effort) { 072 super(effort, segmentHeader); 073 this.type = type; 074 this.cpBands = cpBands; 075 this.context = context; 076 } 077 078 /** 079 * Add an annotation to this set of bands 080 * 081 * @param desc TODO 082 * @param nameRU TODO 083 * @param tags TODO 084 * @param values TODO 085 * @param caseArrayN TODO 086 * @param nestTypeRS TODO 087 * @param nestNameRU TODO 088 * @param nestPairN TODO 089 */ 090 public void addAnnotation(final String desc, final List<String> nameRU, final List<String> tags, final List<Object> values, final List<Integer> caseArrayN, 091 final List<String> nestTypeRS, final List<String> nestNameRU, final List<Integer> nestPairN) { 092 type_RS.add(cpBands.getCPSignature(desc)); 093 pair_N.add(nameRU.size()); 094 nameRU.forEach(name -> name_RU.add(cpBands.getCPUtf8(name))); 095 096 final Iterator<Object> valuesIterator = values.iterator(); 097 for (final String tag : tags) { 098 T.add(tag); 099 switch (tag) { 100 case "B": 101 case "C": 102 case "I": 103 case "S": 104 case "Z": { 105 caseI_KI.add(cpBands.getConstant(valuesIterator.next())); 106 break; 107 } 108 case "D": { 109 caseD_KD.add(cpBands.getConstant(valuesIterator.next())); 110 break; 111 } 112 case "F": { 113 caseF_KF.add(cpBands.getConstant(valuesIterator.next())); 114 break; 115 } 116 case "J": { 117 caseJ_KJ.add(cpBands.getConstant(valuesIterator.next())); 118 break; 119 } 120 case "c": { 121 casec_RS.add(cpBands.getCPSignature(nextString(valuesIterator))); 122 break; 123 } 124 case "e": { 125 caseet_RS.add(cpBands.getCPSignature(nextString(valuesIterator))); 126 caseec_RU.add(cpBands.getCPUtf8(nextString(valuesIterator))); 127 break; 128 } 129 case "s": { 130 cases_RU.add(cpBands.getCPUtf8(nextString(valuesIterator))); 131 break; 132 } 133 } 134 // do nothing here for [ or @ (handled below) 135 } 136 for (final Integer element : caseArrayN) { 137 final int arraySize = element.intValue(); 138 casearray_N.add(arraySize); 139 numBackwardsCalls += arraySize; 140 } 141 nestTypeRS.forEach(element -> nesttype_RS.add(cpBands.getCPSignature(element))); 142 nestNameRU.forEach(element -> nestname_RU.add(cpBands.getCPUtf8(element))); 143 for (final Integer numPairs : nestPairN) { 144 nestpair_N.add(numPairs.intValue()); 145 numBackwardsCalls += numPairs.intValue(); 146 } 147 } 148 149 /** 150 * Add an annotation to this set of bands. 151 * 152 * @param numParams TODO 153 * @param annoN TODO 154 * @param pairN TODO 155 * @param typeRS TODO 156 * @param nameRU TODO 157 * @param tags TODO 158 * @param values TODO 159 * @param caseArrayN TODO 160 * @param nestTypeRS TODO 161 * @param nestNameRU TODO 162 * @param nestPairN TODO 163 */ 164 public void addParameterAnnotation(final int numParams, final int[] annoN, final IntList pairN, final List<String> typeRS, final List<String> nameRU, 165 final List<String> tags, final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, final List<String> nestNameRU, 166 final List<Integer> nestPairN) { 167 param_NB.add(numParams); 168 for (final int element : annoN) { 169 anno_N.add(element); 170 } 171 pair_N.addAll(pairN); 172 typeRS.forEach(desc -> type_RS.add(cpBands.getCPSignature(desc))); 173 nameRU.forEach(name -> name_RU.add(cpBands.getCPUtf8(name))); 174 final Iterator<Object> valuesIterator = values.iterator(); 175 for (final String tag : tags) { 176 T.add(tag); 177 switch (tag) { 178 case "B": 179 case "C": 180 case "I": 181 case "S": 182 case "Z": { 183 caseI_KI.add(cpBands.getConstant(valuesIterator.next())); 184 break; 185 } 186 case "D": { 187 caseD_KD.add(cpBands.getConstant(valuesIterator.next())); 188 break; 189 } 190 case "F": { 191 caseF_KF.add(cpBands.getConstant(valuesIterator.next())); 192 break; 193 } 194 case "J": { 195 caseJ_KJ.add(cpBands.getConstant(valuesIterator.next())); 196 break; 197 } 198 case "c": { 199 casec_RS.add(cpBands.getCPSignature(nextString(valuesIterator))); 200 break; 201 } 202 case "e": { 203 caseet_RS.add(cpBands.getCPSignature(nextString(valuesIterator))); 204 caseec_RU.add(cpBands.getCPUtf8(nextString(valuesIterator))); 205 break; 206 } 207 case "s": { 208 cases_RU.add(cpBands.getCPUtf8(nextString(valuesIterator))); 209 break; 210 } 211 } 212 // do nothing here for [ or @ (handled below) 213 } 214 for (final Integer element : caseArrayN) { 215 final int arraySize = element.intValue(); 216 casearray_N.add(arraySize); 217 numBackwardsCalls += arraySize; 218 } 219 nestTypeRS.forEach(type -> nesttype_RS.add(cpBands.getCPSignature(type))); 220 nestNameRU.forEach(name -> nestname_RU.add(cpBands.getCPUtf8(name))); 221 for (final Integer numPairs : nestPairN) { 222 nestpair_N.add(numPairs.intValue()); 223 numBackwardsCalls += numPairs.intValue(); 224 } 225 } 226 227 /** 228 * Returns true if any annotations have been added to this set of bands. 229 * 230 * @return true if any annotations have been added to this set of bands. 231 */ 232 public boolean hasContent() { 233 return type_RS.size() > 0; 234 } 235 236 public void incrementAnnoN() { 237 anno_N.increment(anno_N.size() - 1); 238 } 239 240 public void newEntryInAnnoN() { 241 anno_N.add(1); 242 } 243 244 private String nextString(final Iterator<Object> valuesIterator) { 245 return (String) valuesIterator.next(); 246 } 247 248 public int numBackwardsCalls() { 249 return numBackwardsCalls; 250 } 251 252 /* 253 * (non-Javadoc) 254 * 255 * @see org.apache.commons.compress.harmony.pack200.BandSet#pack(java.io.OutputStream) 256 */ 257 @Override 258 public void pack(final OutputStream out) throws IOException, Pack200Exception { 259 PackingUtils.log("Writing metadata band group..."); 260 if (hasContent()) { 261 final String contextStr; 262 if (context == CONTEXT_CLASS) { 263 contextStr = "Class"; 264 } else if (context == CONTEXT_FIELD) { 265 contextStr = "Field"; 266 } else { 267 contextStr = "Method"; 268 } 269 byte[] encodedBand; 270 if (!type.equals("AD")) { 271 if (type.indexOf('P') != -1) { 272 // Parameter annotation so we need to transmit param_NB 273 encodedBand = encodeBandInt(contextStr + "_" + type + " param_NB", param_NB.toArray(), Codec.BYTE1); 274 out.write(encodedBand); 275 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " anno_N[" + param_NB.size() + "]"); 276 } 277 encodedBand = encodeBandInt(contextStr + "_" + type + " anno_N", anno_N.toArray(), Codec.UNSIGNED5); 278 out.write(encodedBand); 279 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " anno_N[" + anno_N.size() + "]"); 280 281 encodedBand = encodeBandInt(contextStr + "_" + type + " type_RS", cpEntryListToArray(type_RS), Codec.UNSIGNED5); 282 out.write(encodedBand); 283 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " type_RS[" + type_RS.size() + "]"); 284 285 encodedBand = encodeBandInt(contextStr + "_" + type + " pair_N", pair_N.toArray(), Codec.UNSIGNED5); 286 out.write(encodedBand); 287 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " pair_N[" + pair_N.size() + "]"); 288 289 encodedBand = encodeBandInt(contextStr + "_" + type + " name_RU", cpEntryListToArray(name_RU), Codec.UNSIGNED5); 290 out.write(encodedBand); 291 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " name_RU[" + name_RU.size() + "]"); 292 } 293 encodedBand = encodeBandInt(contextStr + "_" + type + " T", tagListToArray(T), Codec.BYTE1); 294 out.write(encodedBand); 295 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " T[" + T.size() + "]"); 296 297 encodedBand = encodeBandInt(contextStr + "_" + type + " caseI_KI", cpEntryListToArray(caseI_KI), Codec.UNSIGNED5); 298 out.write(encodedBand); 299 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseI_KI[" + caseI_KI.size() + "]"); 300 301 encodedBand = encodeBandInt(contextStr + "_" + type + " caseD_KD", cpEntryListToArray(caseD_KD), Codec.UNSIGNED5); 302 out.write(encodedBand); 303 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseD_KD[" + caseD_KD.size() + "]"); 304 305 encodedBand = encodeBandInt(contextStr + "_" + type + " caseF_KF", cpEntryListToArray(caseF_KF), Codec.UNSIGNED5); 306 out.write(encodedBand); 307 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseF_KF[" + caseF_KF.size() + "]"); 308 309 encodedBand = encodeBandInt(contextStr + "_" + type + " caseJ_KJ", cpEntryListToArray(caseJ_KJ), Codec.UNSIGNED5); 310 out.write(encodedBand); 311 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseJ_KJ[" + caseJ_KJ.size() + "]"); 312 313 encodedBand = encodeBandInt(contextStr + "_" + type + " casec_RS", cpEntryListToArray(casec_RS), Codec.UNSIGNED5); 314 out.write(encodedBand); 315 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casec_RS[" + casec_RS.size() + "]"); 316 317 encodedBand = encodeBandInt(contextStr + "_" + type + " caseet_RS", cpEntryListToArray(caseet_RS), Codec.UNSIGNED5); 318 out.write(encodedBand); 319 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseet_RS[" + caseet_RS.size() + "]"); 320 321 encodedBand = encodeBandInt(contextStr + "_" + type + " caseec_RU", cpEntryListToArray(caseec_RU), Codec.UNSIGNED5); 322 out.write(encodedBand); 323 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseec_RU[" + caseec_RU.size() + "]"); 324 325 encodedBand = encodeBandInt(contextStr + "_" + type + " cases_RU", cpEntryListToArray(cases_RU), Codec.UNSIGNED5); 326 out.write(encodedBand); 327 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " cases_RU[" + cases_RU.size() + "]"); 328 329 encodedBand = encodeBandInt(contextStr + "_" + type + " casearray_N", casearray_N.toArray(), Codec.UNSIGNED5); 330 out.write(encodedBand); 331 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casearray_N[" + casearray_N.size() + "]"); 332 333 encodedBand = encodeBandInt(contextStr + "_" + type + " nesttype_RS", cpEntryListToArray(nesttype_RS), Codec.UNSIGNED5); 334 out.write(encodedBand); 335 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nesttype_RS[" + nesttype_RS.size() + "]"); 336 337 encodedBand = encodeBandInt(contextStr + "_" + type + " nestpair_N", nestpair_N.toArray(), Codec.UNSIGNED5); 338 out.write(encodedBand); 339 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestpair_N[" + nestpair_N.size() + "]"); 340 341 encodedBand = encodeBandInt(contextStr + "_" + type + " nestname_RU", cpEntryListToArray(nestname_RU), Codec.UNSIGNED5); 342 out.write(encodedBand); 343 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestname_RU[" + nestname_RU.size() + "]"); 344 } 345 } 346 347 /** 348 * Remove the latest annotation that was added to this group 349 */ 350 public void removeLatest() { 351 final int latest = anno_N.remove(anno_N.size() - 1); 352 for (int i = 0; i < latest; i++) { 353 type_RS.remove(type_RS.size() - 1); 354 final int pairs = pair_N.remove(pair_N.size() - 1); 355 for (int j = 0; j < pairs; j++) { 356 removeOnePair(); 357 } 358 } 359 } 360 361 /* 362 * Convenience method for removeLatest 363 */ 364 private void removeOnePair() { 365 final String tag = T.remove(T.size() - 1); 366 switch (tag) { 367 case "B": 368 case "C": 369 case "I": 370 case "S": 371 case "Z": 372 caseI_KI.remove(caseI_KI.size() - 1); 373 break; 374 case "D": 375 caseD_KD.remove(caseD_KD.size() - 1); 376 break; 377 case "F": 378 caseF_KF.remove(caseF_KF.size() - 1); 379 break; 380 case "J": 381 caseJ_KJ.remove(caseJ_KJ.size() - 1); 382 break; 383 case "e": 384 caseet_RS.remove(caseet_RS.size() - 1); 385 caseec_RU.remove(caseet_RS.size() - 1); 386 break; 387 case "s": 388 cases_RU.remove(cases_RU.size() - 1); 389 break; 390 case "[": 391 final int arraySize = casearray_N.remove(casearray_N.size() - 1); 392 numBackwardsCalls -= arraySize; 393 for (int k = 0; k < arraySize; k++) { 394 removeOnePair(); 395 } 396 break; 397 case "@": 398 nesttype_RS.remove(nesttype_RS.size() - 1); 399 final int numPairs = nestpair_N.remove(nestpair_N.size() - 1); 400 numBackwardsCalls -= numPairs; 401 for (int i = 0; i < numPairs; i++) { 402 removeOnePair(); 403 } 404 break; 405 } 406 } 407 408 private int[] tagListToArray(final List<String> list) { 409 return list.stream().mapToInt(s -> s.charAt(0)).toArray(); 410 } 411 412}