• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dx.cf.direct;
18 
19 import com.android.dx.cf.attrib.AttAnnotationDefault;
20 import com.android.dx.cf.attrib.AttCode;
21 import com.android.dx.cf.attrib.AttConstantValue;
22 import com.android.dx.cf.attrib.AttDeprecated;
23 import com.android.dx.cf.attrib.AttEnclosingMethod;
24 import com.android.dx.cf.attrib.AttExceptions;
25 import com.android.dx.cf.attrib.AttInnerClasses;
26 import com.android.dx.cf.attrib.AttLineNumberTable;
27 import com.android.dx.cf.attrib.AttLocalVariableTable;
28 import com.android.dx.cf.attrib.AttLocalVariableTypeTable;
29 import com.android.dx.cf.attrib.AttRuntimeInvisibleAnnotations;
30 import com.android.dx.cf.attrib.AttRuntimeInvisibleParameterAnnotations;
31 import com.android.dx.cf.attrib.AttRuntimeVisibleAnnotations;
32 import com.android.dx.cf.attrib.AttRuntimeVisibleParameterAnnotations;
33 import com.android.dx.cf.attrib.AttSignature;
34 import com.android.dx.cf.attrib.AttSourceFile;
35 import com.android.dx.cf.attrib.AttSynthetic;
36 import com.android.dx.cf.attrib.InnerClassList;
37 import com.android.dx.cf.code.ByteCatchList;
38 import com.android.dx.cf.code.BytecodeArray;
39 import com.android.dx.cf.code.LineNumberList;
40 import com.android.dx.cf.code.LocalVariableList;
41 import com.android.dx.cf.iface.Attribute;
42 import com.android.dx.cf.iface.ParseException;
43 import com.android.dx.cf.iface.ParseObserver;
44 import com.android.dx.cf.iface.StdAttributeList;
45 import com.android.dx.rop.annotation.AnnotationVisibility;
46 import com.android.dx.rop.annotation.Annotations;
47 import com.android.dx.rop.annotation.AnnotationsList;
48 import com.android.dx.rop.code.AccessFlags;
49 import com.android.dx.rop.cst.Constant;
50 import com.android.dx.rop.cst.ConstantPool;
51 import com.android.dx.rop.cst.CstNat;
52 import com.android.dx.rop.cst.CstString;
53 import com.android.dx.rop.cst.CstType;
54 import com.android.dx.rop.cst.TypedConstant;
55 import com.android.dx.rop.type.TypeList;
56 import com.android.dx.util.ByteArray;
57 import com.android.dx.util.Hex;
58 import java.io.IOException;
59 
60 /**
61  * Standard subclass of {@link AttributeFactory}, which knows how to parse
62  * all the standard attribute types.
63  */
64 public class StdAttributeFactory
65     extends AttributeFactory {
66     /** {@code non-null;} shared instance of this class */
67     public static final StdAttributeFactory THE_ONE =
68         new StdAttributeFactory();
69 
70     /**
71      * Constructs an instance.
72      */
StdAttributeFactory()73     public StdAttributeFactory() {
74         // This space intentionally left blank.
75     }
76 
77     /** {@inheritDoc} */
78     @Override
parse0(DirectClassFile cf, int context, String name, int offset, int length, ParseObserver observer)79     protected Attribute parse0(DirectClassFile cf, int context, String name,
80             int offset, int length, ParseObserver observer) {
81         switch (context) {
82             case CTX_CLASS: {
83                 if (name == AttDeprecated.ATTRIBUTE_NAME) {
84                     return deprecated(cf, offset, length, observer);
85                 }
86                 if (name == AttEnclosingMethod.ATTRIBUTE_NAME) {
87                     return enclosingMethod(cf, offset, length, observer);
88                 }
89                 if (name == AttInnerClasses.ATTRIBUTE_NAME) {
90                     return innerClasses(cf, offset, length, observer);
91                 }
92                 if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) {
93                     return runtimeInvisibleAnnotations(cf, offset, length,
94                             observer);
95                 }
96                 if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) {
97                     return runtimeVisibleAnnotations(cf, offset, length,
98                             observer);
99                 }
100                 if (name == AttSynthetic.ATTRIBUTE_NAME) {
101                     return synthetic(cf, offset, length, observer);
102                 }
103                 if (name == AttSignature.ATTRIBUTE_NAME) {
104                     return signature(cf, offset, length, observer);
105                 }
106                 if (name == AttSourceFile.ATTRIBUTE_NAME) {
107                     return sourceFile(cf, offset, length, observer);
108                 }
109                 break;
110             }
111             case CTX_FIELD: {
112                 if (name == AttConstantValue.ATTRIBUTE_NAME) {
113                     return constantValue(cf, offset, length, observer);
114                 }
115                 if (name == AttDeprecated.ATTRIBUTE_NAME) {
116                     return deprecated(cf, offset, length, observer);
117                 }
118                 if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) {
119                     return runtimeInvisibleAnnotations(cf, offset, length,
120                             observer);
121                 }
122                 if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) {
123                     return runtimeVisibleAnnotations(cf, offset, length,
124                             observer);
125                 }
126                 if (name == AttSignature.ATTRIBUTE_NAME) {
127                     return signature(cf, offset, length, observer);
128                 }
129                 if (name == AttSynthetic.ATTRIBUTE_NAME) {
130                     return synthetic(cf, offset, length, observer);
131                 }
132                 break;
133             }
134             case CTX_METHOD: {
135                 if (name == AttAnnotationDefault.ATTRIBUTE_NAME) {
136                     return annotationDefault(cf, offset, length, observer);
137                 }
138                 if (name == AttCode.ATTRIBUTE_NAME) {
139                     return code(cf, offset, length, observer);
140                 }
141                 if (name == AttDeprecated.ATTRIBUTE_NAME) {
142                     return deprecated(cf, offset, length, observer);
143                 }
144                 if (name == AttExceptions.ATTRIBUTE_NAME) {
145                     return exceptions(cf, offset, length, observer);
146                 }
147                 if (name == AttRuntimeInvisibleAnnotations.ATTRIBUTE_NAME) {
148                     return runtimeInvisibleAnnotations(cf, offset, length,
149                             observer);
150                 }
151                 if (name == AttRuntimeVisibleAnnotations.ATTRIBUTE_NAME) {
152                     return runtimeVisibleAnnotations(cf, offset, length,
153                             observer);
154                 }
155                 if (name == AttRuntimeInvisibleParameterAnnotations.
156                         ATTRIBUTE_NAME) {
157                     return runtimeInvisibleParameterAnnotations(
158                             cf, offset, length, observer);
159                 }
160                 if (name == AttRuntimeVisibleParameterAnnotations.
161                         ATTRIBUTE_NAME) {
162                     return runtimeVisibleParameterAnnotations(
163                             cf, offset, length, observer);
164                 }
165                 if (name == AttSignature.ATTRIBUTE_NAME) {
166                     return signature(cf, offset, length, observer);
167                 }
168                 if (name == AttSynthetic.ATTRIBUTE_NAME) {
169                     return synthetic(cf, offset, length, observer);
170                 }
171                 break;
172             }
173             case CTX_CODE: {
174                 if (name == AttLineNumberTable.ATTRIBUTE_NAME) {
175                     return lineNumberTable(cf, offset, length, observer);
176                 }
177                 if (name == AttLocalVariableTable.ATTRIBUTE_NAME) {
178                     return localVariableTable(cf, offset, length, observer);
179                 }
180                 if (name == AttLocalVariableTypeTable.ATTRIBUTE_NAME) {
181                     return localVariableTypeTable(cf, offset, length,
182                             observer);
183                 }
184                 break;
185             }
186         }
187 
188         return super.parse0(cf, context, name, offset, length, observer);
189     }
190 
191     /**
192      * Parses an {@code AnnotationDefault} attribute.
193      */
annotationDefault(DirectClassFile cf, int offset, int length, ParseObserver observer)194     private Attribute annotationDefault(DirectClassFile cf,
195             int offset, int length, ParseObserver observer) {
196         if (length < 2) {
197             throwSeverelyTruncated();
198         }
199 
200         AnnotationParser ap =
201             new AnnotationParser(cf, offset, length, observer);
202         Constant cst = ap.parseValueAttribute();
203 
204         return new AttAnnotationDefault(cst, length);
205     }
206 
207     /**
208      * Parses a {@code Code} attribute.
209      */
code(DirectClassFile cf, int offset, int length, ParseObserver observer)210     private Attribute code(DirectClassFile cf, int offset, int length,
211             ParseObserver observer) {
212         if (length < 12) {
213             return throwSeverelyTruncated();
214         }
215 
216         ByteArray bytes = cf.getBytes();
217         ConstantPool pool = cf.getConstantPool();
218         int maxStack = bytes.getUnsignedShort(offset); // u2 max_stack
219         int maxLocals = bytes.getUnsignedShort(offset + 2); // u2 max_locals
220         int codeLength = bytes.getInt(offset + 4); // u4 code_length
221         int origOffset = offset;
222 
223         if (observer != null) {
224             observer.parsed(bytes, offset, 2,
225                             "max_stack: " + Hex.u2(maxStack));
226             observer.parsed(bytes, offset + 2, 2,
227                             "max_locals: " + Hex.u2(maxLocals));
228             observer.parsed(bytes, offset + 4, 4,
229                             "code_length: " + Hex.u4(codeLength));
230         }
231 
232         offset += 8;
233         length -= 8;
234 
235         if (length < (codeLength + 4)) {
236             return throwTruncated();
237         }
238 
239         int codeOffset = offset;
240         offset += codeLength;
241         length -= codeLength;
242         BytecodeArray code =
243             new BytecodeArray(bytes.slice(codeOffset, codeOffset + codeLength),
244                               pool);
245         if (observer != null) {
246             code.forEach(new CodeObserver(code.getBytes(), observer));
247         }
248 
249         // u2 exception_table_length
250         int exceptionTableLength = bytes.getUnsignedShort(offset);
251         ByteCatchList catches = (exceptionTableLength == 0) ?
252             ByteCatchList.EMPTY :
253             new ByteCatchList(exceptionTableLength);
254 
255         if (observer != null) {
256             observer.parsed(bytes, offset, 2,
257                             "exception_table_length: " +
258                             Hex.u2(exceptionTableLength));
259         }
260 
261         offset += 2;
262         length -= 2;
263 
264         if (length < (exceptionTableLength * 8 + 2)) {
265             return throwTruncated();
266         }
267 
268         for (int i = 0; i < exceptionTableLength; i++) {
269             if (observer != null) {
270                 observer.changeIndent(1);
271             }
272 
273             int startPc = bytes.getUnsignedShort(offset);
274             int endPc = bytes.getUnsignedShort(offset + 2);
275             int handlerPc = bytes.getUnsignedShort(offset + 4);
276             int catchTypeIdx = bytes.getUnsignedShort(offset + 6);
277             CstType catchType = (CstType) pool.get0Ok(catchTypeIdx);
278             catches.set(i, startPc, endPc, handlerPc, catchType);
279             if (observer != null) {
280                 observer.parsed(bytes, offset, 8,
281                                 Hex.u2(startPc) + ".." + Hex.u2(endPc) +
282                                 " -> " + Hex.u2(handlerPc) + " " +
283                                 ((catchType == null) ? "<any>" :
284                                  catchType.toHuman()));
285             }
286             offset += 8;
287             length -= 8;
288 
289             if (observer != null) {
290                 observer.changeIndent(-1);
291             }
292         }
293 
294         catches.setImmutable();
295 
296         AttributeListParser parser =
297             new AttributeListParser(cf, CTX_CODE, offset, this);
298         parser.setObserver(observer);
299 
300         StdAttributeList attributes = parser.getList();
301         attributes.setImmutable();
302 
303         int attributeByteCount = parser.getEndOffset() - offset;
304         if (attributeByteCount != length) {
305             return throwBadLength(attributeByteCount + (offset - origOffset));
306         }
307 
308         return new AttCode(maxStack, maxLocals, code, catches, attributes);
309     }
310 
311     /**
312      * Parses a {@code ConstantValue} attribute.
313      */
constantValue(DirectClassFile cf, int offset, int length, ParseObserver observer)314     private Attribute constantValue(DirectClassFile cf, int offset, int length,
315             ParseObserver observer) {
316         if (length != 2) {
317             return throwBadLength(2);
318         }
319 
320         ByteArray bytes = cf.getBytes();
321         ConstantPool pool = cf.getConstantPool();
322         int idx = bytes.getUnsignedShort(offset);
323         TypedConstant cst = (TypedConstant) pool.get(idx);
324         Attribute result = new AttConstantValue(cst);
325 
326         if (observer != null) {
327             observer.parsed(bytes, offset, 2, "value: " + cst);
328         }
329 
330         return result;
331     }
332 
333     /**
334      * Parses a {@code Deprecated} attribute.
335      */
deprecated(DirectClassFile cf, int offset, int length, ParseObserver observer)336     private Attribute deprecated(DirectClassFile cf, int offset, int length,
337             ParseObserver observer) {
338         if (length != 0) {
339             return throwBadLength(0);
340         }
341 
342         return new AttDeprecated();
343     }
344 
345     /**
346      * Parses an {@code EnclosingMethod} attribute.
347      */
enclosingMethod(DirectClassFile cf, int offset, int length, ParseObserver observer)348     private Attribute enclosingMethod(DirectClassFile cf, int offset,
349             int length, ParseObserver observer) {
350         if (length != 4) {
351             throwBadLength(4);
352         }
353 
354         ByteArray bytes = cf.getBytes();
355         ConstantPool pool = cf.getConstantPool();
356 
357         int idx = bytes.getUnsignedShort(offset);
358         CstType type = (CstType) pool.get(idx);
359 
360         idx = bytes.getUnsignedShort(offset + 2);
361         CstNat method = (CstNat) pool.get0Ok(idx);
362 
363         Attribute result = new AttEnclosingMethod(type, method);
364 
365         if (observer != null) {
366             observer.parsed(bytes, offset, 2, "class: " + type);
367             observer.parsed(bytes, offset + 2, 2, "method: " +
368                             DirectClassFile.stringOrNone(method));
369         }
370 
371         return result;
372     }
373 
374     /**
375      * Parses an {@code Exceptions} attribute.
376      */
exceptions(DirectClassFile cf, int offset, int length, ParseObserver observer)377     private Attribute exceptions(DirectClassFile cf, int offset, int length,
378             ParseObserver observer) {
379         if (length < 2) {
380             return throwSeverelyTruncated();
381         }
382 
383         ByteArray bytes = cf.getBytes();
384         int count = bytes.getUnsignedShort(offset); // number_of_exceptions
385 
386         if (observer != null) {
387             observer.parsed(bytes, offset, 2,
388                             "number_of_exceptions: " + Hex.u2(count));
389         }
390 
391         offset += 2;
392         length -= 2;
393 
394         if (length != (count * 2)) {
395             throwBadLength((count * 2) + 2);
396         }
397 
398         TypeList list = cf.makeTypeList(offset, count);
399         return new AttExceptions(list);
400     }
401 
402     /**
403      * Parses an {@code InnerClasses} attribute.
404      */
innerClasses(DirectClassFile cf, int offset, int length, ParseObserver observer)405     private Attribute innerClasses(DirectClassFile cf, int offset, int length,
406             ParseObserver observer) {
407         if (length < 2) {
408             return throwSeverelyTruncated();
409         }
410 
411         ByteArray bytes = cf.getBytes();
412         ConstantPool pool = cf.getConstantPool();
413         int count = bytes.getUnsignedShort(offset); // number_of_classes
414 
415         if (observer != null) {
416             observer.parsed(bytes, offset, 2,
417                             "number_of_classes: " + Hex.u2(count));
418         }
419 
420         offset += 2;
421         length -= 2;
422 
423         if (length != (count * 8)) {
424             throwBadLength((count * 8) + 2);
425         }
426 
427         InnerClassList list = new InnerClassList(count);
428 
429         for (int i = 0; i < count; i++) {
430             int innerClassIdx = bytes.getUnsignedShort(offset);
431             int outerClassIdx = bytes.getUnsignedShort(offset + 2);
432             int nameIdx = bytes.getUnsignedShort(offset + 4);
433             int accessFlags = bytes.getUnsignedShort(offset + 6);
434             CstType innerClass = (CstType) pool.get(innerClassIdx);
435             CstType outerClass = (CstType) pool.get0Ok(outerClassIdx);
436             CstString name = (CstString) pool.get0Ok(nameIdx);
437             list.set(i, innerClass, outerClass, name, accessFlags);
438             if (observer != null) {
439                 observer.parsed(bytes, offset, 2,
440                                 "inner_class: " +
441                                 DirectClassFile.stringOrNone(innerClass));
442                 observer.parsed(bytes, offset + 2, 2,
443                                 "  outer_class: " +
444                                 DirectClassFile.stringOrNone(outerClass));
445                 observer.parsed(bytes, offset + 4, 2,
446                                 "  name: " +
447                                 DirectClassFile.stringOrNone(name));
448                 observer.parsed(bytes, offset + 6, 2,
449                                 "  access_flags: " +
450                                 AccessFlags.innerClassString(accessFlags));
451             }
452             offset += 8;
453         }
454 
455         list.setImmutable();
456         return new AttInnerClasses(list);
457     }
458 
459     /**
460      * Parses a {@code LineNumberTable} attribute.
461      */
lineNumberTable(DirectClassFile cf, int offset, int length, ParseObserver observer)462     private Attribute lineNumberTable(DirectClassFile cf, int offset,
463             int length, ParseObserver observer) {
464         if (length < 2) {
465             return throwSeverelyTruncated();
466         }
467 
468         ByteArray bytes = cf.getBytes();
469         int count = bytes.getUnsignedShort(offset); // line_number_table_length
470 
471         if (observer != null) {
472             observer.parsed(bytes, offset, 2,
473                             "line_number_table_length: " + Hex.u2(count));
474         }
475 
476         offset += 2;
477         length -= 2;
478 
479         if (length != (count * 4)) {
480             throwBadLength((count * 4) + 2);
481         }
482 
483         LineNumberList list = new LineNumberList(count);
484 
485         for (int i = 0; i < count; i++) {
486             int startPc = bytes.getUnsignedShort(offset);
487             int lineNumber = bytes.getUnsignedShort(offset + 2);
488             list.set(i, startPc, lineNumber);
489             if (observer != null) {
490                 observer.parsed(bytes, offset, 4,
491                                 Hex.u2(startPc) + " " + lineNumber);
492             }
493             offset += 4;
494         }
495 
496         list.setImmutable();
497         return new AttLineNumberTable(list);
498     }
499 
500     /**
501      * Parses a {@code LocalVariableTable} attribute.
502      */
localVariableTable(DirectClassFile cf, int offset, int length, ParseObserver observer)503     private Attribute localVariableTable(DirectClassFile cf, int offset,
504             int length, ParseObserver observer) {
505         if (length < 2) {
506             return throwSeverelyTruncated();
507         }
508 
509         ByteArray bytes = cf.getBytes();
510         int count = bytes.getUnsignedShort(offset);
511 
512         if (observer != null) {
513             observer.parsed(bytes, offset, 2,
514                     "local_variable_table_length: " + Hex.u2(count));
515         }
516 
517         LocalVariableList list = parseLocalVariables(
518                 bytes.slice(offset + 2, offset + length), cf.getConstantPool(),
519                 observer, count, false);
520         return new AttLocalVariableTable(list);
521     }
522 
523     /**
524      * Parses a {@code LocalVariableTypeTable} attribute.
525      */
localVariableTypeTable(DirectClassFile cf, int offset, int length, ParseObserver observer)526     private Attribute localVariableTypeTable(DirectClassFile cf, int offset,
527             int length, ParseObserver observer) {
528         if (length < 2) {
529             return throwSeverelyTruncated();
530         }
531 
532         ByteArray bytes = cf.getBytes();
533         int count = bytes.getUnsignedShort(offset);
534 
535         if (observer != null) {
536             observer.parsed(bytes, offset, 2,
537                     "local_variable_type_table_length: " + Hex.u2(count));
538         }
539 
540         LocalVariableList list = parseLocalVariables(
541                 bytes.slice(offset + 2, offset + length), cf.getConstantPool(),
542                 observer, count, true);
543         return new AttLocalVariableTypeTable(list);
544     }
545 
546     /**
547      * Parse the table part of either a {@code LocalVariableTable}
548      * or a {@code LocalVariableTypeTable}.
549      *
550      * @param bytes {@code non-null;} bytes to parse, which should <i>only</i>
551      * contain the table data (no header)
552      * @param pool {@code non-null;} constant pool to use
553      * @param count {@code >= 0;} the number of entries
554      * @param typeTable {@code true} iff this is for a type table
555      * @return {@code non-null;} the constructed list
556      */
parseLocalVariables(ByteArray bytes, ConstantPool pool, ParseObserver observer, int count, boolean typeTable)557     private LocalVariableList parseLocalVariables(ByteArray bytes,
558             ConstantPool pool, ParseObserver observer, int count,
559             boolean typeTable) {
560         if (bytes.size() != (count * 10)) {
561             // "+ 2" is for the count.
562             throwBadLength((count * 10) + 2);
563         }
564 
565         ByteArray.MyDataInputStream in = bytes.makeDataInputStream();
566         LocalVariableList list = new LocalVariableList(count);
567 
568         try {
569             for (int i = 0; i < count; i++) {
570                 int startPc = in.readUnsignedShort();
571                 int length = in.readUnsignedShort();
572                 int nameIdx = in.readUnsignedShort();
573                 int typeIdx = in.readUnsignedShort();
574                 int index = in.readUnsignedShort();
575                 CstString name = (CstString) pool.get(nameIdx);
576                 CstString type = (CstString) pool.get(typeIdx);
577                 CstString descriptor = null;
578                 CstString signature = null;
579 
580                 if (typeTable) {
581                     signature = type;
582                 } else {
583                     descriptor = type;
584                 }
585 
586                 list.set(i, startPc, length, name,
587                         descriptor, signature, index);
588 
589                 if (observer != null) {
590                     observer.parsed(bytes, i * 10, 10, Hex.u2(startPc) +
591                             ".." + Hex.u2(startPc + length) + " " +
592                             Hex.u2(index) + " " + name.toHuman() + " " +
593                             type.toHuman());
594                 }
595             }
596         } catch (IOException ex) {
597             throw new RuntimeException("shouldn't happen", ex);
598         }
599 
600         list.setImmutable();
601         return list;
602     }
603 
604     /**
605      * Parses a {@code RuntimeInvisibleAnnotations} attribute.
606      */
runtimeInvisibleAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)607     private Attribute runtimeInvisibleAnnotations(DirectClassFile cf,
608             int offset, int length, ParseObserver observer) {
609         if (length < 2) {
610             throwSeverelyTruncated();
611         }
612 
613         AnnotationParser ap =
614             new AnnotationParser(cf, offset, length, observer);
615         Annotations annotations =
616             ap.parseAnnotationAttribute(AnnotationVisibility.BUILD);
617 
618         return new AttRuntimeInvisibleAnnotations(annotations, length);
619     }
620 
621     /**
622      * Parses a {@code RuntimeVisibleAnnotations} attribute.
623      */
runtimeVisibleAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)624     private Attribute runtimeVisibleAnnotations(DirectClassFile cf,
625             int offset, int length, ParseObserver observer) {
626         if (length < 2) {
627             throwSeverelyTruncated();
628         }
629 
630         AnnotationParser ap =
631             new AnnotationParser(cf, offset, length, observer);
632         Annotations annotations =
633             ap.parseAnnotationAttribute(AnnotationVisibility.RUNTIME);
634 
635         return new AttRuntimeVisibleAnnotations(annotations, length);
636     }
637 
638     /**
639      * Parses a {@code RuntimeInvisibleParameterAnnotations} attribute.
640      */
runtimeInvisibleParameterAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)641     private Attribute runtimeInvisibleParameterAnnotations(DirectClassFile cf,
642             int offset, int length, ParseObserver observer) {
643         if (length < 2) {
644             throwSeverelyTruncated();
645         }
646 
647         AnnotationParser ap =
648             new AnnotationParser(cf, offset, length, observer);
649         AnnotationsList list =
650             ap.parseParameterAttribute(AnnotationVisibility.BUILD);
651 
652         return new AttRuntimeInvisibleParameterAnnotations(list, length);
653     }
654 
655     /**
656      * Parses a {@code RuntimeVisibleParameterAnnotations} attribute.
657      */
runtimeVisibleParameterAnnotations(DirectClassFile cf, int offset, int length, ParseObserver observer)658     private Attribute runtimeVisibleParameterAnnotations(DirectClassFile cf,
659             int offset, int length, ParseObserver observer) {
660         if (length < 2) {
661             throwSeverelyTruncated();
662         }
663 
664         AnnotationParser ap =
665             new AnnotationParser(cf, offset, length, observer);
666         AnnotationsList list =
667             ap.parseParameterAttribute(AnnotationVisibility.RUNTIME);
668 
669         return new AttRuntimeVisibleParameterAnnotations(list, length);
670     }
671 
672     /**
673      * Parses a {@code Signature} attribute.
674      */
signature(DirectClassFile cf, int offset, int length, ParseObserver observer)675     private Attribute signature(DirectClassFile cf, int offset, int length,
676             ParseObserver observer) {
677         if (length != 2) {
678             throwBadLength(2);
679         }
680 
681         ByteArray bytes = cf.getBytes();
682         ConstantPool pool = cf.getConstantPool();
683         int idx = bytes.getUnsignedShort(offset);
684         CstString cst = (CstString) pool.get(idx);
685         Attribute result = new AttSignature(cst);
686 
687         if (observer != null) {
688             observer.parsed(bytes, offset, 2, "signature: " + cst);
689         }
690 
691         return result;
692     }
693 
694     /**
695      * Parses a {@code SourceFile} attribute.
696      */
sourceFile(DirectClassFile cf, int offset, int length, ParseObserver observer)697     private Attribute sourceFile(DirectClassFile cf, int offset, int length,
698             ParseObserver observer) {
699         if (length != 2) {
700             throwBadLength(2);
701         }
702 
703         ByteArray bytes = cf.getBytes();
704         ConstantPool pool = cf.getConstantPool();
705         int idx = bytes.getUnsignedShort(offset);
706         CstString cst = (CstString) pool.get(idx);
707         Attribute result = new AttSourceFile(cst);
708 
709         if (observer != null) {
710             observer.parsed(bytes, offset, 2, "source: " + cst);
711         }
712 
713         return result;
714     }
715 
716     /**
717      * Parses a {@code Synthetic} attribute.
718      */
synthetic(DirectClassFile cf, int offset, int length, ParseObserver observer)719     private Attribute synthetic(DirectClassFile cf, int offset, int length,
720             ParseObserver observer) {
721         if (length != 0) {
722             return throwBadLength(0);
723         }
724 
725         return new AttSynthetic();
726     }
727 
728     /**
729      * Throws the right exception when a known attribute has a way too short
730      * length.
731      *
732      * @return never
733      * @throws ParseException always thrown
734      */
throwSeverelyTruncated()735     private static Attribute throwSeverelyTruncated() {
736         throw new ParseException("severely truncated attribute");
737     }
738 
739     /**
740      * Throws the right exception when a known attribute has a too short
741      * length.
742      *
743      * @return never
744      * @throws ParseException always thrown
745      */
throwTruncated()746     private static Attribute throwTruncated() {
747         throw new ParseException("truncated attribute");
748     }
749 
750     /**
751      * Throws the right exception when an attribute has an unexpected length
752      * (given its contents).
753      *
754      * @param expected expected length
755      * @return never
756      * @throws ParseException always thrown
757      */
throwBadLength(int expected)758     private static Attribute throwBadLength(int expected) {
759         throw new ParseException("bad attribute length; expected length " +
760                                  Hex.u4(expected));
761     }
762 }
763