View Javadoc
1   package org.apache.maven.shared.dependency.analyzer.asm;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.nio.ByteBuffer;
23  import java.nio.ByteOrder;
24  import java.util.Collections;
25  import java.util.HashMap;
26  import java.util.HashSet;
27  import java.util.Map;
28  import java.util.Set;
29  
30  /**
31   * A small parser to read the constant pool directly, in case it contains references
32   * ASM does not support.
33   *
34   * Adapted from http://stackoverflow.com/a/32278587/23691
35   */
36  public class ConstantPoolParser
37  {
38      public static final int HEAD = 0xcafebabe;
39  
40      // Constant pool types
41      public static final byte CONSTANT_UTF8 = 1;
42  
43      public static final byte CONSTANT_INTEGER = 3;
44  
45      public static final byte CONSTANT_FLOAT = 4;
46  
47      public static final byte CONSTANT_LONG = 5;
48  
49      public static final byte CONSTANT_DOUBLE = 6;
50  
51      public static final byte CONSTANT_CLASS = 7;
52  
53      public static final byte CONSTANT_STRING = 8;
54  
55      public static final byte CONSTANT_FIELDREF = 9;
56  
57      public static final byte CONSTANT_METHODREF = 10;
58  
59      public static final byte CONSTANT_INTERFACEMETHODREF = 11;
60  
61      public static final byte CONSTANT_NAME_AND_TYPE = 12;
62  
63      public static final byte CONSTANT_METHODHANDLE = 15;
64  
65      public static final byte CONSTANT_METHOD_TYPE = 16;
66  
67      public static final byte CONSTANT_INVOKE_DYNAMIC = 18;
68  
69      private static final int OXF0 = 0xf0;
70  
71      private static final int OXE0 = 0xe0;
72  
73      private static final int OX3F = 0x3F;
74  
75      static Set<String> getConstantPoolClassReferences( byte[] b )
76      {
77          return parseConstantPoolClassReferences( ByteBuffer.wrap( b ) );
78      }
79  
80      static Set<String> parseConstantPoolClassReferences( ByteBuffer buf )
81      {
82          if ( buf.order( ByteOrder.BIG_ENDIAN )
83                  .getInt() != HEAD )
84          {
85              return Collections.emptySet();
86          }
87          buf.getChar() ; buf.getChar(); // minor + ver
88          Set<Integer> classes = new HashSet<Integer>();
89          Map<Integer, String> stringConstants = new HashMap<Integer, String>();
90          for ( int ix = 1, num = buf.getChar(); ix < num; ix++ )
91          {
92              byte tag = buf.get();
93              switch ( tag )
94              {
95                  default:
96                      throw new RuntimeException( "Unknown constant pool type" );
97                  case CONSTANT_UTF8:
98                      stringConstants.put( ix, decodeString( buf ) );
99                      continue;
100                 case CONSTANT_CLASS:
101                 case CONSTANT_STRING:
102                 case CONSTANT_METHOD_TYPE:
103                     classes.add( (int) buf.getChar() );
104                     break;
105                 case CONSTANT_FIELDREF:
106                 case CONSTANT_METHODREF:
107                 case CONSTANT_INTERFACEMETHODREF:
108                 case CONSTANT_NAME_AND_TYPE:
109                     buf.getChar();
110                     buf.getChar();
111                     break;
112                 case CONSTANT_INTEGER:
113                     buf.getInt();
114                     break;
115                 case CONSTANT_FLOAT:
116                     buf.getFloat();
117                     break;
118                 case CONSTANT_DOUBLE:
119                     buf.getDouble();
120                     ix++;
121                     break;
122                 case CONSTANT_LONG:
123                     buf.getLong();
124                     ix++;
125                     break;
126                 case CONSTANT_METHODHANDLE:
127                     buf.get();
128                     buf.getChar();
129                     break;
130                 case CONSTANT_INVOKE_DYNAMIC:
131                     buf.getChar();
132                     buf.getChar();
133                     break;
134             }
135         }
136         Set<String> result = new HashSet<String>();
137         for ( Integer aClass : classes )
138         {
139             result.add( stringConstants.get( aClass ) );
140         }
141         return result;
142     }
143 
144     private static String decodeString( ByteBuffer buf )
145     {
146         int size = buf.getChar(), oldLimit = buf.limit();
147         buf.limit( buf.position() + size );
148         StringBuilder sb = new StringBuilder( size + ( size >> 1 ) + 16 );
149         while ( buf.hasRemaining() )
150         {
151             byte b = buf.get();
152             if ( b > 0 )
153             {
154                 sb.append( (char) b );
155             }
156             else
157             {
158                 int b2 = buf.get();
159                 if ( ( b & OXF0 ) != OXE0 )
160                 {
161                     sb.append( (char) ( ( b & 0x1F ) << 6 | b2 & OX3F ) );
162                 }
163                 else
164                 {
165                     int b3 = buf.get();
166                     sb.append( (char) ( ( b & 0x0F ) << 12 | ( b2 & OX3F ) << 6 | b3 & OX3F ) );
167                 }
168             }
169         }
170         buf.limit( oldLimit );
171         return sb.toString();
172     }
173 }