View Javadoc
1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one or more
3    *  contributor license agreements.  See the NOTICE file distributed with
4    *  this work for additional information regarding copyright ownership.
5    *  The ASF licenses this file to You under the Apache License, Version 2.0
6    *  (the "License"); you may not use this file except in compliance with
7    *  the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   *  Unless required by applicable law or agreed to in writing, software
12   *  distributed under the License is distributed on an "AS IS" BASIS,
13   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   *  See the License for the specific language governing permissions and
15   *  limitations under the License.
16   */
17  package org.apache.commons.compress.harmony.unpack200;
18  
19  import java.util.ArrayList;
20  import java.util.Arrays;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationDefaultAttribute;
25  import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.Annotation;
26  import org.apache.commons.compress.harmony.unpack200.bytecode.AnnotationsAttribute.ElementValue;
27  import org.apache.commons.compress.harmony.unpack200.bytecode.Attribute;
28  import org.apache.commons.compress.harmony.unpack200.bytecode.CPDouble;
29  import org.apache.commons.compress.harmony.unpack200.bytecode.CPFloat;
30  import org.apache.commons.compress.harmony.unpack200.bytecode.CPInteger;
31  import org.apache.commons.compress.harmony.unpack200.bytecode.CPLong;
32  import org.apache.commons.compress.harmony.unpack200.bytecode.CPUTF8;
33  import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleAnnotationsAttribute;
34  import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute;
35  import org.apache.commons.compress.harmony.unpack200.bytecode.RuntimeVisibleorInvisibleParameterAnnotationsAttribute.ParameterAnnotation;
36  
37  /**
38   * A group of metadata bands, such as class_RVA_bands, method_AD_bands etc.
39   */
40  public class MetadataBandGroup {
41  
42      private static CPUTF8 rvaUTF8;
43      private static CPUTF8 riaUTF8;
44  
45      private static CPUTF8 rvpaUTF8;
46      private static CPUTF8 ripaUTF8;
47  
48      public static void setRiaAttributeName(final CPUTF8 cpUTF8Value) {
49          riaUTF8 = cpUTF8Value;
50      }
51  
52      public static void setRipaAttributeName(final CPUTF8 cpUTF8Value) {
53          ripaUTF8 = cpUTF8Value;
54      }
55  
56      public static void setRvaAttributeName(final CPUTF8 cpUTF8Value) {
57          rvaUTF8 = cpUTF8Value;
58      }
59  
60      public static void setRvpaAttributeName(final CPUTF8 cpUTF8Value) {
61          rvpaUTF8 = cpUTF8Value;
62      }
63  
64      private final String type;
65  
66      private final CpBands cpBands;
67  
68      private List<Attribute> attributes;
69  
70      public int[] param_NB;
71  
72      public int[] anno_N;
73      public CPUTF8[][] type_RS;
74      public int[][] pair_N;
75      public CPUTF8[] name_RU;
76      public int[] T;
77      public CPInteger[] caseI_KI;
78      public CPDouble[] caseD_KD;
79      public CPFloat[] caseF_KF;
80      public CPLong[] caseJ_KJ;
81      public CPUTF8[] casec_RS;
82      public String[] caseet_RS;
83      public String[] caseec_RU;
84      public CPUTF8[] cases_RU;
85      public int[] casearray_N;
86      public CPUTF8[] nesttype_RS;
87      public int[] nestpair_N;
88      public CPUTF8[] nestname_RU;
89      private int caseI_KI_Index;
90  
91      private int caseD_KD_Index;
92  
93      private int caseF_KF_Index;
94  
95      private int caseJ_KJ_Index;
96  
97      private int casec_RS_Index;
98  
99      private int caseet_RS_Index;
100 
101     private int caseec_RU_Index;
102 
103     private int cases_RU_Index;
104 
105     private int casearray_N_Index;
106 
107     private int T_index;
108 
109     private int nesttype_RS_Index;
110 
111     private int nestpair_N_Index;
112 
113     private Iterator<CPUTF8> nestname_RU_Iterator;
114 
115     private int anno_N_Index;
116 
117     private int pair_N_Index;
118 
119     public MetadataBandGroup(final String type, final CpBands cpBands) {
120         this.type = type;
121         this.cpBands = cpBands;
122     }
123 
124     private Annotation getAnnotation(final CPUTF8 type, final int pairCount, final Iterator<CPUTF8> namesIterator) {
125         final CPUTF8[] elementNames = new CPUTF8[pairCount];
126         final ElementValue[] elementValues = new ElementValue[pairCount];
127         for (int j = 0; j < elementNames.length; j++) {
128             elementNames[j] = namesIterator.next();
129             final int t = T[T_index++];
130             elementValues[j] = new ElementValue(t, getNextValue(t));
131         }
132         return new Annotation(pairCount, type, elementNames, elementValues);
133     }
134 
135     private Attribute getAttribute(final int numAnnotations, final CPUTF8[] types, final int[] pairCounts, final Iterator<CPUTF8> namesIterator) {
136         final Annotation[] annotations = new Annotation[numAnnotations];
137         Arrays.setAll(annotations, i -> getAnnotation(types[i], pairCounts[i], namesIterator));
138         return new RuntimeVisibleorInvisibleAnnotationsAttribute(type.equals("RVA") ? rvaUTF8 : riaUTF8, annotations);
139     }
140 
141     public List<Attribute> getAttributes() {
142         // TODO: Optimize iterators!
143         if (attributes == null) {
144             attributes = new ArrayList<>();
145             if (name_RU != null) {
146                 final Iterator<CPUTF8> name_RU_Iterator = Arrays.asList(name_RU).iterator();
147                 if (!type.equals("AD")) {
148                     T_index = 0;
149                 }
150                 caseI_KI_Index = 0;
151                 caseD_KD_Index = 0;
152                 caseF_KF_Index = 0;
153                 caseJ_KJ_Index = 0;
154                 casec_RS_Index = 0;
155                 caseet_RS_Index = 0;
156                 caseec_RU_Index = 0;
157                 cases_RU_Index = 0;
158                 casearray_N_Index = 0;
159                 nesttype_RS_Index = 0;
160                 nestpair_N_Index = 0;
161                 nestname_RU_Iterator = Arrays.asList(nestname_RU).iterator();
162                 if (type.equals("RVA") || type.equals("RIA")) {
163                     for (int i = 0; i < anno_N.length; i++) {
164                         attributes.add(getAttribute(anno_N[i], type_RS[i], pair_N[i], name_RU_Iterator));
165                     }
166                 } else if (type.equals("RVPA") || type.equals("RIPA")) {
167                     anno_N_Index = 0;
168                     pair_N_Index = 0;
169                     for (final int element : param_NB) {
170                         attributes.add(getParameterAttribute(element, name_RU_Iterator));
171                     }
172                 }
173             } else if (type.equals("AD")) {
174                 for (final int element : T) {
175                     attributes.add(new AnnotationDefaultAttribute(new ElementValue(element, getNextValue(element))));
176                 }
177             }
178         }
179         return attributes;
180     }
181 
182     private Object getNextValue(final int t) {
183         switch (t) {
184         case 'B':
185         case 'C':
186         case 'I':
187         case 'S':
188         case 'Z':
189             return caseI_KI[caseI_KI_Index++];
190         case 'D':
191             return caseD_KD[caseD_KD_Index++];
192         case 'F':
193             return caseF_KF[caseF_KF_Index++];
194         case 'J':
195             return caseJ_KJ[caseJ_KJ_Index++];
196         case 'c':
197             return casec_RS[casec_RS_Index++];
198         case 'e':
199             // TODO: check this - it may not work if the first string already
200             // has a colon in it
201             final String enumString = caseet_RS[caseet_RS_Index++] + ":" + caseec_RU[caseec_RU_Index++];
202             return cpBands.cpNameAndTypeValue(enumString);
203         case 's':
204             return cases_RU[cases_RU_Index++];
205         case '[':
206             final int arraySize = casearray_N[casearray_N_Index++];
207             final ElementValue[] nestedArray = new ElementValue[arraySize];
208             for (int i = 0; i < arraySize; i++) {
209                 final int nextT = T[T_index++];
210                 nestedArray[i] = new ElementValue(nextT, getNextValue(nextT));
211             }
212             return nestedArray;
213         case '@':
214             final CPUTF8 type = nesttype_RS[nesttype_RS_Index++];
215             final int numPairs = nestpair_N[nestpair_N_Index++];
216 
217             return getAnnotation(type, numPairs, nestname_RU_Iterator);
218         }
219         return null;
220     }
221 
222     private Attribute getParameterAttribute(final int numParameters, final Iterator<CPUTF8> namesIterator) {
223         final ParameterAnnotation[] parameterAnnotations = new ParameterAnnotation[numParameters];
224         for (int i = 0; i < numParameters; i++) {
225             final int numAnnotations = anno_N[anno_N_Index++];
226             final int[] pairCounts = pair_N[pair_N_Index++];
227             final Annotation[] annotations = new Annotation[numAnnotations];
228             Arrays.setAll(annotations, j -> getAnnotation(type_RS[anno_N_Index - 1][j], pairCounts[j], namesIterator));
229             parameterAnnotations[i] = new ParameterAnnotation(annotations);
230         }
231         return new RuntimeVisibleorInvisibleParameterAnnotationsAttribute(type.equals("RVPA") ? rvpaUTF8 : ripaUTF8, parameterAnnotations);
232     }
233 
234 }