Skip to main content

rust_asm/
class_reader.rs

1use crate::constant_pool::CpInfo;
2use crate::error::ClassReadError;
3use crate::insn::{
4    AbstractInsnNode, FieldInsnNode, IincInsnNode, Insn, InsnList, InsnNode, IntInsnNode,
5    InvokeDynamicInsnNode, InvokeInterfaceInsnNode, JumpInsnNode, LabelNode, LdcInsnNode, LdcValue,
6    LookupSwitchInsnNode, MemberRef, MethodInsnNode, MultiANewArrayInsnNode, TableSwitchInsnNode,
7    TryCatchBlockNode, TypeInsnNode, VarInsnNode,
8};
9use crate::types::Type;
10use crate::{constants, opcodes};
11
12/// Represents a constant value loadable by the `LDC` (Load Constant) instruction.
13///
14/// This enum wraps various types of constants that can be stored in the constant pool
15/// and pushed onto the operand stack.
16#[derive(Debug, Clone)]
17pub enum LdcConstant {
18    /// A 32-bit integer constant.
19    Integer(i32),
20    /// A 32-bit floating-point constant.
21    Float(f32),
22    /// A 64-bit integer constant.
23    Long(i64),
24    /// A 64-bit floating-point constant.
25    Double(f64),
26    /// A string literal constant.
27    String(String),
28    /// A class constant (e.g., `String.class`).
29    Class(String),
30    /// A method type constant (MethodDescriptor).
31    MethodType(String),
32    /// A method handle constant.
33    MethodHandle {
34        reference_kind: u8,
35        reference_index: u16,
36    },
37    /// A dynamic constant (computed via `invokedynamic` bootstrap methods).
38    Dynamic,
39}
40
41/// A visitor to visit a Java field.
42///
43/// The methods of this trait must be called in the following order:
44/// `visit_end`.
45pub trait FieldVisitor {
46    /// Visits the end of the field.
47    ///
48    /// This method, which is the last one to be called, is used to inform the
49    /// visitor that all the annotations and attributes of the field have been visited.
50    fn visit_end(&mut self) {}
51}
52
53pub trait MethodVisitor {
54    /// Starts the visit of the method's code.
55    fn visit_code(&mut self) {}
56
57    /// Visits a zero-operand instruction.
58    ///
59    /// # Arguments
60    /// * `opcode` - The opcode of the instruction to be visited.
61    fn visit_insn(&mut self, _opcode: u8) {}
62
63    /// Visits an instruction with a single int operand.
64    fn visit_int_insn(&mut self, _opcode: u8, _operand: i32) {}
65
66    /// Visits a local variable instruction.
67    fn visit_var_insn(&mut self, _opcode: u8, _var_index: u16) {}
68
69    /// Visits a type instruction.
70    ///
71    /// # Arguments
72    /// * `opcode` - The opcode of the instruction.
73    /// * `type_name` - The internal name of the object or array class.
74    fn visit_type_insn(&mut self, _opcode: u8, _type_name: &str) {}
75
76    /// Visits a field instruction.
77    ///
78    /// # Arguments
79    /// * `opcode` - The opcode of the instruction.
80    /// * `owner` - The internal name of the field's owner class.
81    /// * `name` - The field's name.
82    /// * `desc` - The field's descriptor.
83    fn visit_field_insn(&mut self, _opcode: u8, _owner: &str, _name: &str, _desc: &str) {}
84    fn visit_method_insn(
85        &mut self,
86        _opcode: u8,
87        _owner: &str,
88        _name: &str,
89        _desc: &str,
90        _is_interface: bool,
91    ) {
92    }
93    fn visit_invoke_dynamic_insn(&mut self, _name: &str, _desc: &str) {}
94    /// Visits a jump instruction.
95    ///
96    /// # Arguments
97    /// * `opcode` - The opcode of the instruction.
98    /// * `target_offset` - The offset of the target instruction relative to the current instruction.
99    fn visit_jump_insn(&mut self, _opcode: u8, _target_offset: i32) {}
100
101    /// Visits an `LDC` instruction.
102    fn visit_ldc_insn(&mut self, _value: LdcConstant) {}
103    fn visit_iinc_insn(&mut self, _var_index: u16, _increment: i16) {}
104    fn visit_table_switch(&mut self, _default: i32, _low: i32, _high: i32, _targets: &[i32]) {}
105    fn visit_lookup_switch(&mut self, _default: i32, _pairs: &[(i32, i32)]) {}
106    fn visit_multi_anewarray_insn(&mut self, _type_name: &str, _dims: u8) {}
107    fn visit_maxs(&mut self, _max_stack: u16, _max_locals: u16) {}
108    fn visit_end(&mut self) {}
109}
110
111/// A visitor to visit a Java class.
112///
113/// The methods of this trait must be called in the following order:
114/// `visit` -> `visit_source` -> (`visit_field` | `visit_method`)* -> `visit_end`.
115pub trait ClassVisitor {
116    /// Visits the header of the class.
117    ///
118    /// # Arguments
119    /// * `major` - The major version number of the class file.
120    /// * `minor` - The minor version number of the class file.
121    /// * `access_flags` - The class's access flags (see `Opcodes`).
122    /// * `name` - The internal name of the class.
123    /// * `super_name` - The internal name of the super class (e.g., `java/lang/String`, `a/b/c`).
124    ///   Use `None` for `Object`.
125    /// * `interfaces` - The internal names of the class's interfaces.
126    fn visit(
127        &mut self,
128        _major: u16,
129        _minor: u16,
130        _access_flags: u16,
131        _name: &str,
132        _super_name: Option<&str>,
133        _interfaces: &[String],
134    ) {
135    }
136
137    /// Visits the source file name of the class.
138    fn visit_source(&mut self, _source: &str) {}
139
140    /// Visits a field of the class.
141    ///
142    /// Returns an optional `FieldVisitor` to visit the field's content.
143    fn visit_field(
144        &mut self,
145        _access_flags: u16,
146        _name: &str,
147        _descriptor: &str,
148    ) -> Option<Box<dyn FieldVisitor>> {
149        None
150    }
151
152    /// Visits a method of the class.
153    ///
154    /// Returns an optional `MethodVisitor` to visit the method's code.
155    fn visit_method(
156        &mut self,
157        _access_flags: u16,
158        _name: &str,
159        _descriptor: &str,
160    ) -> Option<Box<dyn MethodVisitor>> {
161        None
162    }
163
164    /// Visits the end of the class.
165    fn visit_end(&mut self) {}
166}
167
168/// A parser to make a [`ClassVisitor`] visit a `ClassFile` structure.
169///
170/// This class parses a byte array conforming to the Java class file format and
171/// calls the appropriate methods of a given class visitor for each field, method,
172/// and bytecode instruction encountered.
173pub struct ClassReader {
174    bytes: Vec<u8>,
175}
176
177impl ClassReader {
178    /// Constructs a new `ClassReader` with the given class file bytes.
179    ///
180    /// # Arguments
181    ///
182    /// * `bytes` - A byte slice containing the JVM class file data.
183    pub fn new(bytes: &[u8]) -> Self {
184        Self {
185            bytes: bytes.to_vec(),
186        }
187    }
188
189    /// Makes the given visitor visit the Java class of this `ClassReader`.
190    ///
191    /// This method parses the class file data and drives the visitor events.
192    ///
193    /// # Arguments
194    ///
195    /// * `visitor` - The visitor that must visit this class.
196    /// * `_options` - Option flags (currently unused, reserve for future parsing options like skipping debug info).
197    ///
198    /// # Errors
199    ///
200    /// Returns a [`ClassReadError`] if the class file is malformed or contains unsupported versions.
201    pub fn accept(
202        &self,
203        visitor: &mut dyn ClassVisitor,
204        _options: u32,
205    ) -> Result<(), ClassReadError> {
206        let class_file = read_class_file(&self.bytes)?;
207        let name = class_file.class_name(class_file.this_class)?.to_string();
208        let super_name = if class_file.super_class == 0 {
209            None
210        } else {
211            Some(class_file.class_name(class_file.super_class)?.to_string())
212        };
213        let mut interfaces = Vec::with_capacity(class_file.interfaces.len());
214        for index in &class_file.interfaces {
215            interfaces.push(class_file.class_name(*index)?.to_string());
216        }
217
218        visitor.visit(
219            class_file.major_version,
220            class_file.minor_version,
221            class_file.access_flags,
222            &name,
223            super_name.as_deref(),
224            &interfaces,
225        );
226
227        for attr in &class_file.attributes {
228            if let AttributeInfo::SourceFile { sourcefile_index } = attr {
229                let source = class_file.cp_utf8(*sourcefile_index)?;
230                visitor.visit_source(source);
231            }
232        }
233
234        for field in &class_file.fields {
235            let field_name = class_file.cp_utf8(field.name_index)?;
236            let field_desc = class_file.cp_utf8(field.descriptor_index)?;
237            if let Some(mut fv) = visitor.visit_field(field.access_flags, field_name, field_desc) {
238                fv.visit_end();
239            }
240        }
241
242        for method in &class_file.methods {
243            let method_name = class_file.cp_utf8(method.name_index)?;
244            let method_desc = class_file.cp_utf8(method.descriptor_index)?;
245            if let Some(mut mv) =
246                visitor.visit_method(method.access_flags, method_name, method_desc)
247            {
248                let code = method.attributes.iter().find_map(|attr| match attr {
249                    AttributeInfo::Code(code) => Some(code),
250                    _ => None,
251                });
252                if let Some(code) = code {
253                    mv.visit_code();
254                    let instructions = parse_code_instructions_with_offsets(&code.code)?;
255                    for instruction in instructions {
256                        visit_instruction(
257                            &class_file.constant_pool,
258                            instruction.offset as i32,
259                            instruction.insn,
260                            &mut *mv,
261                        )?;
262                    }
263                    mv.visit_maxs(code.max_stack, code.max_locals);
264                }
265                mv.visit_end();
266            }
267        }
268
269        visitor.visit_end();
270        Ok(())
271    }
272
273    /// Converts the read class data directly into a `ClassNode`.
274    ///
275    /// This is a convenience method that parses the bytes and builds a
276    /// complete object model of the class.
277    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
278        let class_file = read_class_file(&self.bytes)?;
279        class_file.to_class_node()
280    }
281}
282
283#[derive(Debug, Clone)]
284pub struct ClassFile {
285    pub minor_version: u16,
286    pub major_version: u16,
287    pub constant_pool: Vec<CpInfo>,
288    pub access_flags: u16,
289    pub this_class: u16,
290    pub super_class: u16,
291    pub interfaces: Vec<u16>,
292    pub fields: Vec<FieldInfo>,
293    pub methods: Vec<MethodInfo>,
294    pub attributes: Vec<AttributeInfo>,
295}
296
297impl ClassFile {
298    pub fn cp_utf8(&self, index: u16) -> Result<&str, ClassReadError> {
299        match self
300            .constant_pool
301            .get(index as usize)
302            .ok_or(ClassReadError::InvalidIndex(index))?
303        {
304            CpInfo::Utf8(value) => Ok(value.as_str()),
305            _ => Err(ClassReadError::InvalidIndex(index)),
306        }
307    }
308
309    pub fn class_name(&self, index: u16) -> Result<&str, ClassReadError> {
310        match self
311            .constant_pool
312            .get(index as usize)
313            .ok_or(ClassReadError::InvalidIndex(index))?
314        {
315            CpInfo::Class { name_index } => self.cp_utf8(*name_index),
316            _ => Err(ClassReadError::InvalidIndex(index)),
317        }
318    }
319
320    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
321        let name = self.class_name(self.this_class)?.to_string();
322        let super_name = if self.super_class == 0 {
323            None
324        } else {
325            Some(self.class_name(self.super_class)?.to_string())
326        };
327        let source_file = self.attributes.iter().find_map(|attr| match attr {
328            AttributeInfo::SourceFile { sourcefile_index } => self
329                .cp_utf8(*sourcefile_index)
330                .ok()
331                .map(|value| value.to_string()),
332            _ => None,
333        });
334        let mut interfaces = Vec::with_capacity(self.interfaces.len());
335        for index in &self.interfaces {
336            interfaces.push(self.class_name(*index)?.to_string());
337        }
338
339        let mut fields = Vec::with_capacity(self.fields.len());
340        for field in &self.fields {
341            let name = self.cp_utf8(field.name_index)?.to_string();
342            let descriptor = self.cp_utf8(field.descriptor_index)?.to_string();
343            fields.push(crate::nodes::FieldNode {
344                access_flags: field.access_flags,
345                name,
346                descriptor,
347                attributes: field.attributes.clone(),
348            });
349        }
350
351        let mut methods = Vec::with_capacity(self.methods.len());
352        for method in &self.methods {
353            let name = self.cp_utf8(method.name_index)?.to_string();
354            let descriptor = self.cp_utf8(method.descriptor_index)?.to_string();
355            let mut method_attributes = method.attributes.clone();
356            method_attributes.retain(|attr| !matches!(attr, AttributeInfo::Code(_)));
357            let code = method.attributes.iter().find_map(|attr| match attr {
358                AttributeInfo::Code(code) => Some(code),
359                _ => None,
360            });
361
362            let (has_code, max_stack, max_locals, instructions, exception_table, code_attributes) =
363                if let Some(code) = code {
364                    let mut list = InsnList::new();
365                    for insn in &code.instructions {
366                        list.add(insn.clone());
367                    }
368                    (
369                        true,
370                        code.max_stack,
371                        code.max_locals,
372                        list,
373                        code.exception_table.clone(),
374                        code.attributes.clone(),
375                    )
376                } else {
377                    (false, 0, 0, InsnList::new(), Vec::new(), Vec::new())
378                };
379
380            methods.push(crate::nodes::MethodNode {
381                access_flags: method.access_flags,
382                name,
383                descriptor,
384                has_code,
385                max_stack,
386                max_locals,
387                instructions,
388                exception_table,
389                code_attributes,
390                attributes: method_attributes,
391            });
392        }
393
394        let mut inner_classes = Vec::new();
395        for attr in &self.attributes {
396            if let AttributeInfo::InnerClasses { classes } = attr {
397                for entry in classes {
398                    let name = self.class_name(entry.inner_class_info_index)?.to_string();
399                    let outer_name = if entry.outer_class_info_index == 0 {
400                        None
401                    } else {
402                        Some(self.class_name(entry.outer_class_info_index)?.to_string())
403                    };
404                    let inner_name = if entry.inner_name_index == 0 {
405                        None
406                    } else {
407                        Some(self.cp_utf8(entry.inner_name_index)?.to_string())
408                    };
409                    inner_classes.push(crate::nodes::InnerClassNode {
410                        name,
411                        outer_name,
412                        inner_name,
413                        access_flags: entry.inner_class_access_flags,
414                    });
415                }
416            }
417        }
418
419        let mut outer_class = String::new();
420        if let Some(class_index) = self.attributes.iter().find_map(|attr| match attr {
421            AttributeInfo::EnclosingMethod { class_index, .. } => Some(*class_index),
422            _ => None,
423        }) {
424            outer_class = self.class_name(class_index)?.to_string();
425        }
426        if outer_class.is_empty() {
427            for attr in &self.attributes {
428                if let AttributeInfo::InnerClasses { classes } = attr
429                    && let Some(entry) = classes.iter().find(|entry| {
430                        entry.inner_class_info_index == self.this_class
431                            && entry.outer_class_info_index != 0
432                    })
433                {
434                    outer_class = self.class_name(entry.outer_class_info_index)?.to_string();
435                    break;
436                }
437            }
438        }
439
440        Ok(crate::nodes::ClassNode {
441            minor_version: self.minor_version,
442            major_version: self.major_version,
443            access_flags: self.access_flags,
444            constant_pool: self.constant_pool.clone(),
445            this_class: self.this_class,
446            name,
447            super_name,
448            source_file,
449            interfaces,
450            interface_indices: self.interfaces.clone(),
451            fields,
452            methods,
453            attributes: self.attributes.clone(),
454            inner_classes,
455            outer_class,
456        })
457    }
458}
459
460#[derive(Debug, Clone)]
461pub struct FieldInfo {
462    pub access_flags: u16,
463    pub name_index: u16,
464    pub descriptor_index: u16,
465    pub attributes: Vec<AttributeInfo>,
466}
467
468#[derive(Debug, Clone)]
469pub struct MethodInfo {
470    pub access_flags: u16,
471    pub name_index: u16,
472    pub descriptor_index: u16,
473    pub attributes: Vec<AttributeInfo>,
474}
475
476#[derive(Debug, Clone)]
477pub enum AttributeInfo {
478    Code(CodeAttribute),
479    ConstantValue { constantvalue_index: u16 },
480    Exceptions { exception_index_table: Vec<u16> },
481    SourceFile { sourcefile_index: u16 },
482    LineNumberTable { entries: Vec<LineNumber> },
483    LocalVariableTable { entries: Vec<LocalVariable> },
484    Signature { signature_index: u16 },
485    StackMapTable { entries: Vec<StackMapFrame> },
486    Deprecated,
487    Synthetic,
488    InnerClasses { classes: Vec<InnerClass> },
489    EnclosingMethod { class_index: u16, method_index: u16 },
490    BootstrapMethods { methods: Vec<BootstrapMethod> },
491    MethodParameters { parameters: Vec<MethodParameter> },
492    RuntimeVisibleAnnotations { annotations: Vec<Annotation> },
493    RuntimeInvisibleAnnotations { annotations: Vec<Annotation> },
494    RuntimeVisibleParameterAnnotations { parameters: ParameterAnnotations },
495    RuntimeInvisibleParameterAnnotations { parameters: ParameterAnnotations },
496    RuntimeVisibleTypeAnnotations { annotations: Vec<TypeAnnotation> },
497    RuntimeInvisibleTypeAnnotations { annotations: Vec<TypeAnnotation> },
498    Unknown { name: String, info: Vec<u8> },
499}
500
501#[derive(Debug, Clone, PartialEq)]
502pub struct Annotation {
503    pub type_descriptor_index: u16,
504    pub element_value_pairs: Vec<ElementValuePair>,
505}
506
507#[derive(Debug, Clone, PartialEq)]
508pub struct ElementValuePair {
509    pub element_name_index: u16,
510    pub value: ElementValue,
511}
512
513#[derive(Debug, Clone, PartialEq)]
514pub enum ElementValue {
515    ConstValueIndex {
516        tag: u8,
517        const_value_index: u16,
518    },
519    EnumConstValue {
520        type_name_index: u16,
521        const_name_index: u16,
522    },
523    ClassInfoIndex {
524        class_info_index: u16,
525    },
526    AnnotationValue(Box<Annotation>),
527    ArrayValue(Vec<ElementValue>),
528}
529
530#[derive(Debug, Clone, PartialEq)]
531pub struct ParameterAnnotations {
532    pub parameters: Vec<Vec<Annotation>>,
533}
534
535#[derive(Debug, Clone, PartialEq)]
536pub struct TypeAnnotation {
537    pub target_type: u8,
538    pub target_info: TypeAnnotationTargetInfo,
539    pub target_path: TypePath,
540    pub annotation: Annotation,
541}
542
543#[derive(Debug, Clone, PartialEq)]
544pub struct TypePath {
545    pub path: Vec<TypePathEntry>,
546}
547
548#[derive(Debug, Clone, PartialEq)]
549pub struct TypePathEntry {
550    pub type_path_kind: u8,
551    pub type_argument_index: u8,
552}
553
554#[derive(Debug, Clone, PartialEq)]
555pub enum TypeAnnotationTargetInfo {
556    TypeParameter {
557        type_parameter_index: u8,
558    },
559    Supertype {
560        supertype_index: u16,
561    },
562    TypeParameterBound {
563        type_parameter_index: u8,
564        bound_index: u8,
565    },
566    Empty,
567    FormalParameter {
568        formal_parameter_index: u8,
569    },
570    Throws {
571        throws_type_index: u16,
572    },
573    LocalVar {
574        table: Vec<LocalVarTargetTableEntry>,
575    },
576    Catch {
577        exception_table_index: u16,
578    },
579    Offset {
580        offset: u16,
581    },
582    TypeArgument {
583        offset: u16,
584        type_argument_index: u8,
585    },
586}
587
588#[derive(Debug, Clone, PartialEq)]
589pub struct LocalVarTargetTableEntry {
590    pub start_pc: u16,
591    pub length: u16,
592    pub index: u16,
593}
594
595#[derive(Debug, Clone)]
596pub struct CodeAttribute {
597    pub max_stack: u16,
598    pub max_locals: u16,
599    pub code: Vec<u8>,
600    pub instructions: Vec<Insn>,
601    pub insn_nodes: Vec<AbstractInsnNode>,
602    pub exception_table: Vec<ExceptionTableEntry>,
603    pub try_catch_blocks: Vec<TryCatchBlockNode>,
604    pub attributes: Vec<AttributeInfo>,
605}
606
607#[derive(Debug, Clone)]
608pub struct ExceptionTableEntry {
609    pub start_pc: u16,
610    pub end_pc: u16,
611    pub handler_pc: u16,
612    pub catch_type: u16,
613}
614
615#[derive(Debug, Clone)]
616pub struct LineNumber {
617    pub start_pc: u16,
618    pub line_number: u16,
619}
620
621#[derive(Debug, Clone)]
622pub struct LocalVariable {
623    pub start_pc: u16,
624    pub length: u16,
625    pub name_index: u16,
626    pub descriptor_index: u16,
627    pub index: u16,
628}
629
630#[derive(Debug, Clone)]
631pub struct InnerClass {
632    pub inner_class_info_index: u16,
633    pub outer_class_info_index: u16,
634    pub inner_name_index: u16,
635    pub inner_class_access_flags: u16,
636}
637
638#[derive(Debug, Clone)]
639pub struct BootstrapMethod {
640    pub bootstrap_method_ref: u16,
641    pub bootstrap_arguments: Vec<u16>,
642}
643
644#[derive(Debug, Clone)]
645pub struct MethodParameter {
646    pub name_index: u16,
647    pub access_flags: u16,
648}
649
650#[derive(Debug, Clone, PartialEq, Eq)]
651pub enum VerificationTypeInfo {
652    Top,
653    Integer,
654    Float,
655    Long,
656    Double,
657    Null,
658    UninitializedThis,
659    Object { cpool_index: u16 },
660    Uninitialized { offset: u16 },
661}
662
663#[derive(Debug, Clone)]
664pub enum StackMapFrame {
665    SameFrame {
666        offset_delta: u16,
667    },
668    SameLocals1StackItemFrame {
669        offset_delta: u16,
670        stack: VerificationTypeInfo,
671    },
672    SameLocals1StackItemFrameExtended {
673        offset_delta: u16,
674        stack: VerificationTypeInfo,
675    },
676    ChopFrame {
677        offset_delta: u16,
678        k: u8,
679    },
680    SameFrameExtended {
681        offset_delta: u16,
682    },
683    AppendFrame {
684        offset_delta: u16,
685        locals: Vec<VerificationTypeInfo>,
686    },
687    FullFrame {
688        offset_delta: u16,
689        locals: Vec<VerificationTypeInfo>,
690        stack: Vec<VerificationTypeInfo>,
691    },
692}
693
694pub fn read_class_file(bytes: &[u8]) -> Result<ClassFile, ClassReadError> {
695    let mut reader = ByteReader::new(bytes);
696    let magic = reader.read_u4()?;
697    if magic != 0xCAFEBABE {
698        return Err(ClassReadError::InvalidMagic(magic));
699    }
700    let minor_version = reader.read_u2()?;
701    let major_version = reader.read_u2()?;
702    if major_version > constants::V25 {
703        return Err(ClassReadError::InvalidClassVersion(major_version));
704    }
705    let constant_pool = read_constant_pool(&mut reader)?;
706    let access_flags = reader.read_u2()?;
707    let this_class = reader.read_u2()?;
708    let super_class = reader.read_u2()?;
709    let interfaces = read_u2_table(&mut reader)?;
710    let fields = read_fields(&mut reader, &constant_pool)?;
711    let methods = read_methods(&mut reader, &constant_pool)?;
712    let attributes = read_attributes(&mut reader, &constant_pool)?;
713
714    Ok(ClassFile {
715        minor_version,
716        major_version,
717        constant_pool,
718        access_flags,
719        this_class,
720        super_class,
721        interfaces,
722        fields,
723        methods,
724        attributes,
725    })
726}
727
728fn read_constant_pool(reader: &mut ByteReader<'_>) -> Result<Vec<CpInfo>, ClassReadError> {
729    let count = reader.read_u2()? as usize;
730    let mut pool = Vec::with_capacity(count);
731    pool.push(CpInfo::Unusable);
732
733    let mut index = 1;
734    while index < count {
735        let tag = reader.read_u1()?;
736        let entry = match tag {
737            1 => {
738                let len = reader.read_u2()? as usize;
739                let bytes = reader.read_bytes(len)?;
740                let value = decode_modified_utf8(&bytes)?;
741                CpInfo::Utf8(value)
742            }
743            3 => {
744                let value = reader.read_u4()? as i32;
745                CpInfo::Integer(value)
746            }
747            4 => {
748                let value = f32::from_bits(reader.read_u4()?);
749                CpInfo::Float(value)
750            }
751            5 => {
752                let value = reader.read_u8()? as i64;
753                CpInfo::Long(value)
754            }
755            6 => {
756                let value = f64::from_bits(reader.read_u8()?);
757                CpInfo::Double(value)
758            }
759            7 => CpInfo::Class {
760                name_index: reader.read_u2()?,
761            },
762            8 => CpInfo::String {
763                string_index: reader.read_u2()?,
764            },
765            9 => CpInfo::Fieldref {
766                class_index: reader.read_u2()?,
767                name_and_type_index: reader.read_u2()?,
768            },
769            10 => CpInfo::Methodref {
770                class_index: reader.read_u2()?,
771                name_and_type_index: reader.read_u2()?,
772            },
773            11 => CpInfo::InterfaceMethodref {
774                class_index: reader.read_u2()?,
775                name_and_type_index: reader.read_u2()?,
776            },
777            12 => CpInfo::NameAndType {
778                name_index: reader.read_u2()?,
779                descriptor_index: reader.read_u2()?,
780            },
781            15 => CpInfo::MethodHandle {
782                reference_kind: reader.read_u1()?,
783                reference_index: reader.read_u2()?,
784            },
785            16 => CpInfo::MethodType {
786                descriptor_index: reader.read_u2()?,
787            },
788            17 => CpInfo::Dynamic {
789                bootstrap_method_attr_index: reader.read_u2()?,
790                name_and_type_index: reader.read_u2()?,
791            },
792            18 => CpInfo::InvokeDynamic {
793                bootstrap_method_attr_index: reader.read_u2()?,
794                name_and_type_index: reader.read_u2()?,
795            },
796            19 => CpInfo::Module {
797                name_index: reader.read_u2()?,
798            },
799            20 => CpInfo::Package {
800                name_index: reader.read_u2()?,
801            },
802            _ => return Err(ClassReadError::InvalidConstantPoolTag(tag)),
803        };
804
805        pool.push(entry);
806
807        if tag == 5 || tag == 6 {
808            pool.push(CpInfo::Unusable);
809            index += 2;
810        } else {
811            index += 1;
812        }
813    }
814
815    Ok(pool)
816}
817
818fn read_u2_table(reader: &mut ByteReader<'_>) -> Result<Vec<u16>, ClassReadError> {
819    let count = reader.read_u2()? as usize;
820    let mut values = Vec::with_capacity(count);
821    for _ in 0..count {
822        values.push(reader.read_u2()?);
823    }
824    Ok(values)
825}
826
827fn read_fields(
828    reader: &mut ByteReader<'_>,
829    cp: &[CpInfo],
830) -> Result<Vec<FieldInfo>, ClassReadError> {
831    let count = reader.read_u2()? as usize;
832    let mut fields = Vec::with_capacity(count);
833    for _ in 0..count {
834        let access_flags = reader.read_u2()?;
835        let name_index = reader.read_u2()?;
836        let descriptor_index = reader.read_u2()?;
837        let attributes = read_attributes(reader, cp)?;
838        fields.push(FieldInfo {
839            access_flags,
840            name_index,
841            descriptor_index,
842            attributes,
843        });
844    }
845    Ok(fields)
846}
847
848fn read_methods(
849    reader: &mut ByteReader<'_>,
850    cp: &[CpInfo],
851) -> Result<Vec<MethodInfo>, ClassReadError> {
852    let count = reader.read_u2()? as usize;
853    let mut methods = Vec::with_capacity(count);
854    for _ in 0..count {
855        let access_flags = reader.read_u2()?;
856        let name_index = reader.read_u2()?;
857        let descriptor_index = reader.read_u2()?;
858        let attributes = read_attributes(reader, cp)?;
859        methods.push(MethodInfo {
860            access_flags,
861            name_index,
862            descriptor_index,
863            attributes,
864        });
865    }
866    Ok(methods)
867}
868
869fn read_attributes(
870    reader: &mut ByteReader<'_>,
871    cp: &[CpInfo],
872) -> Result<Vec<AttributeInfo>, ClassReadError> {
873    let count = reader.read_u2()? as usize;
874    let mut attributes = Vec::with_capacity(count);
875    for _ in 0..count {
876        let name_index = reader.read_u2()?;
877        let length = reader.read_u4()? as usize;
878        let name = cp_utf8(cp, name_index)?;
879        let info = reader.read_bytes(length)?;
880        let attribute = parse_attribute(name, info, cp)?;
881        attributes.push(attribute);
882    }
883    Ok(attributes)
884}
885
886fn parse_attribute(
887    name: &str,
888    info: Vec<u8>,
889    cp: &[CpInfo],
890) -> Result<AttributeInfo, ClassReadError> {
891    let mut reader = ByteReader::new(&info);
892    let attribute = match name {
893        "Code" => {
894            let max_stack = reader.read_u2()?;
895            let max_locals = reader.read_u2()?;
896            let code_length = reader.read_u4()? as usize;
897            let code = reader.read_bytes(code_length)?;
898            let instructions = parse_code_instructions(&code)?;
899            let exception_table_length = reader.read_u2()? as usize;
900            let mut exception_table = Vec::with_capacity(exception_table_length);
901            for _ in 0..exception_table_length {
902                exception_table.push(ExceptionTableEntry {
903                    start_pc: reader.read_u2()?,
904                    end_pc: reader.read_u2()?,
905                    handler_pc: reader.read_u2()?,
906                    catch_type: reader.read_u2()?,
907                });
908            }
909            let attributes = read_attributes(&mut reader, cp)?;
910            let (insn_nodes, try_catch_blocks) = build_insn_nodes(&code, &exception_table, cp)?;
911            AttributeInfo::Code(CodeAttribute {
912                max_stack,
913                max_locals,
914                code,
915                instructions,
916                insn_nodes,
917                exception_table,
918                try_catch_blocks,
919                attributes,
920            })
921        }
922        "ConstantValue" => AttributeInfo::ConstantValue {
923            constantvalue_index: reader.read_u2()?,
924        },
925        "Exceptions" => {
926            let count = reader.read_u2()? as usize;
927            let mut exception_index_table = Vec::with_capacity(count);
928            for _ in 0..count {
929                exception_index_table.push(reader.read_u2()?);
930            }
931            AttributeInfo::Exceptions {
932                exception_index_table,
933            }
934        }
935        "SourceFile" => AttributeInfo::SourceFile {
936            sourcefile_index: reader.read_u2()?,
937        },
938        "LineNumberTable" => {
939            let count = reader.read_u2()? as usize;
940            let mut entries = Vec::with_capacity(count);
941            for _ in 0..count {
942                entries.push(LineNumber {
943                    start_pc: reader.read_u2()?,
944                    line_number: reader.read_u2()?,
945                });
946            }
947            AttributeInfo::LineNumberTable { entries }
948        }
949        "LocalVariableTable" => {
950            let count = reader.read_u2()? as usize;
951            let mut entries = Vec::with_capacity(count);
952            for _ in 0..count {
953                entries.push(LocalVariable {
954                    start_pc: reader.read_u2()?,
955                    length: reader.read_u2()?,
956                    name_index: reader.read_u2()?,
957                    descriptor_index: reader.read_u2()?,
958                    index: reader.read_u2()?,
959                });
960            }
961            AttributeInfo::LocalVariableTable { entries }
962        }
963        "Signature" => AttributeInfo::Signature {
964            signature_index: reader.read_u2()?,
965        },
966        "StackMapTable" => {
967            let count = reader.read_u2()? as usize;
968            let mut entries = Vec::with_capacity(count);
969            for _ in 0..count {
970                let frame_type = reader.read_u1()?;
971                let frame = match frame_type {
972                    0..=63 => StackMapFrame::SameFrame {
973                        offset_delta: frame_type as u16,
974                    },
975                    64..=127 => StackMapFrame::SameLocals1StackItemFrame {
976                        offset_delta: (frame_type - 64) as u16,
977                        stack: parse_verification_type(&mut reader)?,
978                    },
979                    247 => StackMapFrame::SameLocals1StackItemFrameExtended {
980                        offset_delta: reader.read_u2()?,
981                        stack: parse_verification_type(&mut reader)?,
982                    },
983                    248..=250 => StackMapFrame::ChopFrame {
984                        offset_delta: reader.read_u2()?,
985                        k: 251 - frame_type,
986                    },
987                    251 => StackMapFrame::SameFrameExtended {
988                        offset_delta: reader.read_u2()?,
989                    },
990                    252..=254 => {
991                        let offset_delta = reader.read_u2()?;
992                        let locals_count = (frame_type - 251) as usize;
993                        let mut locals = Vec::with_capacity(locals_count);
994                        for _ in 0..locals_count {
995                            locals.push(parse_verification_type(&mut reader)?);
996                        }
997                        StackMapFrame::AppendFrame {
998                            offset_delta,
999                            locals,
1000                        }
1001                    }
1002                    255 => {
1003                        let offset_delta = reader.read_u2()?;
1004                        let locals_count = reader.read_u2()? as usize;
1005                        let mut locals = Vec::with_capacity(locals_count);
1006                        for _ in 0..locals_count {
1007                            locals.push(parse_verification_type(&mut reader)?);
1008                        }
1009                        let stack_count = reader.read_u2()? as usize;
1010                        let mut stack = Vec::with_capacity(stack_count);
1011                        for _ in 0..stack_count {
1012                            stack.push(parse_verification_type(&mut reader)?);
1013                        }
1014                        StackMapFrame::FullFrame {
1015                            offset_delta,
1016                            locals,
1017                            stack,
1018                        }
1019                    }
1020                    _ => {
1021                        return Err(ClassReadError::InvalidAttribute(
1022                            "StackMapTable".to_string(),
1023                        ));
1024                    }
1025                };
1026                entries.push(frame);
1027            }
1028            AttributeInfo::StackMapTable { entries }
1029        }
1030        "Deprecated" => AttributeInfo::Deprecated,
1031        "Synthetic" => AttributeInfo::Synthetic,
1032        "InnerClasses" => {
1033            let count = reader.read_u2()? as usize;
1034            let mut classes = Vec::with_capacity(count);
1035            for _ in 0..count {
1036                classes.push(InnerClass {
1037                    inner_class_info_index: reader.read_u2()?,
1038                    outer_class_info_index: reader.read_u2()?,
1039                    inner_name_index: reader.read_u2()?,
1040                    inner_class_access_flags: reader.read_u2()?,
1041                });
1042            }
1043            AttributeInfo::InnerClasses { classes }
1044        }
1045        "EnclosingMethod" => AttributeInfo::EnclosingMethod {
1046            class_index: reader.read_u2()?,
1047            method_index: reader.read_u2()?,
1048        },
1049        "BootstrapMethods" => {
1050            let count = reader.read_u2()? as usize;
1051            let mut methods = Vec::with_capacity(count);
1052            for _ in 0..count {
1053                let bootstrap_method_ref = reader.read_u2()?;
1054                let arg_count = reader.read_u2()? as usize;
1055                let mut bootstrap_arguments = Vec::with_capacity(arg_count);
1056                for _ in 0..arg_count {
1057                    bootstrap_arguments.push(reader.read_u2()?);
1058                }
1059                methods.push(BootstrapMethod {
1060                    bootstrap_method_ref,
1061                    bootstrap_arguments,
1062                });
1063            }
1064            AttributeInfo::BootstrapMethods { methods }
1065        }
1066        "MethodParameters" => {
1067            let count = reader.read_u1()? as usize;
1068            let mut parameters = Vec::with_capacity(count);
1069            for _ in 0..count {
1070                parameters.push(MethodParameter {
1071                    name_index: reader.read_u2()?,
1072                    access_flags: reader.read_u2()?,
1073                });
1074            }
1075            AttributeInfo::MethodParameters { parameters }
1076        }
1077        "RuntimeVisibleAnnotations" => {
1078            let annotations = parse_annotations(&mut reader)?;
1079            AttributeInfo::RuntimeVisibleAnnotations { annotations }
1080        }
1081        "RuntimeInvisibleAnnotations" => {
1082            let annotations = parse_annotations(&mut reader)?;
1083            AttributeInfo::RuntimeInvisibleAnnotations { annotations }
1084        }
1085        "RuntimeVisibleParameterAnnotations" => {
1086            let parameters = parse_parameter_annotations(&mut reader)?;
1087            AttributeInfo::RuntimeVisibleParameterAnnotations { parameters }
1088        }
1089        "RuntimeInvisibleParameterAnnotations" => {
1090            let parameters = parse_parameter_annotations(&mut reader)?;
1091            AttributeInfo::RuntimeInvisibleParameterAnnotations { parameters }
1092        }
1093        "RuntimeVisibleTypeAnnotations" => {
1094            let annotations = parse_type_annotations(&mut reader)?;
1095            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations }
1096        }
1097        "RuntimeInvisibleTypeAnnotations" => {
1098            let annotations = parse_type_annotations(&mut reader)?;
1099            AttributeInfo::RuntimeInvisibleTypeAnnotations { annotations }
1100        }
1101        _ => {
1102            return Ok(AttributeInfo::Unknown {
1103                name: name.to_string(),
1104                info,
1105            });
1106        }
1107    };
1108
1109    if reader.remaining() != 0 {
1110        return Err(ClassReadError::InvalidAttribute(name.to_string()));
1111    }
1112
1113    Ok(attribute)
1114}
1115
1116fn parse_annotations(reader: &mut ByteReader) -> Result<Vec<Annotation>, ClassReadError> {
1117    let num = reader.read_u2()? as usize;
1118    let mut out = Vec::with_capacity(num);
1119    for _ in 0..num {
1120        out.push(parse_annotation(reader)?);
1121    }
1122    Ok(out)
1123}
1124
1125fn parse_annotation(reader: &mut ByteReader) -> Result<Annotation, ClassReadError> {
1126    let type_descriptor_index = reader.read_u2()?;
1127    let num_pairs = reader.read_u2()? as usize;
1128    let mut element_value_pairs = Vec::with_capacity(num_pairs);
1129    for _ in 0..num_pairs {
1130        let element_name_index = reader.read_u2()?;
1131        let value = parse_element_value(reader)?;
1132        element_value_pairs.push(ElementValuePair {
1133            element_name_index,
1134            value,
1135        });
1136    }
1137    Ok(Annotation {
1138        type_descriptor_index,
1139        element_value_pairs,
1140    })
1141}
1142
1143fn parse_parameter_annotations(
1144    reader: &mut ByteReader,
1145) -> Result<ParameterAnnotations, ClassReadError> {
1146    let num_params = reader.read_u1()? as usize;
1147    let mut parameters = Vec::with_capacity(num_params);
1148    for _ in 0..num_params {
1149        let num_ann = reader.read_u2()? as usize;
1150        let mut anns = Vec::with_capacity(num_ann);
1151        for _ in 0..num_ann {
1152            anns.push(parse_annotation(reader)?);
1153        }
1154        parameters.push(anns);
1155    }
1156    Ok(ParameterAnnotations { parameters })
1157}
1158
1159fn parse_type_annotations(reader: &mut ByteReader) -> Result<Vec<TypeAnnotation>, ClassReadError> {
1160    let num = reader.read_u2()? as usize;
1161    let mut out = Vec::with_capacity(num);
1162    for _ in 0..num {
1163        out.push(parse_type_annotation(reader)?);
1164    }
1165    Ok(out)
1166}
1167
1168fn parse_type_annotation(reader: &mut ByteReader) -> Result<TypeAnnotation, ClassReadError> {
1169    let target_type = reader.read_u1()?;
1170    let target_info = parse_type_annotation_target_info(reader, target_type)?;
1171    let target_path = parse_type_path(reader)?;
1172    let annotation = parse_annotation(reader)?;
1173    Ok(TypeAnnotation {
1174        target_type,
1175        target_info,
1176        target_path,
1177        annotation,
1178    })
1179}
1180
1181fn parse_type_path(reader: &mut ByteReader) -> Result<TypePath, ClassReadError> {
1182    let path_length = reader.read_u1()? as usize;
1183    let mut path = Vec::with_capacity(path_length);
1184    for _ in 0..path_length {
1185        path.push(TypePathEntry {
1186            type_path_kind: reader.read_u1()?,
1187            type_argument_index: reader.read_u1()?,
1188        });
1189    }
1190    Ok(TypePath { path })
1191}
1192
1193fn parse_type_annotation_target_info(
1194    reader: &mut ByteReader,
1195    target_type: u8,
1196) -> Result<TypeAnnotationTargetInfo, ClassReadError> {
1197    use crate::constants::*;
1198
1199    let ti = match target_type {
1200        TA_TARGET_CLASS_TYPE_PARAMETER | TA_TARGET_METHOD_TYPE_PARAMETER => {
1201            TypeAnnotationTargetInfo::TypeParameter {
1202                type_parameter_index: reader.read_u1()?,
1203            }
1204        }
1205
1206        TA_TARGET_CLASS_EXTENDS => TypeAnnotationTargetInfo::Supertype {
1207            supertype_index: reader.read_u2()?,
1208        },
1209
1210        TA_TARGET_CLASS_TYPE_PARAMETER_BOUND | TA_TARGET_METHOD_TYPE_PARAMETER_BOUND => {
1211            TypeAnnotationTargetInfo::TypeParameterBound {
1212                type_parameter_index: reader.read_u1()?,
1213                bound_index: reader.read_u1()?,
1214            }
1215        }
1216
1217        TA_TARGET_FIELD | TA_TARGET_METHOD_RETURN | TA_TARGET_METHOD_RECEIVER => {
1218            TypeAnnotationTargetInfo::Empty
1219        }
1220
1221        TA_TARGET_METHOD_FORMAL_PARAMETER => TypeAnnotationTargetInfo::FormalParameter {
1222            formal_parameter_index: reader.read_u1()?,
1223        },
1224
1225        TA_TARGET_THROWS => TypeAnnotationTargetInfo::Throws {
1226            throws_type_index: reader.read_u2()?,
1227        },
1228
1229        TA_TARGET_LOCAL_VARIABLE | TA_TARGET_RESOURCE_VARIABLE => {
1230            let table_length = reader.read_u2()? as usize;
1231            let mut table = Vec::with_capacity(table_length);
1232            for _ in 0..table_length {
1233                table.push(LocalVarTargetTableEntry {
1234                    start_pc: reader.read_u2()?,
1235                    length: reader.read_u2()?,
1236                    index: reader.read_u2()?,
1237                });
1238            }
1239            TypeAnnotationTargetInfo::LocalVar { table }
1240        }
1241
1242        TA_TARGET_EXCEPTION_PARAMETER => TypeAnnotationTargetInfo::Catch {
1243            exception_table_index: reader.read_u2()?,
1244        },
1245
1246        TA_TARGET_INSTANCEOF
1247        | TA_TARGET_NEW
1248        | TA_TARGET_CONSTRUCTOR_REFERENCE_RECEIVER
1249        | TA_TARGET_METHOD_REFERENCE_RECEIVER => TypeAnnotationTargetInfo::Offset {
1250            offset: reader.read_u2()?,
1251        },
1252
1253        TA_TARGET_CAST
1254        | TA_TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
1255        | TA_TARGET_METHOD_INVOCATION_TYPE_ARGUMENT
1256        | TA_TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
1257        | TA_TARGET_METHOD_REFERENCE_TYPE_ARGUMENT => TypeAnnotationTargetInfo::TypeArgument {
1258            offset: reader.read_u2()?,
1259            type_argument_index: reader.read_u1()?,
1260        },
1261
1262        _ => {
1263            return Err(ClassReadError::InvalidAttribute(format!(
1264                "TypeAnnotationTargetInfo(target_type=0x{:02X})",
1265                target_type
1266            )));
1267        }
1268    };
1269
1270    Ok(ti)
1271}
1272
1273fn parse_element_value(reader: &mut ByteReader) -> Result<ElementValue, ClassReadError> {
1274    let tag = reader.read_u1()?;
1275    let v = match tag {
1276        b'B' | b'C' | b'D' | b'F' | b'I' | b'J' | b'S' | b'Z' | b's' => {
1277            ElementValue::ConstValueIndex {
1278                tag,
1279                const_value_index: reader.read_u2()?,
1280            }
1281        }
1282        b'e' => ElementValue::EnumConstValue {
1283            type_name_index: reader.read_u2()?,
1284            const_name_index: reader.read_u2()?,
1285        },
1286        b'c' => ElementValue::ClassInfoIndex {
1287            class_info_index: reader.read_u2()?,
1288        },
1289        b'@' => ElementValue::AnnotationValue(Box::new(parse_annotation(reader)?)),
1290        b'[' => {
1291            let n = reader.read_u2()? as usize;
1292            let mut items = Vec::with_capacity(n);
1293            for _ in 0..n {
1294                items.push(parse_element_value(reader)?);
1295            }
1296            ElementValue::ArrayValue(items)
1297        }
1298        _ => {
1299            return Err(ClassReadError::InvalidAttribute(
1300                "AnnotationElementValue".to_string(),
1301            ));
1302        }
1303    };
1304    Ok(v)
1305}
1306
1307fn parse_verification_type(
1308    reader: &mut ByteReader<'_>,
1309) -> Result<VerificationTypeInfo, ClassReadError> {
1310    let tag = reader.read_u1()?;
1311    let kind = match tag {
1312        0 => VerificationTypeInfo::Top,
1313        1 => VerificationTypeInfo::Integer,
1314        2 => VerificationTypeInfo::Float,
1315        3 => VerificationTypeInfo::Double,
1316        4 => VerificationTypeInfo::Long,
1317        5 => VerificationTypeInfo::Null,
1318        6 => VerificationTypeInfo::UninitializedThis,
1319        7 => VerificationTypeInfo::Object {
1320            cpool_index: reader.read_u2()?,
1321        },
1322        8 => VerificationTypeInfo::Uninitialized {
1323            offset: reader.read_u2()?,
1324        },
1325        _ => {
1326            return Err(ClassReadError::InvalidAttribute(
1327                "StackMapTable".to_string(),
1328            ));
1329        }
1330    };
1331    Ok(kind)
1332}
1333
1334fn cp_utf8(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
1335    match cp.get(index as usize) {
1336        Some(CpInfo::Utf8(value)) => Ok(value.as_str()),
1337        _ => Err(ClassReadError::InvalidIndex(index)),
1338    }
1339}
1340
1341fn cp_class_name(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
1342    match cp.get(index as usize) {
1343        Some(CpInfo::Class { name_index }) => cp_utf8(cp, *name_index),
1344        _ => Err(ClassReadError::InvalidIndex(index)),
1345    }
1346}
1347
1348fn cp_name_and_type(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
1349    match cp.get(index as usize) {
1350        Some(CpInfo::NameAndType {
1351            name_index,
1352            descriptor_index,
1353        }) => Ok((cp_utf8(cp, *name_index)?, cp_utf8(cp, *descriptor_index)?)),
1354        _ => Err(ClassReadError::InvalidIndex(index)),
1355    }
1356}
1357
1358fn cp_field_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str), ClassReadError> {
1359    match cp.get(index as usize) {
1360        Some(CpInfo::Fieldref {
1361            class_index,
1362            name_and_type_index,
1363        }) => {
1364            let owner = cp_class_name(cp, *class_index)?;
1365            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1366            Ok((owner, name, desc))
1367        }
1368        _ => Err(ClassReadError::InvalidIndex(index)),
1369    }
1370}
1371
1372fn cp_method_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str, bool), ClassReadError> {
1373    match cp.get(index as usize) {
1374        Some(CpInfo::Methodref {
1375            class_index,
1376            name_and_type_index,
1377        }) => {
1378            let owner = cp_class_name(cp, *class_index)?;
1379            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1380            Ok((owner, name, desc, false))
1381        }
1382        Some(CpInfo::InterfaceMethodref {
1383            class_index,
1384            name_and_type_index,
1385        }) => {
1386            let owner = cp_class_name(cp, *class_index)?;
1387            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1388            Ok((owner, name, desc, true))
1389        }
1390        _ => Err(ClassReadError::InvalidIndex(index)),
1391    }
1392}
1393
1394fn cp_invoke_dynamic(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
1395    match cp.get(index as usize) {
1396        Some(CpInfo::InvokeDynamic {
1397            name_and_type_index,
1398            ..
1399        }) => cp_name_and_type(cp, *name_and_type_index),
1400        _ => Err(ClassReadError::InvalidIndex(index)),
1401    }
1402}
1403
1404fn cp_ldc_constant(cp: &[CpInfo], index: u16) -> Result<LdcConstant, ClassReadError> {
1405    match cp.get(index as usize) {
1406        Some(CpInfo::Integer(value)) => Ok(LdcConstant::Integer(*value)),
1407        Some(CpInfo::Float(value)) => Ok(LdcConstant::Float(*value)),
1408        Some(CpInfo::Long(value)) => Ok(LdcConstant::Long(*value)),
1409        Some(CpInfo::Double(value)) => Ok(LdcConstant::Double(*value)),
1410        Some(CpInfo::String { string_index }) => {
1411            Ok(LdcConstant::String(cp_utf8(cp, *string_index)?.to_string()))
1412        }
1413        Some(CpInfo::Class { name_index }) => {
1414            Ok(LdcConstant::Class(cp_utf8(cp, *name_index)?.to_string()))
1415        }
1416        Some(CpInfo::MethodType { descriptor_index }) => Ok(LdcConstant::MethodType(
1417            cp_utf8(cp, *descriptor_index)?.to_string(),
1418        )),
1419        Some(CpInfo::MethodHandle {
1420            reference_kind,
1421            reference_index,
1422        }) => Ok(LdcConstant::MethodHandle {
1423            reference_kind: *reference_kind,
1424            reference_index: *reference_index,
1425        }),
1426        Some(CpInfo::Dynamic { .. }) => Ok(LdcConstant::Dynamic),
1427        _ => Err(ClassReadError::InvalidIndex(index)),
1428    }
1429}
1430
1431fn decode_modified_utf8(bytes: &[u8]) -> Result<String, ClassReadError> {
1432    let mut code_units = Vec::with_capacity(bytes.len());
1433    let mut i = 0;
1434    while i < bytes.len() {
1435        let byte = bytes[i];
1436        if byte & 0x80 == 0 {
1437            code_units.push(byte as u16);
1438            i += 1;
1439        } else if byte & 0xE0 == 0xC0 {
1440            if i + 1 >= bytes.len() {
1441                return Err(ClassReadError::Utf8Error("truncated 2-byte".to_string()));
1442            }
1443            let byte2 = bytes[i + 1];
1444            if byte2 & 0xC0 != 0x80 {
1445                return Err(ClassReadError::Utf8Error("invalid 2-byte".to_string()));
1446            }
1447            let value = (((byte & 0x1F) as u16) << 6) | ((byte2 & 0x3F) as u16);
1448            code_units.push(value);
1449            i += 2;
1450        } else if byte & 0xF0 == 0xE0 {
1451            if i + 2 >= bytes.len() {
1452                return Err(ClassReadError::Utf8Error("truncated 3-byte".to_string()));
1453            }
1454            let byte2 = bytes[i + 1];
1455            let byte3 = bytes[i + 2];
1456            if byte2 & 0xC0 != 0x80 || byte3 & 0xC0 != 0x80 {
1457                return Err(ClassReadError::Utf8Error("invalid 3-byte".to_string()));
1458            }
1459            let value = (((byte & 0x0F) as u16) << 12)
1460                | (((byte2 & 0x3F) as u16) << 6)
1461                | ((byte3 & 0x3F) as u16);
1462            code_units.push(value);
1463            i += 3;
1464        } else {
1465            return Err(ClassReadError::Utf8Error(
1466                "invalid leading byte".to_string(),
1467            ));
1468        }
1469    }
1470
1471    String::from_utf16(&code_units)
1472        .map_err(|_| ClassReadError::Utf8Error("invalid utf16".to_string()))
1473}
1474
1475fn parse_code_instructions(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
1476    let mut reader = ByteReader::new(code);
1477    let mut insns = Vec::new();
1478
1479    while reader.remaining() > 0 {
1480        let opcode_offset = reader.pos();
1481        let opcode = reader.read_u1()?;
1482        let insn = match opcode {
1483            opcodes::NOP..=opcodes::DCONST_1 => Insn::Simple(opcode.into()),
1484            opcodes::BIPUSH => Insn::Int(IntInsnNode {
1485                insn: opcode.into(),
1486                operand: reader.read_i1()? as i32,
1487            }),
1488            opcodes::SIPUSH => Insn::Int(IntInsnNode {
1489                insn: opcode.into(),
1490                operand: reader.read_i2()? as i32,
1491            }),
1492            opcodes::LDC => Insn::Ldc(LdcInsnNode {
1493                insn: opcode.into(),
1494                value: LdcValue::Index(reader.read_u1()? as u16),
1495            }),
1496            opcodes::LDC_W | opcodes::LDC2_W => Insn::Ldc(LdcInsnNode {
1497                insn: opcode.into(),
1498                value: LdcValue::Index(reader.read_u2()?),
1499            }),
1500            opcodes::ILOAD..=opcodes::ALOAD => Insn::Var(VarInsnNode {
1501                insn: opcode.into(),
1502                var_index: reader.read_u1()? as u16,
1503            }),
1504            opcodes::ILOAD_0..=opcodes::SALOAD => Insn::Simple(opcode.into()),
1505            opcodes::ISTORE..=opcodes::ASTORE => Insn::Var(VarInsnNode {
1506                insn: opcode.into(),
1507                var_index: reader.read_u1()? as u16,
1508            }),
1509            opcodes::ISTORE_0..=opcodes::SASTORE => Insn::Simple(opcode.into()),
1510            opcodes::POP..=opcodes::LXOR => Insn::Simple(opcode.into()),
1511            opcodes::IINC => Insn::Iinc(IincInsnNode {
1512                insn: opcode.into(),
1513                var_index: reader.read_u1()? as u16,
1514                increment: reader.read_i1()? as i16,
1515            }),
1516            opcodes::I2L..=opcodes::DCMPG => Insn::Simple(opcode.into()),
1517            opcodes::IFEQ..=opcodes::JSR => Insn::Jump(JumpInsnNode {
1518                insn: opcode.into(),
1519                offset: reader.read_i2()? as i32,
1520            }),
1521            opcodes::RET => Insn::Var(VarInsnNode {
1522                insn: opcode.into(),
1523                var_index: reader.read_u1()? as u16,
1524            }),
1525            opcodes::TABLESWITCH => read_table_switch(&mut reader, opcode_offset)?,
1526            opcodes::LOOKUPSWITCH => read_lookup_switch(&mut reader, opcode_offset)?,
1527            opcodes::IRETURN..=opcodes::RETURN => Insn::Simple(InsnNode { opcode }),
1528            opcodes::GETSTATIC..=opcodes::PUTFIELD => Insn::Field(FieldInsnNode {
1529                insn: opcode.into(),
1530                field_ref: MemberRef::Index(reader.read_u2()?),
1531            }),
1532            opcodes::INVOKEVIRTUAL..=opcodes::INVOKESTATIC => Insn::Method(MethodInsnNode {
1533                insn: opcode.into(),
1534                method_ref: MemberRef::Index(reader.read_u2()?),
1535            }),
1536            opcodes::INVOKEINTERFACE => {
1537                let method_index = reader.read_u2()?;
1538                let count = reader.read_u1()?;
1539                let _ = reader.read_u1()?;
1540                Insn::InvokeInterface(InvokeInterfaceInsnNode {
1541                    insn: opcode.into(),
1542                    method_index,
1543                    count,
1544                })
1545            }
1546            opcodes::INVOKEDYNAMIC => {
1547                let method_index = reader.read_u2()?;
1548                let _ = reader.read_u2()?;
1549                Insn::InvokeDynamic(InvokeDynamicInsnNode::from_index(method_index))
1550            }
1551            opcodes::NEW => Insn::Type(TypeInsnNode {
1552                insn: opcode.into(),
1553                type_index: reader.read_u2()?,
1554            }),
1555            opcodes::NEWARRAY => Insn::Int(IntInsnNode {
1556                insn: opcode.into(),
1557                operand: reader.read_u1()? as i32,
1558            }),
1559            opcodes::ANEWARRAY => Insn::Type(TypeInsnNode {
1560                insn: opcode.into(),
1561                type_index: reader.read_u2()?,
1562            }),
1563            opcodes::ARRAYLENGTH | opcodes::ATHROW => Insn::Simple(opcode.into()),
1564            opcodes::CHECKCAST | opcodes::INSTANCEOF => Insn::Type(TypeInsnNode {
1565                insn: opcode.into(),
1566                type_index: reader.read_u2()?,
1567            }),
1568            opcodes::MONITORENTER | opcodes::MONITOREXIT => Insn::Simple(opcode.into()),
1569            opcodes::WIDE => read_wide(&mut reader)?,
1570            opcodes::MULTIANEWARRAY => Insn::MultiANewArray(MultiANewArrayInsnNode {
1571                insn: opcode.into(),
1572                type_index: reader.read_u2()?,
1573                dimensions: reader.read_u1()?,
1574            }),
1575            opcodes::IFNULL | opcodes::IFNONNULL => Insn::Jump(JumpInsnNode {
1576                insn: opcode.into(),
1577                offset: reader.read_i2()? as i32,
1578            }),
1579            opcodes::GOTO_W | opcodes::JSR_W => Insn::Jump(JumpInsnNode {
1580                insn: opcode.into(),
1581                offset: reader.read_i4()?,
1582            }),
1583            opcodes::BREAKPOINT => Insn::Simple(opcode.into()),
1584            opcodes::IMPDEP1 | opcodes::IMPDEP2 => Insn::Simple(opcode.into()),
1585            _ => {
1586                return Err(ClassReadError::InvalidOpcode {
1587                    opcode,
1588                    offset: opcode_offset,
1589                });
1590            }
1591        };
1592
1593        insns.push(insn);
1594    }
1595
1596    Ok(insns)
1597}
1598
1599pub(crate) fn parse_code_instructions_public(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
1600    parse_code_instructions(code)
1601}
1602
1603#[derive(Debug, Clone)]
1604struct ParsedInstruction {
1605    offset: u16,
1606    insn: Insn,
1607}
1608
1609fn parse_code_instructions_with_offsets(
1610    code: &[u8],
1611) -> Result<Vec<ParsedInstruction>, ClassReadError> {
1612    let mut reader = ByteReader::new(code);
1613    let mut insns = Vec::new();
1614
1615    while reader.remaining() > 0 {
1616        let opcode_offset = reader.pos();
1617        let opcode = reader.read_u1()?;
1618        let insn = match opcode {
1619            opcodes::NOP..=opcodes::DCONST_1 => Insn::Simple(opcode.into()),
1620            opcodes::BIPUSH => Insn::Int(IntInsnNode {
1621                insn: opcode.into(),
1622                operand: reader.read_i1()? as i32,
1623            }),
1624            opcodes::SIPUSH => Insn::Int(IntInsnNode {
1625                insn: opcode.into(),
1626                operand: reader.read_i2()? as i32,
1627            }),
1628            opcodes::LDC => Insn::Ldc(LdcInsnNode {
1629                insn: opcode.into(),
1630                value: LdcValue::Index(reader.read_u1()? as u16),
1631            }),
1632            opcodes::LDC_W | opcodes::LDC2_W => Insn::Ldc(LdcInsnNode {
1633                insn: opcode.into(),
1634                value: LdcValue::Index(reader.read_u2()?),
1635            }),
1636            opcodes::ILOAD..=opcodes::ALOAD => Insn::Var(VarInsnNode {
1637                insn: opcode.into(),
1638                var_index: reader.read_u1()? as u16,
1639            }),
1640            opcodes::ILOAD_0..=opcodes::SALOAD => Insn::Simple(opcode.into()),
1641            opcodes::ISTORE..=opcodes::ASTORE => Insn::Var(VarInsnNode {
1642                insn: opcode.into(),
1643                var_index: reader.read_u1()? as u16,
1644            }),
1645            opcodes::ISTORE_0..=opcodes::SASTORE => Insn::Simple(opcode.into()),
1646            opcodes::POP..=opcodes::LXOR => Insn::Simple(opcode.into()),
1647            opcodes::IINC => Insn::Iinc(IincInsnNode {
1648                insn: opcode.into(),
1649                var_index: reader.read_u1()? as u16,
1650                increment: reader.read_i1()? as i16,
1651            }),
1652            opcodes::I2L..=opcodes::DCMPG => Insn::Simple(opcode.into()),
1653            opcodes::IFEQ..=opcodes::JSR => Insn::Jump(JumpInsnNode {
1654                insn: opcode.into(),
1655                offset: reader.read_i2()? as i32,
1656            }),
1657            opcodes::RET => Insn::Var(VarInsnNode {
1658                insn: opcode.into(),
1659                var_index: reader.read_u1()? as u16,
1660            }),
1661            opcodes::TABLESWITCH => read_table_switch(&mut reader, opcode_offset)?,
1662            opcodes::LOOKUPSWITCH => read_lookup_switch(&mut reader, opcode_offset)?,
1663            opcodes::IRETURN..=opcodes::RETURN => Insn::Simple(opcode.into()),
1664            opcodes::GETSTATIC..=opcodes::PUTFIELD => Insn::Field(FieldInsnNode {
1665                insn: opcode.into(),
1666                field_ref: MemberRef::Index(reader.read_u2()?),
1667            }),
1668            opcodes::INVOKEVIRTUAL..=opcodes::INVOKESTATIC => Insn::Method(MethodInsnNode {
1669                insn: opcode.into(),
1670                method_ref: MemberRef::Index(reader.read_u2()?),
1671            }),
1672            opcodes::INVOKEINTERFACE => {
1673                let method_index = reader.read_u2()?;
1674                let count = reader.read_u1()?;
1675                let _ = reader.read_u1()?;
1676                Insn::InvokeInterface(InvokeInterfaceInsnNode {
1677                    insn: opcode.into(),
1678                    method_index,
1679                    count,
1680                })
1681            }
1682            opcodes::INVOKEDYNAMIC => {
1683                let method_index = reader.read_u2()?;
1684                let _ = reader.read_u2()?;
1685                Insn::InvokeDynamic(InvokeDynamicInsnNode::from_index(method_index))
1686            }
1687            opcodes::NEW => Insn::Type(TypeInsnNode {
1688                insn: opcode.into(),
1689                type_index: reader.read_u2()?,
1690            }),
1691            opcodes::NEWARRAY => Insn::Int(IntInsnNode {
1692                insn: opcode.into(),
1693                operand: reader.read_u1()? as i32,
1694            }),
1695            opcodes::ANEWARRAY => Insn::Type(TypeInsnNode {
1696                insn: opcode.into(),
1697                type_index: reader.read_u2()?,
1698            }),
1699            opcodes::ARRAYLENGTH | opcodes::ATHROW => Insn::Simple(opcode.into()),
1700            opcodes::CHECKCAST | opcodes::INSTANCEOF => Insn::Type(TypeInsnNode {
1701                insn: opcode.into(),
1702                type_index: reader.read_u2()?,
1703            }),
1704            opcodes::MONITORENTER | opcodes::MONITOREXIT => Insn::Simple(opcode.into()),
1705            opcodes::WIDE => read_wide(&mut reader)?,
1706            opcodes::MULTIANEWARRAY => Insn::MultiANewArray(MultiANewArrayInsnNode {
1707                insn: opcode.into(),
1708                type_index: reader.read_u2()?,
1709                dimensions: reader.read_u1()?,
1710            }),
1711            opcodes::IFNULL | opcodes::IFNONNULL => Insn::Jump(JumpInsnNode {
1712                insn: opcode.into(),
1713                offset: reader.read_i2()? as i32,
1714            }),
1715            opcodes::GOTO_W | opcodes::JSR_W => Insn::Jump(JumpInsnNode {
1716                insn: opcode.into(),
1717                offset: reader.read_i4()?,
1718            }),
1719            opcodes::BREAKPOINT => Insn::Simple(opcode.into()),
1720            opcodes::IMPDEP1 | opcodes::IMPDEP2 => Insn::Simple(opcode.into()),
1721            _ => {
1722                return Err(ClassReadError::InvalidOpcode {
1723                    opcode,
1724                    offset: opcode_offset,
1725                });
1726            }
1727        };
1728
1729        insns.push(ParsedInstruction {
1730            offset: opcode_offset as u16,
1731            insn,
1732        });
1733    }
1734
1735    Ok(insns)
1736}
1737
1738fn build_insn_nodes(
1739    code: &[u8],
1740    exception_table: &[ExceptionTableEntry],
1741    cp: &[CpInfo],
1742) -> Result<(Vec<AbstractInsnNode>, Vec<TryCatchBlockNode>), ClassReadError> {
1743    let instructions = parse_code_instructions_with_offsets(code)?;
1744    let mut offsets = std::collections::HashSet::new();
1745    for instruction in &instructions {
1746        offsets.insert(instruction.offset);
1747        match &instruction.insn {
1748            Insn::Jump(node) => {
1749                offsets.insert((instruction.offset as i32 + node.offset) as u16);
1750            }
1751            Insn::TableSwitch(node) => {
1752                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
1753                for offset in &node.offsets {
1754                    offsets.insert((instruction.offset as i32 + *offset) as u16);
1755                }
1756            }
1757            Insn::LookupSwitch(node) => {
1758                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
1759                for (_, offset) in &node.pairs {
1760                    offsets.insert((instruction.offset as i32 + *offset) as u16);
1761                }
1762            }
1763            _ => {}
1764        }
1765    }
1766    for entry in exception_table {
1767        offsets.insert(entry.start_pc);
1768        offsets.insert(entry.end_pc);
1769        offsets.insert(entry.handler_pc);
1770    }
1771    offsets.insert(code.len() as u16);
1772
1773    let mut label_by_offset = std::collections::HashMap::new();
1774    for (next_id, offset) in offsets.into_iter().enumerate() {
1775        label_by_offset.insert(offset, LabelNode { id: next_id });
1776    }
1777
1778    let mut nodes = Vec::new();
1779    for instruction in instructions {
1780        if let Some(label) = label_by_offset.get(&{ instruction.offset }) {
1781            nodes.push(AbstractInsnNode::Label(*label));
1782        }
1783        nodes.push(AbstractInsnNode::Insn(instruction.insn));
1784    }
1785    if let Some(label) = label_by_offset.get(&(code.len() as u16)) {
1786        nodes.push(AbstractInsnNode::Label(*label));
1787    }
1788
1789    let mut try_catch_blocks = Vec::new();
1790    for entry in exception_table {
1791        let start = *label_by_offset
1792            .get(&entry.start_pc)
1793            .ok_or_else(|| ClassReadError::InvalidAttribute("missing start label".to_string()))?;
1794        let end = *label_by_offset
1795            .get(&entry.end_pc)
1796            .ok_or_else(|| ClassReadError::InvalidAttribute("missing end label".to_string()))?;
1797        let handler = *label_by_offset
1798            .get(&entry.handler_pc)
1799            .ok_or_else(|| ClassReadError::InvalidAttribute("missing handler label".to_string()))?;
1800        let catch_type = if entry.catch_type == 0 {
1801            None
1802        } else {
1803            Some(cp_class_name(cp, entry.catch_type)?.to_string())
1804        };
1805        try_catch_blocks.push(TryCatchBlockNode {
1806            start,
1807            end,
1808            handler,
1809            catch_type,
1810        });
1811    }
1812
1813    Ok((nodes, try_catch_blocks))
1814}
1815
1816pub(crate) fn build_insn_nodes_public(
1817    code: &[u8],
1818    exception_table: &[ExceptionTableEntry],
1819    cp: &[CpInfo],
1820) -> Result<(Vec<AbstractInsnNode>, Vec<TryCatchBlockNode>), ClassReadError> {
1821    build_insn_nodes(code, exception_table, cp)
1822}
1823
1824fn read_table_switch(
1825    reader: &mut ByteReader<'_>,
1826    opcode_offset: usize,
1827) -> Result<Insn, ClassReadError> {
1828    reader.align4(opcode_offset)?;
1829    let default_offset = reader.read_i4()?;
1830    let low = reader.read_i4()?;
1831    let high = reader.read_i4()?;
1832    let count = if high < low {
1833        0
1834    } else {
1835        (high - low + 1) as usize
1836    };
1837    let mut offsets = Vec::with_capacity(count);
1838    for _ in 0..count {
1839        offsets.push(reader.read_i4()?);
1840    }
1841    Ok(Insn::TableSwitch(TableSwitchInsnNode {
1842        insn: opcodes::TABLESWITCH.into(),
1843        default_offset,
1844        low,
1845        high,
1846        offsets,
1847    }))
1848}
1849
1850fn read_lookup_switch(
1851    reader: &mut ByteReader<'_>,
1852    opcode_offset: usize,
1853) -> Result<Insn, ClassReadError> {
1854    reader.align4(opcode_offset)?;
1855    let default_offset = reader.read_i4()?;
1856    let npairs = reader.read_i4()? as usize;
1857    let mut pairs = Vec::with_capacity(npairs);
1858    for _ in 0..npairs {
1859        let key = reader.read_i4()?;
1860        let offset = reader.read_i4()?;
1861        pairs.push((key, offset));
1862    }
1863    Ok(Insn::LookupSwitch(LookupSwitchInsnNode {
1864        insn: opcodes::LOOKUPSWITCH.into(),
1865        default_offset,
1866        pairs,
1867    }))
1868}
1869
1870fn read_wide(reader: &mut ByteReader<'_>) -> Result<Insn, ClassReadError> {
1871    let opcode = reader.read_u1()?;
1872    match opcode {
1873        opcodes::ILOAD..=opcodes::ALOAD | opcodes::ISTORE..=opcodes::ASTORE | opcodes::RET => {
1874            Ok(Insn::Var(VarInsnNode {
1875                insn: opcode.into(),
1876                var_index: reader.read_u2()?,
1877            }))
1878        }
1879        opcodes::IINC => Ok(Insn::Iinc(IincInsnNode {
1880            insn: opcode.into(),
1881            var_index: reader.read_u2()?,
1882            increment: reader.read_i2()?,
1883        })),
1884        _ => Err(ClassReadError::InvalidOpcode {
1885            opcode,
1886            offset: reader.pos().saturating_sub(1),
1887        }),
1888    }
1889}
1890
1891fn visit_instruction(
1892    cp: &[CpInfo],
1893    offset: i32,
1894    insn: Insn,
1895    mv: &mut dyn MethodVisitor,
1896) -> Result<(), ClassReadError> {
1897    match insn {
1898        Insn::Simple(node) => {
1899            mv.visit_insn(node.opcode);
1900        }
1901        Insn::Int(node) => {
1902            mv.visit_int_insn(node.insn.opcode, node.operand);
1903        }
1904        Insn::Var(node) => {
1905            mv.visit_var_insn(node.insn.opcode, node.var_index);
1906        }
1907        Insn::Type(node) => {
1908            let type_name = cp_class_name(cp, node.type_index)?;
1909            mv.visit_type_insn(node.insn.opcode, type_name);
1910        }
1911        Insn::Field(node) => {
1912            let index = match node.field_ref {
1913                MemberRef::Index(index) => index,
1914                MemberRef::Symbolic { .. } => {
1915                    return Err(ClassReadError::InvalidIndex(0));
1916                }
1917            };
1918            let (owner, name, desc) = cp_field_ref(cp, index)?;
1919            mv.visit_field_insn(node.insn.opcode, owner, name, desc);
1920        }
1921        Insn::Method(node) => {
1922            let index = match node.method_ref {
1923                MemberRef::Index(index) => index,
1924                MemberRef::Symbolic { .. } => {
1925                    return Err(ClassReadError::InvalidIndex(0));
1926                }
1927            };
1928            let (owner, name, desc, is_interface) = cp_method_ref(cp, index)?;
1929            mv.visit_method_insn(node.insn.opcode, owner, name, desc, is_interface);
1930        }
1931        Insn::InvokeInterface(node) => {
1932            let (owner, name, desc, _is_interface) = cp_method_ref(cp, node.method_index)?;
1933            mv.visit_method_insn(node.insn.opcode, owner, name, desc, true);
1934        }
1935        Insn::InvokeDynamic(node) => {
1936            let (name, desc) = cp_invoke_dynamic(cp, node.method_index)?;
1937            mv.visit_invoke_dynamic_insn(name, desc);
1938        }
1939        Insn::Jump(node) => {
1940            let target = offset + node.offset;
1941            mv.visit_jump_insn(node.insn.opcode, target);
1942        }
1943        Insn::Ldc(node) => {
1944            let index = match node.value {
1945                LdcValue::Index(index) => index,
1946                LdcValue::String(value) => {
1947                    mv.visit_ldc_insn(LdcConstant::String(value));
1948                    return Ok(());
1949                }
1950                LdcValue::Type(value) => {
1951                    match value.clone() {
1952                        Type::Method { .. } => {
1953                            mv.visit_ldc_insn(LdcConstant::MethodType(value.get_descriptor()));
1954                        }
1955                        _ => {
1956                            mv.visit_ldc_insn(LdcConstant::Class(value.get_descriptor()));
1957                        }
1958                    }
1959
1960                    return Ok(());
1961                }
1962                LdcValue::Int(value) => {
1963                    mv.visit_ldc_insn(LdcConstant::Integer(value));
1964                    return Ok(());
1965                }
1966                LdcValue::Float(value) => {
1967                    mv.visit_ldc_insn(LdcConstant::Float(value));
1968                    return Ok(());
1969                }
1970                LdcValue::Long(value) => {
1971                    mv.visit_ldc_insn(LdcConstant::Long(value));
1972                    return Ok(());
1973                }
1974                LdcValue::Double(value) => {
1975                    mv.visit_ldc_insn(LdcConstant::Double(value));
1976                    return Ok(());
1977                }
1978            };
1979            let constant = cp_ldc_constant(cp, index)?;
1980            mv.visit_ldc_insn(constant);
1981        }
1982        Insn::Iinc(node) => {
1983            mv.visit_iinc_insn(node.var_index, node.increment);
1984        }
1985        Insn::TableSwitch(node) => {
1986            let targets = node
1987                .offsets
1988                .iter()
1989                .map(|value| offset + *value)
1990                .collect::<Vec<_>>();
1991            mv.visit_table_switch(offset + node.default_offset, node.low, node.high, &targets);
1992        }
1993        Insn::LookupSwitch(node) => {
1994            let pairs = node
1995                .pairs
1996                .iter()
1997                .map(|(key, value)| (*key, offset + *value))
1998                .collect::<Vec<_>>();
1999            mv.visit_lookup_switch(offset + node.default_offset, &pairs);
2000        }
2001        Insn::MultiANewArray(node) => {
2002            let type_name = cp_class_name(cp, node.type_index)?;
2003            mv.visit_multi_anewarray_insn(type_name, node.dimensions);
2004        }
2005    }
2006    Ok(())
2007}
2008
2009pub struct ByteReader<'a> {
2010    data: &'a [u8],
2011    pos: usize,
2012}
2013
2014impl<'a> ByteReader<'a> {
2015    pub fn new(data: &'a [u8]) -> Self {
2016        Self { data, pos: 0 }
2017    }
2018
2019    pub fn remaining(&self) -> usize {
2020        self.data.len().saturating_sub(self.pos)
2021    }
2022
2023    pub fn pos(&self) -> usize {
2024        self.pos
2025    }
2026
2027    pub fn align4(&mut self, opcode_offset: usize) -> Result<(), ClassReadError> {
2028        let mut padding = (4 - ((opcode_offset + 1) % 4)) % 4;
2029        while padding > 0 {
2030            self.read_u1()?;
2031            padding -= 1;
2032        }
2033        Ok(())
2034    }
2035
2036    pub fn read_u1(&mut self) -> Result<u8, ClassReadError> {
2037        if self.pos >= self.data.len() {
2038            return Err(ClassReadError::UnexpectedEof);
2039        }
2040        let value = self.data[self.pos];
2041        self.pos += 1;
2042        Ok(value)
2043    }
2044
2045    pub fn read_i1(&mut self) -> Result<i8, ClassReadError> {
2046        Ok(self.read_u1()? as i8)
2047    }
2048
2049    pub fn read_u2(&mut self) -> Result<u16, ClassReadError> {
2050        let bytes = self.read_bytes(2)?;
2051        Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
2052    }
2053
2054    pub fn read_i2(&mut self) -> Result<i16, ClassReadError> {
2055        Ok(self.read_u2()? as i16)
2056    }
2057
2058    pub fn read_u4(&mut self) -> Result<u32, ClassReadError> {
2059        let bytes = self.read_bytes(4)?;
2060        Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
2061    }
2062
2063    pub fn read_i4(&mut self) -> Result<i32, ClassReadError> {
2064        let bytes = self.read_bytes(4)?;
2065        Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
2066    }
2067
2068    pub fn read_u8(&mut self) -> Result<u64, ClassReadError> {
2069        let bytes = self.read_bytes(8)?;
2070        Ok(u64::from_be_bytes([
2071            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
2072        ]))
2073    }
2074
2075    pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, ClassReadError> {
2076        if self.pos + len > self.data.len() {
2077            return Err(ClassReadError::UnexpectedEof);
2078        }
2079        let bytes = self.data[self.pos..self.pos + len].to_vec();
2080        self.pos += len;
2081        Ok(bytes)
2082    }
2083}
2084
2085#[cfg(test)]
2086mod tests {
2087    use crate::constants::*;
2088
2089    use super::*;
2090    use std::cell::RefCell;
2091    use std::rc::Rc;
2092
2093    // A mock visitor to capture parsing results
2094    struct MockClassVisitor {
2095        pub visited_name: Rc<RefCell<Option<String>>>,
2096        pub visited_methods: Rc<RefCell<Vec<String>>>,
2097    }
2098
2099    impl MockClassVisitor {
2100        fn new() -> Self {
2101            Self {
2102                visited_name: Rc::new(RefCell::new(None)),
2103                visited_methods: Rc::new(RefCell::new(Vec::new())),
2104            }
2105        }
2106    }
2107
2108    impl ClassVisitor for MockClassVisitor {
2109        fn visit(
2110            &mut self,
2111            _major: u16,
2112            _minor: u16,
2113            _access_flags: u16,
2114            name: &str,
2115            _super_name: Option<&str>,
2116            _interfaces: &[String],
2117        ) {
2118            *self.visited_name.borrow_mut() = Some(name.to_string());
2119        }
2120
2121        fn visit_method(
2122            &mut self,
2123            _access_flags: u16,
2124            name: &str,
2125            _descriptor: &str,
2126        ) -> Option<Box<dyn MethodVisitor>> {
2127            self.visited_methods.borrow_mut().push(name.to_string());
2128            None
2129        }
2130    }
2131
2132    /// Helper to generate a minimal valid class file byte array (Java 8).
2133    /// Class Name: "TestClass"
2134    fn generate_minimal_class() -> Vec<u8> {
2135        let mut w = Vec::new();
2136        // Magic
2137        w.extend_from_slice(&0xCAFEBABE_u32.to_be_bytes());
2138        // Version (Java 8 = 52.0)
2139        w.extend_from_slice(&0_u16.to_be_bytes()); // minor
2140        w.extend_from_slice(&52_u16.to_be_bytes()); // major
2141
2142        // Constant Pool (Count: 5)
2143        // 1: UTF8 "TestClass"
2144        // 2: Class #1
2145        // 3: UTF8 "java/lang/Object"
2146        // 4: Class #3
2147        w.extend_from_slice(&5_u16.to_be_bytes()); // Count (N+1)
2148
2149        // #1 UTF8
2150        w.push(1);
2151        let name = "TestClass";
2152        w.extend_from_slice(&(name.len() as u16).to_be_bytes());
2153        w.extend_from_slice(name.as_bytes());
2154
2155        // #2 Class
2156        w.push(7);
2157        w.extend_from_slice(&1_u16.to_be_bytes());
2158
2159        // #3 UTF8
2160        w.push(1);
2161        let obj = "java/lang/Object";
2162        w.extend_from_slice(&(obj.len() as u16).to_be_bytes());
2163        w.extend_from_slice(obj.as_bytes());
2164
2165        // #4 Class
2166        w.push(7);
2167        w.extend_from_slice(&3_u16.to_be_bytes());
2168
2169        // Access Flags (PUBLIC)
2170        w.extend_from_slice(&0x0021_u16.to_be_bytes());
2171        // This Class (#2)
2172        w.extend_from_slice(&2_u16.to_be_bytes());
2173        // Super Class (#4)
2174        w.extend_from_slice(&4_u16.to_be_bytes());
2175
2176        // Interfaces Count
2177        w.extend_from_slice(&0_u16.to_be_bytes());
2178        // Fields Count
2179        w.extend_from_slice(&0_u16.to_be_bytes());
2180        // Methods Count
2181        w.extend_from_slice(&0_u16.to_be_bytes());
2182        // Attributes Count
2183        w.extend_from_slice(&0_u16.to_be_bytes());
2184
2185        w
2186    }
2187
2188    #[test]
2189    fn test_class_reader_header() {
2190        let bytes = generate_minimal_class();
2191        let reader = ClassReader::new(&bytes);
2192        let mut visitor = MockClassVisitor::new();
2193
2194        let result = reader.accept(&mut visitor, 0);
2195
2196        assert!(result.is_ok(), "Should parse valid class file");
2197        assert_eq!(
2198            *visitor.visited_name.borrow(),
2199            Some("TestClass".to_string())
2200        );
2201    }
2202
2203    #[test]
2204    fn test_invalid_magic() {
2205        // expected CA FE BA BE
2206        let bytes = vec![0x00, 0x00, 0x00, 0x00];
2207        let reader = ClassReader::new(&bytes);
2208        let mut visitor = MockClassVisitor::new();
2209
2210        let result = reader.accept(&mut visitor, 0);
2211        assert!(matches!(result, Err(ClassReadError::InvalidMagic(_))));
2212    }
2213
2214    #[test]
2215    fn test_code_reader_alignment() {
2216        // Test internal alignment logic for switch instructions
2217        let data = vec![0x00, 0x00, 0x00, 0x00]; // 4 bytes
2218        let mut reader = super::ByteReader::new(&data);
2219
2220        // If we are at pos 1, padding to 4-byte boundary
2221        reader.pos = 1;
2222        // 1 -> align 4 -> skips 3 bytes -> pos 4
2223        assert!(reader.align4(0).is_ok());
2224        assert_eq!(reader.pos(), 4);
2225    }
2226
2227    #[test]
2228    fn test_parse_runtime_visible_type_annotations_supertype() {
2229        // RuntimeVisibleTypeAnnotations:
2230        // u2 num_annotations = 1
2231        // type_annotation:
2232        //   u1 target_type = TA_TARGET_CLASS_EXTENDS
2233        //   u2 supertype_index = 5
2234        //   type_path: u1 path_len=0
2235        //   annotation:
2236        //     u2 type_descriptor_index=10
2237        //     u2 num_pairs=0
2238        let mut info = vec![];
2239        u2(1, &mut info);
2240        u1(TA_TARGET_CLASS_EXTENDS, &mut info);
2241        u2(5, &mut info);
2242        u1(0, &mut info);
2243        u2(10, &mut info);
2244        u2(0, &mut info);
2245
2246        let cp: Vec<CpInfo> = vec![];
2247        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2248
2249        match attr {
2250            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2251                assert_eq!(annotations.len(), 1);
2252                let a = &annotations[0];
2253                assert_eq!(a.target_type, TA_TARGET_CLASS_EXTENDS);
2254                assert!(matches!(
2255                    a.target_info,
2256                    TypeAnnotationTargetInfo::Supertype { supertype_index: 5 }
2257                ));
2258                assert_eq!(a.target_path.path.len(), 0);
2259                assert_eq!(a.annotation.type_descriptor_index, 10);
2260                assert_eq!(a.annotation.element_value_pairs.len(), 0);
2261            }
2262            other => panic!("unexpected attr: {:?}", other),
2263        }
2264    }
2265
2266    #[test]
2267    fn test_parse_runtime_visible_type_annotations_formal_parameter_with_path() {
2268        // target_type = TA_TARGET_METHOD_FORMAL_PARAMETER
2269        // u1 formal_parameter_index = 2
2270        // type_path len=1 entry(kind=TA_TYPE_PATH_ARRAY, arg_index=0)
2271        // annotation: type_index=9, num_pairs=0
2272        let mut info = vec![];
2273        u2(1, &mut info);
2274        u1(TA_TARGET_METHOD_FORMAL_PARAMETER, &mut info);
2275        u1(2, &mut info);
2276
2277        u1(1, &mut info); // path_length
2278        u1(TA_TYPE_PATH_ARRAY, &mut info);
2279        u1(0, &mut info);
2280
2281        u2(9, &mut info);
2282        u2(0, &mut info);
2283
2284        let cp: Vec<CpInfo> = vec![];
2285        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2286
2287        match attr {
2288            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2289                let a = &annotations[0];
2290                assert_eq!(a.target_type, TA_TARGET_METHOD_FORMAL_PARAMETER);
2291                assert!(matches!(
2292                    a.target_info,
2293                    TypeAnnotationTargetInfo::FormalParameter {
2294                        formal_parameter_index: 2
2295                    }
2296                ));
2297                assert_eq!(a.target_path.path.len(), 1);
2298                assert_eq!(a.target_path.path[0].type_path_kind, TA_TYPE_PATH_ARRAY);
2299                assert_eq!(a.target_path.path[0].type_argument_index, 0);
2300            }
2301            other => panic!("unexpected attr: {:?}", other),
2302        }
2303    }
2304
2305    #[test]
2306    fn test_parse_runtime_visible_type_annotations_localvar_table() {
2307        // target_type = TA_TARGET_LOCAL_VARIABLE
2308        // u2 table_length = 1
2309        // entry: start_pc=1 length=2 index=3
2310        // type_path len=0
2311        // annotation: type_index=8, num_pairs=0
2312        let mut info = vec![];
2313        u2(1, &mut info);
2314        u1(TA_TARGET_LOCAL_VARIABLE, &mut info);
2315
2316        u2(1, &mut info); // table_length
2317        u2(1, &mut info);
2318        u2(2, &mut info);
2319        u2(3, &mut info);
2320
2321        u1(0, &mut info); // path_length
2322        u2(8, &mut info);
2323        u2(0, &mut info);
2324
2325        let cp: Vec<CpInfo> = vec![];
2326        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2327
2328        match attr {
2329            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2330                let a = &annotations[0];
2331                assert_eq!(a.target_type, TA_TARGET_LOCAL_VARIABLE);
2332                match &a.target_info {
2333                    TypeAnnotationTargetInfo::LocalVar { table } => {
2334                        assert_eq!(table.len(), 1);
2335                        assert_eq!(table[0].start_pc, 1);
2336                        assert_eq!(table[0].length, 2);
2337                        assert_eq!(table[0].index, 3);
2338                    }
2339                    other => panic!("unexpected target_info: {:?}", other),
2340                }
2341            }
2342            other => panic!("unexpected attr: {:?}", other),
2343        }
2344    }
2345
2346    fn u1(v: u8, out: &mut Vec<u8>) {
2347        out.push(v);
2348    }
2349    fn u2(v: u16, out: &mut Vec<u8>) {
2350        out.extend_from_slice(&v.to_be_bytes());
2351    }
2352
2353    #[test]
2354    fn test_parse_runtime_visible_annotations_one_empty() {
2355        // u2 num_annotations=1
2356        // annotation: type=10, pairs=0
2357        let mut info = vec![];
2358        u2(1, &mut info);
2359        u2(10, &mut info);
2360        u2(0, &mut info);
2361
2362        let cp: Vec<CpInfo> = vec![];
2363        let attr = parse_attribute("RuntimeVisibleAnnotations", info, &cp).unwrap();
2364        match attr {
2365            AttributeInfo::RuntimeVisibleAnnotations { annotations } => {
2366                assert_eq!(annotations.len(), 1);
2367                assert_eq!(annotations[0].type_descriptor_index, 10);
2368                assert_eq!(annotations[0].element_value_pairs.len(), 0);
2369            }
2370            other => panic!("unexpected attr: {:?}", other),
2371        }
2372    }
2373
2374    #[test]
2375    fn test_parse_runtime_visible_parameter_annotations_two_params() {
2376        // u1 num_params=2
2377        // p0: u2 num_ann=1, annotation(type=10,pairs=0)
2378        // p1: u2 num_ann=0
2379        let mut info = vec![];
2380        u1(2, &mut info);
2381        u2(1, &mut info);
2382        u2(10, &mut info);
2383        u2(0, &mut info);
2384        u2(0, &mut info);
2385
2386        let cp: Vec<CpInfo> = vec![];
2387        let attr = parse_attribute("RuntimeVisibleParameterAnnotations", info, &cp).unwrap();
2388        match attr {
2389            AttributeInfo::RuntimeVisibleParameterAnnotations { parameters } => {
2390                assert_eq!(parameters.parameters.len(), 2);
2391                assert_eq!(parameters.parameters[0].len(), 1);
2392                assert_eq!(parameters.parameters[1].len(), 0);
2393            }
2394            other => panic!("unexpected attr: {:?}", other),
2395        }
2396    }
2397}