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) throws Pack200Exception { 219 if (layout.startsWith("R")) { //$NON-NLS-1$ 220 // references 221 if (layout.indexOf('N') != -1) { 222 value--; 223 } 224 if (layout.startsWith("RU")) { //$NON-NLS-1$ 225 return pool.getValue(SegmentConstantPool.UTF_8, value); 226 } 227 if (layout.startsWith("RS")) { //$NON-NLS-1$ 228 return pool.getValue(SegmentConstantPool.SIGNATURE, value); 229 } 230 } else if (layout.startsWith("K")) { //$NON-NLS-1$ 231 final char type = layout.charAt(1); 232 switch (type) { 233 case 'S': // String 234 return pool.getValue(SegmentConstantPool.CP_STRING, value); 235 case 'I': // Int (or byte or short) 236 case 'C': // Char 237 return pool.getValue(SegmentConstantPool.CP_INT, value); 238 case 'F': // Float 239 return pool.getValue(SegmentConstantPool.CP_FLOAT, value); 240 case 'J': // Long 241 return pool.getValue(SegmentConstantPool.CP_LONG, value); 242 case 'D': // Double 243 return pool.getValue(SegmentConstantPool.CP_DOUBLE, value); 244 } 245 } 246 throw new Pack200Exception("Unknown layout encoding: " + layout); 247 } 248 249 private final int context; 250 251 private final int index; 252 253 private final String layout; 254 255 private long mask; 256 257 private final String name; 258 private final boolean isDefault; 259 private int backwardsCallCount; 260 261 /** 262 * Constructs a default AttributeLayout (equivalent to {@code new AttributeLayout(name, context, layout, index, true);}) 263 * 264 * @param name TODO 265 * @param context TODO 266 * @param layout TODO 267 * @param index TODO 268 * @throws Pack200Exception Attribute context out of range. 269 * @throws Pack200Exception Cannot have a null layout. 270 * @throws Pack200Exception Cannot have an unnamed layout. 271 */ 272 public AttributeLayout(final String name, final int context, final String layout, final int index) throws Pack200Exception { 273 this(name, context, layout, index, true); 274 } 275 276 public AttributeLayout(final String name, final int context, final String layout, final int index, final boolean isDefault) throws Pack200Exception { 277 this.index = index; 278 this.context = context; 279 if (index >= 0) { 280 this.mask = 1L << index; 281 } else { 282 this.mask = 0; 283 } 284 if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD && context != CONTEXT_METHOD) { 285 throw new Pack200Exception("Attribute context out of range: " + context); 286 } 287 if (layout == null) { 288 throw new Pack200Exception("Cannot have a null layout"); 289 } 290 if (name == null || name.length() == 0) { 291 throw new Pack200Exception("Cannot have an unnamed layout"); 292 } 293 this.name = name; 294 this.layout = layout; 295 this.isDefault = isDefault; 296 } 297 298 public Codec getCodec() { 299 if (layout.indexOf('O') >= 0) { 300 return Codec.BRANCH5; 301 } 302 if (layout.indexOf('P') >= 0) { 303 return Codec.BCI5; 304 } 305 if (layout.indexOf('S') >= 0 && !layout.contains("KS") //$NON-NLS-1$ 306 && !layout.contains("RS")) { //$NON-NLS-1$ 307 return Codec.SIGNED5; 308 } 309 if (layout.indexOf('B') >= 0) { 310 return Codec.BYTE1; 311 } 312 return Codec.UNSIGNED5; 313 } 314 315 public int getContext() { 316 return context; 317 } 318 319 public int getIndex() { 320 return index; 321 } 322 323 public String getLayout() { 324 return layout; 325 } 326 327 public String getName() { 328 return name; 329 } 330 331 public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception { 332 return getValue(layout, value, pool); 333 } 334 335 public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool) throws Pack200Exception { 336 // TODO This really needs to be better tested, esp. the different types 337 // TODO This should have the ability to deal with RUN stuff too, and 338 // unions 339 if (!layout.startsWith("KQ")) { 340 return getValue(layout, value, pool); 341 } 342 if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$ 343 return getValue("KS", value, pool); 344 } 345 return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$ 346 pool); 347 } 348 349 @Override 350 public int hashCode() { 351 final int PRIME = 31; 352 int r = 1; 353 if (name != null) { 354 r = r * PRIME + name.hashCode(); 355 } 356 if (layout != null) { 357 r = r * PRIME + layout.hashCode(); 358 } 359 r = r * PRIME + index; 360 r = r * PRIME + context; 361 return r; 362 } 363 364 public boolean isDefaultLayout() { 365 return isDefault; 366 } 367 368 /* 369 * (non-Javadoc) 370 * 371 * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long) 372 */ 373 @Override 374 public boolean matches(final long value) { 375 return (value & mask) != 0; 376 } 377 378 public int numBackwardsCallables() { 379 if ("*".equals(layout)) { 380 return 1; 381 } 382 return backwardsCallCount; 383 } 384 385 public void setBackwardsCallCount(final int backwardsCallCount) { 386 this.backwardsCallCount = backwardsCallCount; 387 } 388 389 @Override 390 public String toString() { 391 return contextNames[context] + ": " + name; 392 } 393 394}