001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with this 004 * work for additional information regarding copyright ownership. The ASF 005 * licenses this file to You under the Apache License, Version 2.0 (the 006 * "License"); you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 013 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 014 * License for the specific language governing permissions and limitations under 015 * the License. 016 */ 017package org.apache.commons.compress.harmony.pack200; 018 019import java.io.IOException; 020import java.io.OutputStream; 021import java.util.ArrayList; 022import java.util.Iterator; 023import java.util.List; 024 025/** 026 * A group of metadata (annotation) bands, such as class_RVA_bands, method_AD_bands etc. 027 */ 028public class MetadataBandGroup extends BandSet { 029 030 public static final int CONTEXT_CLASS = 0; 031 public static final int CONTEXT_FIELD = 1; 032 public static final int CONTEXT_METHOD = 2; 033 034 private final String type; 035 private int numBackwardsCalls; 036 037 public IntList param_NB = new IntList(); // TODO: Lazy instantiation? 038 public IntList anno_N = new IntList(); 039 public List<CPSignature> type_RS = new ArrayList<>(); 040 public IntList pair_N = new IntList(); 041 public List<CPUTF8> name_RU = new ArrayList<>(); 042 public List<String> T = new ArrayList<>(); 043 public List<CPConstant<?>> caseI_KI = new ArrayList<>(); 044 public List<CPConstant<?>> caseD_KD = new ArrayList<>(); 045 public List<CPConstant<?>> caseF_KF = new ArrayList<>(); 046 public List<CPConstant<?>> caseJ_KJ = new ArrayList<>(); 047 public List<CPSignature> casec_RS = new ArrayList<>(); 048 public List<CPSignature> caseet_RS = new ArrayList<>(); 049 public List<CPUTF8> caseec_RU = new ArrayList<>(); 050 public List<CPUTF8> cases_RU = new ArrayList<>(); 051 public IntList casearray_N = new IntList(); 052 public List<CPSignature> nesttype_RS = new ArrayList<>(); 053 public IntList nestpair_N = new IntList(); 054 public List<CPUTF8> nestname_RU = new ArrayList<>(); 055 056 private final CpBands cpBands; 057 private final int context; 058 059 /** 060 * Constructs a new MetadataBandGroup 061 * 062 * @param type must be either AD, RVA, RIA, RVPA or RIPA. 063 * @param context {@code CONTEXT_CLASS}, {@code CONTEXT_METHOD} or {@code CONTEXT_FIELD} 064 * @param cpBands constant pool bands 065 * @param segmentHeader segment header 066 * @param effort packing effort 067 */ 068 public MetadataBandGroup(final String type, final int context, final CpBands cpBands, 069 final SegmentHeader segmentHeader, final int effort) { 070 super(effort, segmentHeader); 071 this.type = type; 072 this.cpBands = cpBands; 073 this.context = context; 074 } 075 076 /** 077 * Add an annotation to this set of bands 078 * 079 * @param desc TODO 080 * @param nameRU TODO 081 * @param tags TODO 082 * @param values TODO 083 * @param caseArrayN TODO 084 * @param nestTypeRS TODO 085 * @param nestNameRU TODO 086 * @param nestPairN TODO 087 */ 088 public void addAnnotation(final String desc, final List<String> nameRU, final List<String> tags, 089 final List<Object> values, final List<Integer> caseArrayN, final List<String> nestTypeRS, 090 final List<String> nestNameRU, final List<Integer> nestPairN) { 091 type_RS.add(cpBands.getCPSignature(desc)); 092 pair_N.add(nameRU.size()); 093 nameRU.forEach(name -> name_RU.add(cpBands.getCPUtf8(name))); 094 095 final Iterator<Object> valuesIterator = values.iterator(); 096 for (final String tag : tags) { 097 T.add(tag); 098 switch (tag) { 099 case "B": 100 case "C": 101 case "I": 102 case "S": 103 case "Z": { 104 caseI_KI.add(cpBands.getConstant(valuesIterator.next())); 105 break; 106 } 107 case "D": { 108 caseD_KD.add(cpBands.getConstant(valuesIterator.next())); 109 break; 110 } 111 case "F": { 112 caseF_KF.add(cpBands.getConstant(valuesIterator.next())); 113 break; 114 } 115 case "J": { 116 caseJ_KJ.add(cpBands.getConstant(valuesIterator.next())); 117 break; 118 } 119 case "c": { 120 casec_RS.add(cpBands.getCPSignature(nextString(valuesIterator))); 121 break; 122 } 123 case "e": { 124 caseet_RS.add(cpBands.getCPSignature(nextString(valuesIterator))); 125 caseec_RU.add(cpBands.getCPUtf8(nextString(valuesIterator))); 126 break; 127 } 128 case "s": { 129 cases_RU.add(cpBands.getCPUtf8(nextString(valuesIterator))); 130 break; 131 } 132 } 133 // do nothing here for [ or @ (handled below) 134 } 135 for (final Integer element : caseArrayN) { 136 final int arraySize = element.intValue(); 137 casearray_N.add(arraySize); 138 numBackwardsCalls += arraySize; 139 } 140 nestTypeRS.forEach(element -> nesttype_RS.add(cpBands.getCPSignature(element))); 141 nestNameRU.forEach(element -> nestname_RU.add(cpBands.getCPUtf8(element))); 142 for (final Integer numPairs : nestPairN) { 143 nestpair_N.add(numPairs.intValue()); 144 numBackwardsCalls += numPairs.intValue(); 145 } 146 } 147 148 /** 149 * Add an annotation to this set of bands. 150 * 151 * @param numParams TODO 152 * @param annoN TODO 153 * @param pairN TODO 154 * @param typeRS TODO 155 * @param nameRU TODO 156 * @param tags TODO 157 * @param values TODO 158 * @param caseArrayN TODO 159 * @param nestTypeRS TODO 160 * @param nestNameRU TODO 161 * @param nestPairN TODO 162 */ 163 public void addParameterAnnotation(final int numParams, final int[] annoN, final IntList pairN, 164 final List<String> typeRS, final List<String> nameRU, final List<String> tags, final List<Object> values, 165 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 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 276 + " anno_N[" + param_NB.size() + "]"); 277 } 278 encodedBand = encodeBandInt(contextStr + "_" + type + " anno_N", anno_N.toArray(), Codec.UNSIGNED5); 279 out.write(encodedBand); 280 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " anno_N[" 281 + anno_N.size() + "]"); 282 283 encodedBand = encodeBandInt(contextStr + "_" + type + " type_RS", cpEntryListToArray(type_RS), 284 Codec.UNSIGNED5); 285 out.write(encodedBand); 286 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " type_RS[" 287 + type_RS.size() + "]"); 288 289 encodedBand = encodeBandInt(contextStr + "_" + type + " pair_N", pair_N.toArray(), Codec.UNSIGNED5); 290 out.write(encodedBand); 291 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " pair_N[" 292 + pair_N.size() + "]"); 293 294 encodedBand = encodeBandInt(contextStr + "_" + type + " name_RU", cpEntryListToArray(name_RU), 295 Codec.UNSIGNED5); 296 out.write(encodedBand); 297 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " name_RU[" 298 + name_RU.size() + "]"); 299 } 300 encodedBand = encodeBandInt(contextStr + "_" + type + " T", tagListToArray(T), Codec.BYTE1); 301 out.write(encodedBand); 302 PackingUtils 303 .log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " T[" + T.size() + "]"); 304 305 encodedBand = encodeBandInt(contextStr + "_" + type + " caseI_KI", cpEntryListToArray(caseI_KI), 306 Codec.UNSIGNED5); 307 out.write(encodedBand); 308 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseI_KI[" 309 + caseI_KI.size() + "]"); 310 311 encodedBand = encodeBandInt(contextStr + "_" + type + " caseD_KD", cpEntryListToArray(caseD_KD), 312 Codec.UNSIGNED5); 313 out.write(encodedBand); 314 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseD_KD[" 315 + caseD_KD.size() + "]"); 316 317 encodedBand = encodeBandInt(contextStr + "_" + type + " caseF_KF", cpEntryListToArray(caseF_KF), 318 Codec.UNSIGNED5); 319 out.write(encodedBand); 320 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseF_KF[" 321 + caseF_KF.size() + "]"); 322 323 encodedBand = encodeBandInt(contextStr + "_" + type + " caseJ_KJ", cpEntryListToArray(caseJ_KJ), 324 Codec.UNSIGNED5); 325 out.write(encodedBand); 326 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseJ_KJ[" 327 + caseJ_KJ.size() + "]"); 328 329 encodedBand = encodeBandInt(contextStr + "_" + type + " casec_RS", cpEntryListToArray(casec_RS), 330 Codec.UNSIGNED5); 331 out.write(encodedBand); 332 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casec_RS[" 333 + casec_RS.size() + "]"); 334 335 encodedBand = encodeBandInt(contextStr + "_" + type + " caseet_RS", cpEntryListToArray(caseet_RS), 336 Codec.UNSIGNED5); 337 out.write(encodedBand); 338 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseet_RS[" 339 + caseet_RS.size() + "]"); 340 341 encodedBand = encodeBandInt(contextStr + "_" + type + " caseec_RU", cpEntryListToArray(caseec_RU), 342 Codec.UNSIGNED5); 343 out.write(encodedBand); 344 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " caseec_RU[" 345 + caseec_RU.size() + "]"); 346 347 encodedBand = encodeBandInt(contextStr + "_" + type + " cases_RU", cpEntryListToArray(cases_RU), 348 Codec.UNSIGNED5); 349 out.write(encodedBand); 350 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " cases_RU[" 351 + cases_RU.size() + "]"); 352 353 encodedBand = encodeBandInt(contextStr + "_" + type + " casearray_N", casearray_N.toArray(), 354 Codec.UNSIGNED5); 355 out.write(encodedBand); 356 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " casearray_N[" 357 + casearray_N.size() + "]"); 358 359 encodedBand = encodeBandInt(contextStr + "_" + type + " nesttype_RS", cpEntryListToArray(nesttype_RS), 360 Codec.UNSIGNED5); 361 out.write(encodedBand); 362 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nesttype_RS[" 363 + nesttype_RS.size() + "]"); 364 365 encodedBand = encodeBandInt(contextStr + "_" + type + " nestpair_N", nestpair_N.toArray(), Codec.UNSIGNED5); 366 out.write(encodedBand); 367 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestpair_N[" 368 + nestpair_N.size() + "]"); 369 370 encodedBand = encodeBandInt(contextStr + "_" + type + " nestname_RU", cpEntryListToArray(nestname_RU), 371 Codec.UNSIGNED5); 372 out.write(encodedBand); 373 PackingUtils.log("Wrote " + encodedBand.length + " bytes from " + contextStr + "_" + type + " nestname_RU[" 374 + nestname_RU.size() + "]"); 375 } 376 } 377 378 /** 379 * Remove the latest annotation that was added to this group 380 */ 381 public void removeLatest() { 382 final int latest = anno_N.remove(anno_N.size() - 1); 383 for (int i = 0; i < latest; i++) { 384 type_RS.remove(type_RS.size() - 1); 385 final int pairs = pair_N.remove(pair_N.size() - 1); 386 for (int j = 0; j < pairs; j++) { 387 removeOnePair(); 388 } 389 } 390 } 391 392 /* 393 * Convenience method for removeLatest 394 */ 395 private void removeOnePair() { 396 final String tag = T.remove(T.size() - 1); 397 switch (tag) { 398 case "B": 399 case "C": 400 case "I": 401 case "S": 402 case "Z": 403 caseI_KI.remove(caseI_KI.size() - 1); 404 break; 405 case "D": 406 caseD_KD.remove(caseD_KD.size() - 1); 407 break; 408 case "F": 409 caseF_KF.remove(caseF_KF.size() - 1); 410 break; 411 case "J": 412 caseJ_KJ.remove(caseJ_KJ.size() - 1); 413 break; 414 case "e": 415 caseet_RS.remove(caseet_RS.size() - 1); 416 caseec_RU.remove(caseet_RS.size() - 1); 417 break; 418 case "s": 419 cases_RU.remove(cases_RU.size() - 1); 420 break; 421 case "[": 422 final int arraySize = casearray_N.remove(casearray_N.size() - 1); 423 numBackwardsCalls -= arraySize; 424 for (int k = 0; k < arraySize; k++) { 425 removeOnePair(); 426 } 427 break; 428 case "@": 429 nesttype_RS.remove(nesttype_RS.size() - 1); 430 final int numPairs = nestpair_N.remove(nestpair_N.size() - 1); 431 numBackwardsCalls -= numPairs; 432 for (int i = 0; i < numPairs; i++) { 433 removeOnePair(); 434 } 435 break; 436 } 437 } 438 439 private int[] tagListToArray(final List<String> list) { 440 return list.stream().mapToInt(s -> s.charAt(0)).toArray(); 441 } 442 443}