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