001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. 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, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.compress.harmony.unpack200; 018 019import org.apache.commons.compress.harmony.pack200.Codec; 020import org.apache.commons.compress.harmony.pack200.Pack200Exception; 021import org.apache.commons.compress.harmony.unpack200.bytecode.ClassFileEntry; 022 023/** 024 * AttributeLayout defines a layout that describes how an attribute will be transmitted. 025 */ 026public class AttributeLayout implements IMatcher { 027 028 /** 029 * {@value} 030 */ 031 public static final String ACC_ABSTRACT = "ACC_ABSTRACT"; //$NON-NLS-1$ 032 033 /** 034 * {@value} 035 */ 036 public static final String ACC_ANNOTATION = "ACC_ANNOTATION"; //$NON-NLS-1$ 037 038 /** 039 * {@value} 040 */ 041 public static final String ACC_ENUM = "ACC_ENUM"; //$NON-NLS-1$ 042 043 /** 044 * {@value} 045 */ 046 public static final String ACC_FINAL = "ACC_FINAL"; //$NON-NLS-1$ 047 048 /** 049 * {@value} 050 */ 051 public static final String ACC_INTERFACE = "ACC_INTERFACE"; //$NON-NLS-1$ 052 053 /** 054 * {@value} 055 */ 056 public static final String ACC_NATIVE = "ACC_NATIVE"; //$NON-NLS-1$ 057 058 /** 059 * {@value} 060 */ 061 public static final String ACC_PRIVATE = "ACC_PRIVATE"; //$NON-NLS-1$ 062 063 /** 064 * {@value} 065 */ 066 public static final String ACC_PROTECTED = "ACC_PROTECTED"; //$NON-NLS-1$ 067 068 /** 069 * {@value} 070 */ 071 public static final String ACC_PUBLIC = "ACC_PUBLIC"; //$NON-NLS-1$ 072 073 /** 074 * {@value} 075 */ 076 public static final String ACC_STATIC = "ACC_STATIC"; //$NON-NLS-1$ 077 078 /** 079 * {@value} 080 */ 081 public static final String ACC_STRICT = "ACC_STRICT"; //$NON-NLS-1$ 082 083 /** 084 * {@value} 085 */ 086 public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED"; //$NON-NLS-1$ 087 088 /** 089 * {@value} 090 */ 091 public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; //$NON-NLS-1$ 092 093 /** 094 * {@value} 095 */ 096 public static final String ACC_TRANSIENT = "ACC_TRANSIENT"; //$NON-NLS-1$ 097 098 /** 099 * {@value} 100 */ 101 public static final String ACC_VOLATILE = "ACC_VOLATILE"; //$NON-NLS-1$ 102 103 /** 104 * {@value} 105 */ 106 public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; //$NON-NLS-1$ 107 108 /** 109 * {@value} 110 */ 111 public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; //$NON-NLS-1$ 112 113 /** 114 * {@value} 115 */ 116 public static final String ATTRIBUTE_CODE = "Code"; //$NON-NLS-1$ 117 118 /** 119 * {@value} 120 */ 121 public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; //$NON-NLS-1$ 122 123 /** 124 * {@value} 125 */ 126 public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; //$NON-NLS-1$ 127 128 /** 129 * {@value} 130 */ 131 132 /** 133 * {@value} 134 */ 135 public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; //$NON-NLS-1$ 136 137 /** 138 * {@value} 139 */ 140 public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; //$NON-NLS-1$ 141 142 /** 143 * {@value} 144 */ 145 public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; //$NON-NLS-1$ 146 147 /** 148 * {@value} 149 */ 150 public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; //$NON-NLS-1$ 151 152 /** 153 * {@value} 154 */ 155 public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; //$NON-NLS-1$ 156 157 /** 158 * {@value} 159 */ 160 public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; //$NON-NLS-1$ 161 162 /** 163 * {@value} 164 */ 165 public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; //$NON-NLS-1$ 166 167 /** 168 * {@value} 169 */ 170 public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; //$NON-NLS-1$ 171 172 /** 173 * {@value} 174 */ 175 public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; //$NON-NLS-1$ 176 177 /** 178 * {@value} 179 */ 180 public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; //$NON-NLS-1$ 181 182 /** 183 * {@value} 184 */ 185 public static final String ATTRIBUTE_SIGNATURE = "Signature"; //$NON-NLS-1$ 186 187 /** 188 * {@value} 189 */ 190 public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; //$NON-NLS-1$ 191 192 /** 193 * {@value} 194 */ 195 public static final int CONTEXT_CLASS = 0; 196 197 /** 198 * {@value} 199 */ 200 public static final int CONTEXT_CODE = 3; 201 202 /** 203 * {@value} 204 */ 205 public static final int CONTEXT_FIELD = 1; 206 207 /** 208 * {@value} 209 */ 210 public static final int CONTEXT_METHOD = 2; 211 212 /** 213 * Context names. 214 */ 215 public static final String[] contextNames = {"Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 216 "Code",}; //$NON-NLS-1$ 217 218 private static ClassFileEntry getValue(final String layout, long value, final SegmentConstantPool pool) 219 throws Pack200Exception { 220 if (layout.startsWith("R")) { //$NON-NLS-1$ 221 // references 222 if (layout.indexOf('N') != -1) { 223 value--; 224 } 225 if (layout.startsWith("RU")) { //$NON-NLS-1$ 226 return pool.getValue(SegmentConstantPool.UTF_8, value); 227 } 228 if (layout.startsWith("RS")) { //$NON-NLS-1$ 229 return pool.getValue(SegmentConstantPool.SIGNATURE, value); 230 } 231 } else if (layout.startsWith("K")) { //$NON-NLS-1$ 232 final char type = layout.charAt(1); 233 switch (type) { 234 case 'S': // String 235 return pool.getValue(SegmentConstantPool.CP_STRING, value); 236 case 'I': // Int (or byte or short) 237 case 'C': // Char 238 return pool.getValue(SegmentConstantPool.CP_INT, value); 239 case 'F': // Float 240 return pool.getValue(SegmentConstantPool.CP_FLOAT, value); 241 case 'J': // Long 242 return pool.getValue(SegmentConstantPool.CP_LONG, value); 243 case 'D': // Double 244 return pool.getValue(SegmentConstantPool.CP_DOUBLE, value); 245 } 246 } 247 throw new Pack200Exception("Unknown layout encoding: " + layout); 248 } 249 250 private final int context; 251 252 private final int index; 253 254 private final String layout; 255 256 private long mask; 257 258 private final String name; 259 private final boolean isDefault; 260 private int backwardsCallCount; 261 262 /** 263 * Constructs a default AttributeLayout (equivalent to 264 * {@code new AttributeLayout(name, context, layout, index, true);}) 265 * 266 * @param name TODO 267 * @param context TODO 268 * @param layout TODO 269 * @param index TODO 270 * @throws Pack200Exception Attribute context out of range. 271 * @throws Pack200Exception Cannot have a null layout. 272 * @throws Pack200Exception Cannot have an unnamed layout. 273 */ 274 public AttributeLayout(final String name, final int context, final String layout, final int index) 275 throws Pack200Exception { 276 this(name, context, layout, index, true); 277 } 278 279 public AttributeLayout(final String name, final int context, final String layout, final int index, 280 final boolean isDefault) throws Pack200Exception { 281 this.index = index; 282 this.context = context; 283 if (index >= 0) { 284 this.mask = 1L << index; 285 } else { 286 this.mask = 0; 287 } 288 if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD 289 && context != CONTEXT_METHOD) { 290 throw new Pack200Exception("Attribute context out of range: " + context); 291 } 292 if (layout == null) { 293 throw new Pack200Exception("Cannot have a null layout"); 294 } 295 if (name == null || name.length() == 0) { 296 throw new Pack200Exception("Cannot have an unnamed layout"); 297 } 298 this.name = name; 299 this.layout = layout; 300 this.isDefault = isDefault; 301 } 302 303 public Codec getCodec() { 304 if (layout.indexOf('O') >= 0) { 305 return Codec.BRANCH5; 306 } 307 if (layout.indexOf('P') >= 0) { 308 return Codec.BCI5; 309 } 310 if (layout.indexOf('S') >= 0 && layout.indexOf("KS") < 0 //$NON-NLS-1$ 311 && layout.indexOf("RS") < 0) { //$NON-NLS-1$ 312 return Codec.SIGNED5; 313 } 314 if (layout.indexOf('B') >= 0) { 315 return Codec.BYTE1; 316 } 317 return Codec.UNSIGNED5; 318 } 319 320 public int getContext() { 321 return context; 322 } 323 324 public int getIndex() { 325 return index; 326 } 327 328 public String getLayout() { 329 return layout; 330 } 331 332 public String getName() { 333 return name; 334 } 335 336 public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception { 337 return getValue(layout, value, pool); 338 } 339 340 public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool) 341 throws Pack200Exception { 342 // TODO This really needs to be better tested, esp. the different types 343 // TODO This should have the ability to deal with RUN stuff too, and 344 // unions 345 if (!layout.startsWith("KQ")) { 346 return getValue(layout, value, pool); 347 } 348 if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$ 349 return getValue("KS", value, pool); 350 } 351 return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$ 352 pool); 353 } 354 355 @Override 356 public int hashCode() { 357 final int PRIME = 31; 358 int r = 1; 359 if (name != null) { 360 r = r * PRIME + name.hashCode(); 361 } 362 if (layout != null) { 363 r = r * PRIME + layout.hashCode(); 364 } 365 r = r * PRIME + index; 366 r = r * PRIME + context; 367 return r; 368 } 369 370 public boolean isDefaultLayout() { 371 return isDefault; 372 } 373 374 /* 375 * (non-Javadoc) 376 * 377 * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long) 378 */ 379 @Override 380 public boolean matches(final long value) { 381 return (value & mask) != 0; 382 } 383 384 public int numBackwardsCallables() { 385 if ("*".equals(layout)) { 386 return 1; 387 } 388 return backwardsCallCount; 389 } 390 391 public void setBackwardsCallCount(final int backwardsCallCount) { 392 this.backwardsCallCount = backwardsCallCount; 393 } 394 395 @Override 396 public String toString() { 397 return contextNames[context] + ": " + name; 398 } 399 400}