/**
 * An  AnnotationVisitor that generates annotations in bytecode form.
 *
 *  author Eric Bruneton
 *  author Eugene Kuleshov
  import type { ClassWriter } from "./ClassWriter" ; import { AnnotationVisitor } from "./AnnotationVisitor" ; import { ByteVector } from "./ByteVector" ; import { Opcodes } from "./Opcodes" ; import { Item } from "./Item" ; import { TypePath } from "./TypePath" ; import { Type } from "./Type" ; export class AnnotationWriter extends AnnotationVisitor { /**
     * The class writer TO which this annotation must be added.
     */ private cw : ClassWriter ; /**
     * The number of values in this annotation.
     */ private size : number ; /**
     * <tt>true<tt> if values are named, <tt>false</tt> otherwise. Annotation
     * writers used for annotation default and annotation arrays use unnamed
     * values.
     */ private named : boolean ; /**
     * The annotation values in bytecode form. This byte vector only contains
     * the values themselves, i.e. the number of values must be stored as a
     * unsigned short just before these bytes.
     */ private bv : ByteVector ; /**
     * The byte vector to be used to store the number of values of this
     * annotation. See  {@link #bv} .
      private parent : ByteVector | null ; /**
     * Where the number of values of this annotation must be stored in
     *  {@link #parent} .
      private offset : number ; /**
     * Next annotation writer. This field is used to store annotation lists.
     */ next : AnnotationWriter | null = null ; /**
     * Previous annotation writer. This field is used to store annotation lists.
     */ prev : AnnotationWriter | null = null ; /**
     * Constructs a new  AnnotationWriter .
     *
     *  param cw param named param bv param parent param offset constructor ( cw , named , bv , parent = null , offset ) { super ( Opcodes . ASM5 ) ; this . size = 0 ; this . named = false ; this . offset = 0 ; this . cw = cw ; this . named = named ; this . bv = bv ; this . parent = parent ; this . offset = offset ; } public visit ( name , value ) { ++ this . size ; if ( this . named ) { this . bv . putShort ( this . cw . newUTF8 ( name ) ) ; } if ( typeof value === "string" ) { this . bv . put12 ( ( "s" ) . charCodeAt ( 0 ) , this . cw . newUTF8 ( value ) ) ; } else if ( typeof value === "number" ) { this . bv . put12 ( ( "B" ) . charCodeAt ( 0 ) , this . cw . newInteger ( value ) . index ) ; } else if ( typeof value === "boolean" ) { let v = ( value ) ? 1 : 0 ; this . bv . put12 ( ( "Z" ) . charCodeAt ( 0 ) , this . cw . newInteger ( v ) . index ) ; } else if ( typeof value === "string" ) { this . bv . put12 ( ( "C" ) . charCodeAt ( 0 ) , this . cw . newInteger ( ( value ) . charCodeAt ( 0 ) ) . index ) ; } else if ( typeof value === "number" ) { this . bv . put12 ( ( "S" ) . charCodeAt ( 0 ) , this . cw . newInteger ( ( value ) ) . index ) ; } else if ( value != null && value instanceof Type ) { this . bv . put12 ( ( "c" ) . charCodeAt ( 0 ) , this . cw . newUTF8 ( ( value ) . getDescriptor ( ) ) ) ; } else if ( value != null && value instanceof Array ) { let v = value as number [ ] ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "B" ) . charCodeAt ( 0 ) , this . cw . newInteger ( v [ i ] ) . index ) ; } } else if ( value != null && value instanceof Array ) { let v = < boolean [ ] > value ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "Z" ) . charCodeAt ( 0 ) , this . cw . newInteger ( v [ i ] ? 1 : 0 ) . index ) ; } } else if ( value != null && value instanceof Array ) { let v = value as number [ ] ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "S" ) . charCodeAt ( 0 ) , this . cw . newInteger ( v [ i ] ) . index ) ; } } else if ( value != null && value instanceof Array ) { let v = < string [ ] > value ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "C" ) . charCodeAt ( 0 ) , this . cw . newInteger ( ( v [ i ] ) . charCodeAt ( 0 ) ) . index ) ; } } else if ( value != null && value instanceof Array ) { let v = value as number [ ] ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "I" ) . charCodeAt ( 0 ) , this . cw . newInteger ( v [ i ] ) . index ) ; } } else if ( value != null && value instanceof Array ) { let v = value as number [ ] ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { } } else if ( value != null && value instanceof Array ) { let v = value as number [ ] ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "F" ) . charCodeAt ( 0 ) , this . cw . newFloat ( v [ i ] ) . index ) ; } } else if ( value != null && value instanceof Array ) { let v = value as number [ ] ; this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , v . length ) ; for ( let i = 0 ; i < v . length ; i ++ ) { this . bv . put12 ( ( "D" ) . charCodeAt ( 0 ) , this . cw . newDouble ( v [ i ] ) . index ) ; } } else { let i = this . cw . newConstItem ( value ) ; this . bv . put12 ( ( ".s.IFJDCS" . charAt ( i . type ) ) . charCodeAt ( 0 ) , i . index ) ; } } public visitEnum ( name , desc , value ) { ++ this . size ; if ( this . named ) { this . bv . putShort ( this . cw . newUTF8 ( name ) ) ; } this . bv . put12 ( ( "e" ) . charCodeAt ( 0 ) , this . cw . newUTF8 ( desc ) ) . putShort ( this . cw . newUTF8 ( value ) ) ; } public visitAnnotation ( name , desc ) { ++ this . size ; if ( this . named ) { this . bv . putShort ( this . cw . newUTF8 ( name ) ) ; } this . bv . put12 ( ( "@" ) . charCodeAt ( 0 ) , this . cw . newUTF8 ( desc ) ) . putShort ( 0 ) ; return new AnnotationWriter ( this . cw , true , this . bv , this . bv , this . bv . length - 2 ) ; } public visitArray ( name ) { ++ this . size ; if ( this . named ) { this . bv . putShort ( this . cw . newUTF8 ( name ) ) ; } this . bv . put12 ( ( "[" ) . charCodeAt ( 0 ) , 0 ) ; return new AnnotationWriter ( this . cw , false , this . bv , this . bv , this . bv . length - 2 ) ; } public visitEnd ( ) { if ( this . parent != null ) { let data = this . parent . data ; data [ this . offset ] = ( ( this . size >>> 8 ) | 0 ) ; data [ this . offset + 1 ] = ( this . size | 0 ) ; } } return getSize ( ) { let size = 0 ; let aw = this ; while ( ( aw != null ) ) { size += aw . bv . length ; aw = aw . next ; } ; return size ; } param out put ( out ) { let n = 0 ; let size = 2 ; let aw = this ; let last = null ; while ( ( aw != null ) ) { ++ n ; size += aw . bv . length ; aw . visitEnd ( ) ; aw . prev = last ; last = aw ; aw = aw . next ; } ; out . putInt ( size ) ; out . putShort ( n ) ; aw = last ; while ( ( aw != null ) ) { out . putByteArray ( aw . bv . data , 0 , aw . bv . length ) ; aw = aw . prev ; } ; } param panns param off param out static put ( panns , off , out ) { let size = 1 + 2 * ( panns . length - off ) ; for ( let i = off ; i < panns . length ; ++ i ) { size += panns [ i ] == null ? 0 : panns [ i ] . getSize ( ) ; } out . putInt ( size ) . putByte ( panns . length - off ) ; for ( let i = off ; i < panns . length ; ++ i ) { let aw = panns [ i ] ; let last = null ; let n = 0 ; while ( ( aw != null ) ) { ++ n ; aw . visitEnd ( ) ; aw . prev = last ; last = aw ; aw = aw . next ; } ; out . putShort ( n ) ; aw = last ; while ( ( aw != null ) ) { out . putByteArray ( aw . bv . data , 0 , aw . bv . length ) ; aw = aw . prev ; } ; } } param typeRef a reference to the annotated type. See  TypeReference .
     *  param typePath param out static putTarget ( typeRef , typePath , out ) { switch ( ( typeRef >>> 24 ) ) { case 0 : case 1 : case 22 : out . putShort ( typeRef >>> 16 ) ; break ; case 19 : case 20 : case 21 : out . putByte ( typeRef >>> 24 ) ; break ; case 71 : case 72 : case 73 : case 74 : case 75 : out . putInt ( typeRef ) ; break ; default : out . put12 ( typeRef >>> 24 , ( typeRef & 16776960 ) >> 8 ) ; break ; } if ( typePath == null ) { out . putByte ( 0 ) ; } else { let length = typePath . buf [ typePath . offset ] * 2 + 1 ; out . putByteArray ( typePath . buf , typePath . offset , length ) ; } } }