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 public static final String ACC_ABSTRACT = "ACC_ABSTRACT"; //$NON-NLS-1$ 029 public static final String ACC_ANNOTATION = "ACC_ANNOTATION"; //$NON-NLS-1$ 030 public static final String ACC_ENUM = "ACC_ENUM"; //$NON-NLS-1$ 031 public static final String ACC_FINAL = "ACC_FINAL"; //$NON-NLS-1$ 032 public static final String ACC_INTERFACE = "ACC_INTERFACE"; //$NON-NLS-1$ 033 public static final String ACC_NATIVE = "ACC_NATIVE"; //$NON-NLS-1$ 034 public static final String ACC_PRIVATE = "ACC_PRIVATE"; //$NON-NLS-1$ 035 public static final String ACC_PROTECTED = "ACC_PROTECTED"; //$NON-NLS-1$ 036 public static final String ACC_PUBLIC = "ACC_PUBLIC"; //$NON-NLS-1$ 037 public static final String ACC_STATIC = "ACC_STATIC"; //$NON-NLS-1$ 038 public static final String ACC_STRICT = "ACC_STRICT"; //$NON-NLS-1$ 039 public static final String ACC_SYNCHRONIZED = "ACC_SYNCHRONIZED"; //$NON-NLS-1$ 040 public static final String ACC_SYNTHETIC = "ACC_SYNTHETIC"; //$NON-NLS-1$ 041 public static final String ACC_TRANSIENT = "ACC_TRANSIENT"; //$NON-NLS-1$ 042 public static final String ACC_VOLATILE = "ACC_VOLATILE"; //$NON-NLS-1$ 043 public static final String ATTRIBUTE_ANNOTATION_DEFAULT = "AnnotationDefault"; //$NON-NLS-1$ 044 public static final String ATTRIBUTE_CLASS_FILE_VERSION = "class-file version"; //$NON-NLS-1$ 045 public static final String ATTRIBUTE_CODE = "Code"; //$NON-NLS-1$ 046 public static final String ATTRIBUTE_CONSTANT_VALUE = "ConstantValue"; //$NON-NLS-1$ 047 public static final String ATTRIBUTE_DEPRECATED = "Deprecated"; //$NON-NLS-1$ 048 public static final String ATTRIBUTE_ENCLOSING_METHOD = "EnclosingMethod"; //$NON-NLS-1$ 049 public static final String ATTRIBUTE_EXCEPTIONS = "Exceptions"; //$NON-NLS-1$ 050 public static final String ATTRIBUTE_INNER_CLASSES = "InnerClasses"; //$NON-NLS-1$ 051 public static final String ATTRIBUTE_LINE_NUMBER_TABLE = "LineNumberTable"; //$NON-NLS-1$ 052 public static final String ATTRIBUTE_LOCAL_VARIABLE_TABLE = "LocalVariableTable"; //$NON-NLS-1$ 053 public static final String ATTRIBUTE_LOCAL_VARIABLE_TYPE_TABLE = "LocalVariableTypeTable"; //$NON-NLS-1$ 054 public static final String ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations"; //$NON-NLS-1$ 055 public static final String ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS = "RuntimeInvisibleParameterAnnotations"; //$NON-NLS-1$ 056 public static final String ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS = "RuntimeVisibleAnnotations"; //$NON-NLS-1$ 057 public static final String ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS = "RuntimeVisibleParameterAnnotations"; //$NON-NLS-1$ 058 public static final String ATTRIBUTE_SIGNATURE = "Signature"; //$NON-NLS-1$ 059 public static final String ATTRIBUTE_SOURCE_FILE = "SourceFile"; //$NON-NLS-1$ 060 public static final int CONTEXT_CLASS = 0; 061 public static final int CONTEXT_CODE = 3; 062 public static final int CONTEXT_FIELD = 1; 063 public static final int CONTEXT_METHOD = 2; 064 public static final String[] contextNames = {"Class", "Field", "Method", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 065 "Code",}; //$NON-NLS-1$ 066 067 private static ClassFileEntry getValue(final String layout, long value, final SegmentConstantPool pool) 068 throws Pack200Exception { 069 if (layout.startsWith("R")) { //$NON-NLS-1$ 070 // references 071 if (layout.indexOf('N') != -1) { 072 value--; 073 } 074 if (layout.startsWith("RU")) { //$NON-NLS-1$ 075 return pool.getValue(SegmentConstantPool.UTF_8, value); 076 } 077 if (layout.startsWith("RS")) { //$NON-NLS-1$ 078 return pool.getValue(SegmentConstantPool.SIGNATURE, value); 079 } 080 } else if (layout.startsWith("K")) { //$NON-NLS-1$ 081 final char type = layout.charAt(1); 082 switch (type) { 083 case 'S': // String 084 return pool.getValue(SegmentConstantPool.CP_STRING, value); 085 case 'I': // Int (or byte or short) 086 case 'C': // Char 087 return pool.getValue(SegmentConstantPool.CP_INT, value); 088 case 'F': // Float 089 return pool.getValue(SegmentConstantPool.CP_FLOAT, value); 090 case 'J': // Long 091 return pool.getValue(SegmentConstantPool.CP_LONG, value); 092 case 'D': // Double 093 return pool.getValue(SegmentConstantPool.CP_DOUBLE, value); 094 } 095 } 096 throw new Pack200Exception("Unknown layout encoding: " + layout); 097 } 098 099 private final int context; 100 101 private final int index; 102 103 private final String layout; 104 105 private long mask; 106 107 private final String name; 108 private final boolean isDefault; 109 private int backwardsCallCount; 110 111 /** 112 * Construct a default AttributeLayout (equivalent to 113 * {@code new AttributeLayout(name, context, layout, index, true);}) 114 * 115 * @param name TODO 116 * @param context TODO 117 * @param layout TODO 118 * @param index TODO 119 * @throws Pack200Exception Attribute context out of range. 120 * @throws Pack200Exception Cannot have a null layout. 121 * @throws Pack200Exception Cannot have an unnamed layout. 122 */ 123 public AttributeLayout(final String name, final int context, final String layout, final int index) 124 throws Pack200Exception { 125 this(name, context, layout, index, true); 126 } 127 128 public AttributeLayout(final String name, final int context, final String layout, final int index, 129 final boolean isDefault) throws Pack200Exception { 130 super(); 131 this.index = index; 132 this.context = context; 133 if (index >= 0) { 134 this.mask = 1L << index; 135 } else { 136 this.mask = 0; 137 } 138 if (context != CONTEXT_CLASS && context != CONTEXT_CODE && context != CONTEXT_FIELD 139 && context != CONTEXT_METHOD) { 140 throw new Pack200Exception("Attribute context out of range: " + context); 141 } 142 if (layout == null) { 143 throw new Pack200Exception("Cannot have a null layout"); 144 } 145 if (name == null || name.length() == 0) { 146 throw new Pack200Exception("Cannot have an unnamed layout"); 147 } 148 this.name = name; 149 this.layout = layout; 150 this.isDefault = isDefault; 151 } 152 153 public Codec getCodec() { 154 if (layout.indexOf('O') >= 0) { 155 return Codec.BRANCH5; 156 } 157 if (layout.indexOf('P') >= 0) { 158 return Codec.BCI5; 159 } 160 if (layout.indexOf('S') >= 0 && layout.indexOf("KS") < 0 //$NON-NLS-1$ 161 && layout.indexOf("RS") < 0) { //$NON-NLS-1$ 162 return Codec.SIGNED5; 163 } 164 if (layout.indexOf('B') >= 0) { 165 return Codec.BYTE1; 166 } 167 return Codec.UNSIGNED5; 168 } 169 170 public String getLayout() { 171 return layout; 172 } 173 174 public ClassFileEntry getValue(final long value, final SegmentConstantPool pool) throws Pack200Exception { 175 return getValue(layout, value, pool); 176 } 177 178 public ClassFileEntry getValue(final long value, final String type, final SegmentConstantPool pool) 179 throws Pack200Exception { 180 // TODO This really needs to be better tested, esp. the different types 181 // TODO This should have the ability to deal with RUN stuff too, and 182 // unions 183 if (!layout.startsWith("KQ")) { 184 return getValue(layout, value, pool); 185 } 186 if (type.equals("Ljava/lang/String;")) { //$NON-NLS-1$ 187 return getValue("KS", value, pool); 188 } 189 return getValue("K" + type + layout.substring(2), value, //$NON-NLS-1$ 190 pool); 191 } 192 193 @Override 194 public int hashCode() { 195 final int PRIME = 31; 196 int r = 1; 197 if (name != null) { 198 r = r * PRIME + name.hashCode(); 199 } 200 if (layout != null) { 201 r = r * PRIME + layout.hashCode(); 202 } 203 r = r * PRIME + index; 204 r = r * PRIME + context; 205 return r; 206 } 207 208 /* 209 * (non-Javadoc) 210 * 211 * @see org.apache.commons.compress.harmony.unpack200.IMatches#matches(long) 212 */ 213 @Override 214 public boolean matches(final long value) { 215 return (value & mask) != 0; 216 } 217 218 @Override 219 public String toString() { 220 return contextNames[context] + ": " + name; 221 } 222 223 public int getContext() { 224 return context; 225 } 226 227 public int getIndex() { 228 return index; 229 } 230 231 public String getName() { 232 return name; 233 } 234 235 public int numBackwardsCallables() { 236 if (layout == "*") { 237 return 1; 238 } 239 return backwardsCallCount; 240 } 241 242 public boolean isDefaultLayout() { 243 return isDefault; 244 } 245 246 public void setBackwardsCallCount(final int backwardsCallCount) { 247 this.backwardsCallCount = backwardsCallCount; 248 } 249 250}