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    LineNumberInsnNode, LookupSwitchInsnNode, MemberRef, MethodInsnNode, MultiANewArrayInsnNode,
7    TableSwitchInsnNode, 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 JPMS module descriptor.
112pub trait ModuleVisitor {
113    fn visit_main_class(&mut self, _main_class: &str) {}
114    fn visit_package(&mut self, _package: &str) {}
115    fn visit_require(&mut self, _module: &str, _access_flags: u16, _version: Option<&str>) {}
116    fn visit_export(&mut self, _package: &str, _access_flags: u16, _modules: &[String]) {}
117    fn visit_open(&mut self, _package: &str, _access_flags: u16, _modules: &[String]) {}
118    fn visit_use(&mut self, _service: &str) {}
119    fn visit_provide(&mut self, _service: &str, _providers: &[String]) {}
120    fn visit_end(&mut self) {}
121}
122
123/// A visitor to visit a Java class.
124///
125/// The methods of this trait must be called in the following order:
126/// `visit` -> `visit_source` -> `visit_module` -> (`visit_field` | `visit_method`)* -> `visit_end`.
127pub trait ClassVisitor {
128    /// Visits the header of the class.
129    ///
130    /// # Arguments
131    /// * `major` - The major version number of the class file.
132    /// * `minor` - The minor version number of the class file.
133    /// * `access_flags` - The class's access flags (see `Opcodes`).
134    /// * `name` - The internal name of the class.
135    /// * `super_name` - The internal name of the super class (e.g., `java/lang/String`, `a/b/c`).
136    ///   Use `None` for `Object`.
137    /// * `interfaces` - The internal names of the class's interfaces.
138    fn visit(
139        &mut self,
140        _major: u16,
141        _minor: u16,
142        _access_flags: u16,
143        _name: &str,
144        _super_name: Option<&str>,
145        _interfaces: &[String],
146    ) {
147    }
148
149    /// Visits the source file name of the class.
150    fn visit_source(&mut self, _source: &str) {}
151
152    /// Visits the JPMS module descriptor of this class, if this is a `module-info.class`.
153    fn visit_module(
154        &mut self,
155        _name: &str,
156        _access_flags: u16,
157        _version: Option<&str>,
158    ) -> Option<Box<dyn ModuleVisitor>> {
159        None
160    }
161
162    /// Visits a field of the class.
163    ///
164    /// Returns an optional `FieldVisitor` to visit the field's content.
165    fn visit_field(
166        &mut self,
167        _access_flags: u16,
168        _name: &str,
169        _descriptor: &str,
170    ) -> Option<Box<dyn FieldVisitor>> {
171        None
172    }
173
174    /// Visits a method of the class.
175    ///
176    /// Returns an optional `MethodVisitor` to visit the method's code.
177    fn visit_method(
178        &mut self,
179        _access_flags: u16,
180        _name: &str,
181        _descriptor: &str,
182    ) -> Option<Box<dyn MethodVisitor>> {
183        None
184    }
185
186    /// Visits the end of the class.
187    fn visit_end(&mut self) {}
188}
189
190/// A parser to make a [`ClassVisitor`] visit a `ClassFile` structure.
191///
192/// This class parses a byte array conforming to the Java class file format and
193/// calls the appropriate methods of a given class visitor for each field, method,
194/// and bytecode instruction encountered.
195pub struct ClassReader {
196    bytes: Vec<u8>,
197}
198
199impl ClassReader {
200    /// Constructs a new `ClassReader` with the given class file bytes.
201    ///
202    /// # Arguments
203    ///
204    /// * `bytes` - A byte slice containing the JVM class file data.
205    pub fn new(bytes: &[u8]) -> Self {
206        Self {
207            bytes: bytes.to_vec(),
208        }
209    }
210
211    /// Makes the given visitor visit the Java class of this `ClassReader`.
212    ///
213    /// This method parses the class file data and drives the visitor events.
214    ///
215    /// # Arguments
216    ///
217    /// * `visitor` - The visitor that must visit this class.
218    /// * `_options` - Option flags (currently unused, reserve for future parsing options like skipping debug info).
219    ///
220    /// # Errors
221    ///
222    /// Returns a [`ClassReadError`] if the class file is malformed or contains unsupported versions.
223    pub fn accept(
224        &self,
225        visitor: &mut dyn ClassVisitor,
226        _options: u32,
227    ) -> Result<(), ClassReadError> {
228        let class_file = read_class_file(&self.bytes)?;
229        let name = class_file.class_name(class_file.this_class)?.to_string();
230        let super_name = if class_file.super_class == 0 {
231            None
232        } else {
233            Some(class_file.class_name(class_file.super_class)?.to_string())
234        };
235        let mut interfaces = Vec::with_capacity(class_file.interfaces.len());
236        for index in &class_file.interfaces {
237            interfaces.push(class_file.class_name(*index)?.to_string());
238        }
239
240        visitor.visit(
241            class_file.major_version,
242            class_file.minor_version,
243            class_file.access_flags,
244            &name,
245            super_name.as_deref(),
246            &interfaces,
247        );
248
249        for attr in &class_file.attributes {
250            if let AttributeInfo::SourceFile { sourcefile_index } = attr {
251                let source = class_file.cp_utf8(*sourcefile_index)?;
252                visitor.visit_source(source);
253            }
254        }
255
256        if let Some(module_attr) = class_file.attributes.iter().find_map(|attr| match attr {
257            AttributeInfo::Module(module) => Some(module),
258            _ => None,
259        }) {
260            let version = if module_attr.module_version_index == 0 {
261                None
262            } else {
263                Some(class_file.cp_utf8(module_attr.module_version_index)?)
264            };
265            if let Some(mut mv) = visitor.visit_module(
266                class_file.module_name(module_attr.module_name_index)?,
267                module_attr.module_flags,
268                version,
269            ) {
270                if let Some(main_class_index) =
271                    class_file.attributes.iter().find_map(|attr| match attr {
272                        AttributeInfo::ModuleMainClass { main_class_index } => {
273                            Some(*main_class_index)
274                        }
275                        _ => None,
276                    })
277                {
278                    mv.visit_main_class(class_file.class_name(main_class_index)?);
279                }
280                if let Some(package_index_table) =
281                    class_file.attributes.iter().find_map(|attr| match attr {
282                        AttributeInfo::ModulePackages {
283                            package_index_table,
284                        } => Some(package_index_table.as_slice()),
285                        _ => None,
286                    })
287                {
288                    for package_index in package_index_table {
289                        mv.visit_package(class_file.package_name(*package_index)?);
290                    }
291                }
292                for require in &module_attr.requires {
293                    let version = if require.requires_version_index == 0 {
294                        None
295                    } else {
296                        Some(class_file.cp_utf8(require.requires_version_index)?)
297                    };
298                    mv.visit_require(
299                        class_file.module_name(require.requires_index)?,
300                        require.requires_flags,
301                        version,
302                    );
303                }
304                for export in &module_attr.exports {
305                    let modules = export
306                        .exports_to_index
307                        .iter()
308                        .map(|index| class_file.module_name(*index).map(str::to_string))
309                        .collect::<Result<Vec<_>, _>>()?;
310                    mv.visit_export(
311                        class_file.package_name(export.exports_index)?,
312                        export.exports_flags,
313                        &modules,
314                    );
315                }
316                for open in &module_attr.opens {
317                    let modules = open
318                        .opens_to_index
319                        .iter()
320                        .map(|index| class_file.module_name(*index).map(str::to_string))
321                        .collect::<Result<Vec<_>, _>>()?;
322                    mv.visit_open(
323                        class_file.package_name(open.opens_index)?,
324                        open.opens_flags,
325                        &modules,
326                    );
327                }
328                for uses_index in &module_attr.uses_index {
329                    mv.visit_use(class_file.class_name(*uses_index)?);
330                }
331                for provide in &module_attr.provides {
332                    let providers = provide
333                        .provides_with_index
334                        .iter()
335                        .map(|index| class_file.class_name(*index).map(str::to_string))
336                        .collect::<Result<Vec<_>, _>>()?;
337                    mv.visit_provide(class_file.class_name(provide.provides_index)?, &providers);
338                }
339                mv.visit_end();
340            }
341        }
342
343        for field in &class_file.fields {
344            let field_name = class_file.cp_utf8(field.name_index)?;
345            let field_desc = class_file.cp_utf8(field.descriptor_index)?;
346            if let Some(mut fv) = visitor.visit_field(field.access_flags, field_name, field_desc) {
347                fv.visit_end();
348            }
349        }
350
351        for method in &class_file.methods {
352            let method_name = class_file.cp_utf8(method.name_index)?;
353            let method_desc = class_file.cp_utf8(method.descriptor_index)?;
354            if let Some(mut mv) =
355                visitor.visit_method(method.access_flags, method_name, method_desc)
356            {
357                let code = method.attributes.iter().find_map(|attr| match attr {
358                    AttributeInfo::Code(code) => Some(code),
359                    _ => None,
360                });
361                if let Some(code) = code {
362                    mv.visit_code();
363                    let instructions = parse_code_instructions_with_offsets(&code.code)?;
364                    for instruction in instructions {
365                        visit_instruction(
366                            &class_file.constant_pool,
367                            instruction.offset as i32,
368                            instruction.insn,
369                            &mut *mv,
370                        )?;
371                    }
372                    mv.visit_maxs(code.max_stack, code.max_locals);
373                }
374                mv.visit_end();
375            }
376        }
377
378        visitor.visit_end();
379        Ok(())
380    }
381
382    /// Converts the read class data directly into a `ClassNode`.
383    ///
384    /// This is a convenience method that parses the bytes and builds a
385    /// complete object model of the class.
386    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
387        let class_file = read_class_file(&self.bytes)?;
388        class_file.to_class_node()
389    }
390}
391
392#[derive(Debug, Clone)]
393pub struct ClassFile {
394    pub minor_version: u16,
395    pub major_version: u16,
396    pub constant_pool: Vec<CpInfo>,
397    pub access_flags: u16,
398    pub this_class: u16,
399    pub super_class: u16,
400    pub interfaces: Vec<u16>,
401    pub fields: Vec<FieldInfo>,
402    pub methods: Vec<MethodInfo>,
403    pub attributes: Vec<AttributeInfo>,
404}
405
406impl ClassFile {
407    pub fn cp_utf8(&self, index: u16) -> Result<&str, ClassReadError> {
408        match self
409            .constant_pool
410            .get(index as usize)
411            .ok_or(ClassReadError::InvalidIndex(index))?
412        {
413            CpInfo::Utf8(value) => Ok(value.as_str()),
414            _ => Err(ClassReadError::InvalidIndex(index)),
415        }
416    }
417
418    pub fn class_name(&self, index: u16) -> Result<&str, ClassReadError> {
419        match self
420            .constant_pool
421            .get(index as usize)
422            .ok_or(ClassReadError::InvalidIndex(index))?
423        {
424            CpInfo::Class { name_index } => self.cp_utf8(*name_index),
425            _ => Err(ClassReadError::InvalidIndex(index)),
426        }
427    }
428
429    pub fn module_name(&self, index: u16) -> Result<&str, ClassReadError> {
430        match self
431            .constant_pool
432            .get(index as usize)
433            .ok_or(ClassReadError::InvalidIndex(index))?
434        {
435            CpInfo::Module { name_index } => self.cp_utf8(*name_index),
436            _ => Err(ClassReadError::InvalidIndex(index)),
437        }
438    }
439
440    pub fn package_name(&self, index: u16) -> Result<&str, ClassReadError> {
441        match self
442            .constant_pool
443            .get(index as usize)
444            .ok_or(ClassReadError::InvalidIndex(index))?
445        {
446            CpInfo::Package { name_index } => self.cp_utf8(*name_index),
447            _ => Err(ClassReadError::InvalidIndex(index)),
448        }
449    }
450
451    pub fn to_class_node(&self) -> Result<crate::nodes::ClassNode, ClassReadError> {
452        let name = self.class_name(self.this_class)?.to_string();
453        let super_name = if self.super_class == 0 {
454            None
455        } else {
456            Some(self.class_name(self.super_class)?.to_string())
457        };
458        let source_file = self.attributes.iter().find_map(|attr| match attr {
459            AttributeInfo::SourceFile { sourcefile_index } => self
460                .cp_utf8(*sourcefile_index)
461                .ok()
462                .map(|value| value.to_string()),
463            _ => None,
464        });
465        let mut interfaces = Vec::with_capacity(self.interfaces.len());
466        for index in &self.interfaces {
467            interfaces.push(self.class_name(*index)?.to_string());
468        }
469
470        let mut fields = Vec::with_capacity(self.fields.len());
471        for field in &self.fields {
472            let name = self.cp_utf8(field.name_index)?.to_string();
473            let descriptor = self.cp_utf8(field.descriptor_index)?.to_string();
474            fields.push(crate::nodes::FieldNode {
475                access_flags: field.access_flags,
476                name,
477                descriptor,
478                attributes: field.attributes.clone(),
479            });
480        }
481
482        let mut methods = Vec::with_capacity(self.methods.len());
483        for method in &self.methods {
484            let name = self.cp_utf8(method.name_index)?.to_string();
485            let descriptor = self.cp_utf8(method.descriptor_index)?.to_string();
486            let mut method_attributes = method.attributes.clone();
487            method_attributes.retain(|attr| !matches!(attr, AttributeInfo::Code(_)));
488            let code = method.attributes.iter().find_map(|attr| match attr {
489                AttributeInfo::Code(code) => Some(code),
490                _ => None,
491            });
492
493            let (
494                has_code,
495                max_stack,
496                max_locals,
497                instructions,
498                instruction_offsets,
499                insn_nodes,
500                exception_table,
501                try_catch_blocks,
502                line_numbers,
503                local_variables,
504                code_attributes,
505            ) = if let Some(code) = code {
506                let mut list = InsnList::new();
507                let mut instruction_offsets = Vec::with_capacity(code.instructions.len());
508                for insn in &code.instructions {
509                    list.add(insn.clone());
510                }
511                for node in parse_code_instructions_with_offsets(&code.code)? {
512                    instruction_offsets.push(node.offset);
513                }
514                let line_numbers = code
515                    .attributes
516                    .iter()
517                    .find_map(|attr| match attr {
518                        AttributeInfo::LineNumberTable { entries } => Some(entries.clone()),
519                        _ => None,
520                    })
521                    .unwrap_or_default();
522                let local_variables = code
523                    .attributes
524                    .iter()
525                    .find_map(|attr| match attr {
526                        AttributeInfo::LocalVariableTable { entries } => Some(entries.clone()),
527                        _ => None,
528                    })
529                    .unwrap_or_default();
530                (
531                    true,
532                    code.max_stack,
533                    code.max_locals,
534                    list,
535                    instruction_offsets,
536                    code.insn_nodes.clone(),
537                    code.exception_table.clone(),
538                    code.try_catch_blocks.clone(),
539                    line_numbers,
540                    local_variables,
541                    code.attributes.clone(),
542                )
543            } else {
544                (
545                    false,
546                    0,
547                    0,
548                    InsnList::new(),
549                    Vec::new(),
550                    Vec::new(),
551                    Vec::new(),
552                    Vec::new(),
553                    Vec::new(),
554                    Vec::new(),
555                    Vec::new(),
556                )
557            };
558            let method_parameters = method
559                .attributes
560                .iter()
561                .find_map(|attr| match attr {
562                    AttributeInfo::MethodParameters { parameters } => Some(parameters.clone()),
563                    _ => None,
564                })
565                .unwrap_or_default();
566            let exceptions = method
567                .attributes
568                .iter()
569                .find_map(|attr| match attr {
570                    AttributeInfo::Exceptions {
571                        exception_index_table,
572                    } => Some(exception_index_table),
573                    _ => None,
574                })
575                .map(|entries| -> Result<Vec<String>, ClassReadError> {
576                    let mut values = Vec::with_capacity(entries.len());
577                    for index in entries {
578                        values.push(self.class_name(*index)?.to_string());
579                    }
580                    Ok(values)
581                })
582                .transpose()?
583                .unwrap_or_default();
584            let signature = method.attributes.iter().find_map(|attr| match attr {
585                AttributeInfo::Signature { signature_index } => self
586                    .cp_utf8(*signature_index)
587                    .ok()
588                    .map(|value| value.to_string()),
589                _ => None,
590            });
591
592            methods.push(crate::nodes::MethodNode {
593                access_flags: method.access_flags,
594                name,
595                descriptor,
596                has_code,
597                max_stack,
598                max_locals,
599                instructions,
600                instruction_offsets,
601                insn_nodes,
602                exception_table,
603                try_catch_blocks,
604                line_numbers,
605                local_variables,
606                method_parameters,
607                exceptions,
608                signature,
609                code_attributes,
610                attributes: method_attributes,
611            });
612        }
613
614        let mut inner_classes = Vec::new();
615        for attr in &self.attributes {
616            if let AttributeInfo::InnerClasses { classes } = attr {
617                for entry in classes {
618                    let name = self.class_name(entry.inner_class_info_index)?.to_string();
619                    let outer_name = if entry.outer_class_info_index == 0 {
620                        None
621                    } else {
622                        Some(self.class_name(entry.outer_class_info_index)?.to_string())
623                    };
624                    let inner_name = if entry.inner_name_index == 0 {
625                        None
626                    } else {
627                        Some(self.cp_utf8(entry.inner_name_index)?.to_string())
628                    };
629                    inner_classes.push(crate::nodes::InnerClassNode {
630                        name,
631                        outer_name,
632                        inner_name,
633                        access_flags: entry.inner_class_access_flags,
634                    });
635                }
636            }
637        }
638
639        let mut outer_class = String::new();
640        if let Some(class_index) = self.attributes.iter().find_map(|attr| match attr {
641            AttributeInfo::EnclosingMethod { class_index, .. } => Some(*class_index),
642            _ => None,
643        }) {
644            outer_class = self.class_name(class_index)?.to_string();
645        }
646        if outer_class.is_empty() {
647            for attr in &self.attributes {
648                if let AttributeInfo::InnerClasses { classes } = attr
649                    && let Some(entry) = classes.iter().find(|entry| {
650                        entry.inner_class_info_index == self.this_class
651                            && entry.outer_class_info_index != 0
652                    })
653                {
654                    outer_class = self.class_name(entry.outer_class_info_index)?.to_string();
655                    break;
656                }
657            }
658        }
659
660        let module = self
661            .attributes
662            .iter()
663            .find_map(|attr| match attr {
664                AttributeInfo::Module(module) => Some(module),
665                _ => None,
666            })
667            .map(|module| {
668                let requires = module
669                    .requires
670                    .iter()
671                    .map(|require| {
672                        Ok(crate::nodes::ModuleRequireNode {
673                            module: self.module_name(require.requires_index)?.to_string(),
674                            access_flags: require.requires_flags,
675                            version: if require.requires_version_index == 0 {
676                                None
677                            } else {
678                                Some(self.cp_utf8(require.requires_version_index)?.to_string())
679                            },
680                        })
681                    })
682                    .collect::<Result<Vec<_>, ClassReadError>>()?;
683                let exports = module
684                    .exports
685                    .iter()
686                    .map(|export| {
687                        Ok(crate::nodes::ModuleExportNode {
688                            package: self.package_name(export.exports_index)?.to_string(),
689                            access_flags: export.exports_flags,
690                            modules: export
691                                .exports_to_index
692                                .iter()
693                                .map(|index| self.module_name(*index).map(str::to_string))
694                                .collect::<Result<Vec<_>, ClassReadError>>()?,
695                        })
696                    })
697                    .collect::<Result<Vec<_>, ClassReadError>>()?;
698                let opens = module
699                    .opens
700                    .iter()
701                    .map(|open| {
702                        Ok(crate::nodes::ModuleOpenNode {
703                            package: self.package_name(open.opens_index)?.to_string(),
704                            access_flags: open.opens_flags,
705                            modules: open
706                                .opens_to_index
707                                .iter()
708                                .map(|index| self.module_name(*index).map(str::to_string))
709                                .collect::<Result<Vec<_>, ClassReadError>>()?,
710                        })
711                    })
712                    .collect::<Result<Vec<_>, ClassReadError>>()?;
713                let provides = module
714                    .provides
715                    .iter()
716                    .map(|provide| {
717                        Ok(crate::nodes::ModuleProvideNode {
718                            service: self.class_name(provide.provides_index)?.to_string(),
719                            providers: provide
720                                .provides_with_index
721                                .iter()
722                                .map(|index| self.class_name(*index).map(str::to_string))
723                                .collect::<Result<Vec<_>, ClassReadError>>()?,
724                        })
725                    })
726                    .collect::<Result<Vec<_>, ClassReadError>>()?;
727                let packages = self
728                    .attributes
729                    .iter()
730                    .find_map(|attr| match attr {
731                        AttributeInfo::ModulePackages {
732                            package_index_table,
733                        } => Some(package_index_table),
734                        _ => None,
735                    })
736                    .map(|package_index_table| {
737                        package_index_table
738                            .iter()
739                            .map(|index| self.package_name(*index).map(str::to_string))
740                            .collect::<Result<Vec<_>, ClassReadError>>()
741                    })
742                    .transpose()?
743                    .unwrap_or_default();
744                let main_class = self
745                    .attributes
746                    .iter()
747                    .find_map(|attr| match attr {
748                        AttributeInfo::ModuleMainClass { main_class_index } => {
749                            Some(*main_class_index)
750                        }
751                        _ => None,
752                    })
753                    .map(|index| self.class_name(index).map(str::to_string))
754                    .transpose()?;
755
756                Ok(crate::nodes::ModuleNode {
757                    name: self.module_name(module.module_name_index)?.to_string(),
758                    access_flags: module.module_flags,
759                    version: if module.module_version_index == 0 {
760                        None
761                    } else {
762                        Some(self.cp_utf8(module.module_version_index)?.to_string())
763                    },
764                    requires,
765                    exports,
766                    opens,
767                    uses: module
768                        .uses_index
769                        .iter()
770                        .map(|index| self.class_name(*index).map(str::to_string))
771                        .collect::<Result<Vec<_>, ClassReadError>>()?,
772                    provides,
773                    packages,
774                    main_class,
775                })
776            })
777            .transpose()?;
778
779        Ok(crate::nodes::ClassNode {
780            minor_version: self.minor_version,
781            major_version: self.major_version,
782            access_flags: self.access_flags,
783            constant_pool: self.constant_pool.clone(),
784            this_class: self.this_class,
785            name,
786            super_name,
787            source_file,
788            interfaces,
789            interface_indices: self.interfaces.clone(),
790            fields,
791            methods,
792            attributes: self.attributes.clone(),
793            inner_classes,
794            outer_class,
795            module,
796        })
797    }
798}
799
800#[derive(Debug, Clone)]
801pub struct FieldInfo {
802    pub access_flags: u16,
803    pub name_index: u16,
804    pub descriptor_index: u16,
805    pub attributes: Vec<AttributeInfo>,
806}
807
808#[derive(Debug, Clone)]
809pub struct MethodInfo {
810    pub access_flags: u16,
811    pub name_index: u16,
812    pub descriptor_index: u16,
813    pub attributes: Vec<AttributeInfo>,
814}
815
816#[derive(Debug, Clone)]
817pub enum AttributeInfo {
818    Code(CodeAttribute),
819    ConstantValue { constantvalue_index: u16 },
820    Exceptions { exception_index_table: Vec<u16> },
821    SourceFile { sourcefile_index: u16 },
822    LineNumberTable { entries: Vec<LineNumber> },
823    LocalVariableTable { entries: Vec<LocalVariable> },
824    Signature { signature_index: u16 },
825    StackMapTable { entries: Vec<StackMapFrame> },
826    Deprecated,
827    Synthetic,
828    InnerClasses { classes: Vec<InnerClass> },
829    EnclosingMethod { class_index: u16, method_index: u16 },
830    Module(ModuleAttribute),
831    ModulePackages { package_index_table: Vec<u16> },
832    ModuleMainClass { main_class_index: u16 },
833    BootstrapMethods { methods: Vec<BootstrapMethod> },
834    MethodParameters { parameters: Vec<MethodParameter> },
835    RuntimeVisibleAnnotations { annotations: Vec<Annotation> },
836    RuntimeInvisibleAnnotations { annotations: Vec<Annotation> },
837    RuntimeVisibleParameterAnnotations { parameters: ParameterAnnotations },
838    RuntimeInvisibleParameterAnnotations { parameters: ParameterAnnotations },
839    RuntimeVisibleTypeAnnotations { annotations: Vec<TypeAnnotation> },
840    RuntimeInvisibleTypeAnnotations { annotations: Vec<TypeAnnotation> },
841    Unknown { name: String, info: Vec<u8> },
842}
843
844#[derive(Debug, Clone, PartialEq, Eq)]
845pub struct ModuleAttribute {
846    pub module_name_index: u16,
847    pub module_flags: u16,
848    pub module_version_index: u16,
849    pub requires: Vec<ModuleRequire>,
850    pub exports: Vec<ModuleExport>,
851    pub opens: Vec<ModuleOpen>,
852    pub uses_index: Vec<u16>,
853    pub provides: Vec<ModuleProvide>,
854}
855
856#[derive(Debug, Clone, PartialEq, Eq)]
857pub struct ModuleRequire {
858    pub requires_index: u16,
859    pub requires_flags: u16,
860    pub requires_version_index: u16,
861}
862
863#[derive(Debug, Clone, PartialEq, Eq)]
864pub struct ModuleExport {
865    pub exports_index: u16,
866    pub exports_flags: u16,
867    pub exports_to_index: Vec<u16>,
868}
869
870#[derive(Debug, Clone, PartialEq, Eq)]
871pub struct ModuleOpen {
872    pub opens_index: u16,
873    pub opens_flags: u16,
874    pub opens_to_index: Vec<u16>,
875}
876
877#[derive(Debug, Clone, PartialEq, Eq)]
878pub struct ModuleProvide {
879    pub provides_index: u16,
880    pub provides_with_index: Vec<u16>,
881}
882
883#[derive(Debug, Clone, PartialEq)]
884pub struct Annotation {
885    pub type_descriptor_index: u16,
886    pub element_value_pairs: Vec<ElementValuePair>,
887}
888
889#[derive(Debug, Clone, PartialEq)]
890pub struct ElementValuePair {
891    pub element_name_index: u16,
892    pub value: ElementValue,
893}
894
895#[derive(Debug, Clone, PartialEq)]
896pub enum ElementValue {
897    ConstValueIndex {
898        tag: u8,
899        const_value_index: u16,
900    },
901    EnumConstValue {
902        type_name_index: u16,
903        const_name_index: u16,
904    },
905    ClassInfoIndex {
906        class_info_index: u16,
907    },
908    AnnotationValue(Box<Annotation>),
909    ArrayValue(Vec<ElementValue>),
910}
911
912#[derive(Debug, Clone, PartialEq)]
913pub struct ParameterAnnotations {
914    pub parameters: Vec<Vec<Annotation>>,
915}
916
917#[derive(Debug, Clone, PartialEq)]
918pub struct TypeAnnotation {
919    pub target_type: u8,
920    pub target_info: TypeAnnotationTargetInfo,
921    pub target_path: TypePath,
922    pub annotation: Annotation,
923}
924
925#[derive(Debug, Clone, PartialEq)]
926pub struct TypePath {
927    pub path: Vec<TypePathEntry>,
928}
929
930#[derive(Debug, Clone, PartialEq)]
931pub struct TypePathEntry {
932    pub type_path_kind: u8,
933    pub type_argument_index: u8,
934}
935
936#[derive(Debug, Clone, PartialEq)]
937pub enum TypeAnnotationTargetInfo {
938    TypeParameter {
939        type_parameter_index: u8,
940    },
941    Supertype {
942        supertype_index: u16,
943    },
944    TypeParameterBound {
945        type_parameter_index: u8,
946        bound_index: u8,
947    },
948    Empty,
949    FormalParameter {
950        formal_parameter_index: u8,
951    },
952    Throws {
953        throws_type_index: u16,
954    },
955    LocalVar {
956        table: Vec<LocalVarTargetTableEntry>,
957    },
958    Catch {
959        exception_table_index: u16,
960    },
961    Offset {
962        offset: u16,
963    },
964    TypeArgument {
965        offset: u16,
966        type_argument_index: u8,
967    },
968}
969
970#[derive(Debug, Clone, PartialEq)]
971pub struct LocalVarTargetTableEntry {
972    pub start_pc: u16,
973    pub length: u16,
974    pub index: u16,
975}
976
977#[derive(Debug, Clone)]
978pub struct CodeAttribute {
979    pub max_stack: u16,
980    pub max_locals: u16,
981    pub code: Vec<u8>,
982    pub instructions: Vec<Insn>,
983    pub insn_nodes: Vec<AbstractInsnNode>,
984    pub exception_table: Vec<ExceptionTableEntry>,
985    pub try_catch_blocks: Vec<TryCatchBlockNode>,
986    pub attributes: Vec<AttributeInfo>,
987}
988
989#[derive(Debug, Clone)]
990pub struct ExceptionTableEntry {
991    pub start_pc: u16,
992    pub end_pc: u16,
993    pub handler_pc: u16,
994    pub catch_type: u16,
995}
996
997#[derive(Debug, Clone)]
998pub struct LineNumber {
999    pub start_pc: u16,
1000    pub line_number: u16,
1001}
1002
1003#[derive(Debug, Clone)]
1004pub struct LocalVariable {
1005    pub start_pc: u16,
1006    pub length: u16,
1007    pub name_index: u16,
1008    pub descriptor_index: u16,
1009    pub index: u16,
1010}
1011
1012#[derive(Debug, Clone)]
1013pub struct InnerClass {
1014    pub inner_class_info_index: u16,
1015    pub outer_class_info_index: u16,
1016    pub inner_name_index: u16,
1017    pub inner_class_access_flags: u16,
1018}
1019
1020#[derive(Debug, Clone)]
1021pub struct BootstrapMethod {
1022    pub bootstrap_method_ref: u16,
1023    pub bootstrap_arguments: Vec<u16>,
1024}
1025
1026#[derive(Debug, Clone)]
1027pub struct MethodParameter {
1028    pub name_index: u16,
1029    pub access_flags: u16,
1030}
1031
1032#[derive(Debug, Clone, PartialEq, Eq)]
1033pub enum VerificationTypeInfo {
1034    Top,
1035    Integer,
1036    Float,
1037    Long,
1038    Double,
1039    Null,
1040    UninitializedThis,
1041    Object { cpool_index: u16 },
1042    Uninitialized { offset: u16 },
1043}
1044
1045#[derive(Debug, Clone)]
1046pub enum StackMapFrame {
1047    SameFrame {
1048        offset_delta: u16,
1049    },
1050    SameLocals1StackItemFrame {
1051        offset_delta: u16,
1052        stack: VerificationTypeInfo,
1053    },
1054    SameLocals1StackItemFrameExtended {
1055        offset_delta: u16,
1056        stack: VerificationTypeInfo,
1057    },
1058    ChopFrame {
1059        offset_delta: u16,
1060        k: u8,
1061    },
1062    SameFrameExtended {
1063        offset_delta: u16,
1064    },
1065    AppendFrame {
1066        offset_delta: u16,
1067        locals: Vec<VerificationTypeInfo>,
1068    },
1069    FullFrame {
1070        offset_delta: u16,
1071        locals: Vec<VerificationTypeInfo>,
1072        stack: Vec<VerificationTypeInfo>,
1073    },
1074}
1075
1076pub fn read_class_file(bytes: &[u8]) -> Result<ClassFile, ClassReadError> {
1077    let mut reader = ByteReader::new(bytes);
1078    let magic = reader.read_u4()?;
1079    if magic != 0xCAFEBABE {
1080        return Err(ClassReadError::InvalidMagic(magic));
1081    }
1082    let minor_version = reader.read_u2()?;
1083    let major_version = reader.read_u2()?;
1084    if major_version > constants::V25 {
1085        return Err(ClassReadError::InvalidClassVersion(major_version));
1086    }
1087    let constant_pool = read_constant_pool(&mut reader)?;
1088    let access_flags = reader.read_u2()?;
1089    let this_class = reader.read_u2()?;
1090    let super_class = reader.read_u2()?;
1091    let interfaces = read_u2_table(&mut reader)?;
1092    let fields = read_fields(&mut reader, &constant_pool)?;
1093    let methods = read_methods(&mut reader, &constant_pool)?;
1094    let attributes = read_attributes(&mut reader, &constant_pool)?;
1095
1096    Ok(ClassFile {
1097        minor_version,
1098        major_version,
1099        constant_pool,
1100        access_flags,
1101        this_class,
1102        super_class,
1103        interfaces,
1104        fields,
1105        methods,
1106        attributes,
1107    })
1108}
1109
1110fn read_constant_pool(reader: &mut ByteReader<'_>) -> Result<Vec<CpInfo>, ClassReadError> {
1111    let count = reader.read_u2()? as usize;
1112    let mut pool = Vec::with_capacity(count);
1113    pool.push(CpInfo::Unusable);
1114
1115    let mut index = 1;
1116    while index < count {
1117        let tag = reader.read_u1()?;
1118        let entry = match tag {
1119            1 => {
1120                let len = reader.read_u2()? as usize;
1121                let bytes = reader.read_bytes(len)?;
1122                let value = decode_modified_utf8(&bytes)?;
1123                CpInfo::Utf8(value)
1124            }
1125            3 => {
1126                let value = reader.read_u4()? as i32;
1127                CpInfo::Integer(value)
1128            }
1129            4 => {
1130                let value = f32::from_bits(reader.read_u4()?);
1131                CpInfo::Float(value)
1132            }
1133            5 => {
1134                let value = reader.read_u8()? as i64;
1135                CpInfo::Long(value)
1136            }
1137            6 => {
1138                let value = f64::from_bits(reader.read_u8()?);
1139                CpInfo::Double(value)
1140            }
1141            7 => CpInfo::Class {
1142                name_index: reader.read_u2()?,
1143            },
1144            8 => CpInfo::String {
1145                string_index: reader.read_u2()?,
1146            },
1147            9 => CpInfo::Fieldref {
1148                class_index: reader.read_u2()?,
1149                name_and_type_index: reader.read_u2()?,
1150            },
1151            10 => CpInfo::Methodref {
1152                class_index: reader.read_u2()?,
1153                name_and_type_index: reader.read_u2()?,
1154            },
1155            11 => CpInfo::InterfaceMethodref {
1156                class_index: reader.read_u2()?,
1157                name_and_type_index: reader.read_u2()?,
1158            },
1159            12 => CpInfo::NameAndType {
1160                name_index: reader.read_u2()?,
1161                descriptor_index: reader.read_u2()?,
1162            },
1163            15 => CpInfo::MethodHandle {
1164                reference_kind: reader.read_u1()?,
1165                reference_index: reader.read_u2()?,
1166            },
1167            16 => CpInfo::MethodType {
1168                descriptor_index: reader.read_u2()?,
1169            },
1170            17 => CpInfo::Dynamic {
1171                bootstrap_method_attr_index: reader.read_u2()?,
1172                name_and_type_index: reader.read_u2()?,
1173            },
1174            18 => CpInfo::InvokeDynamic {
1175                bootstrap_method_attr_index: reader.read_u2()?,
1176                name_and_type_index: reader.read_u2()?,
1177            },
1178            19 => CpInfo::Module {
1179                name_index: reader.read_u2()?,
1180            },
1181            20 => CpInfo::Package {
1182                name_index: reader.read_u2()?,
1183            },
1184            _ => return Err(ClassReadError::InvalidConstantPoolTag(tag)),
1185        };
1186
1187        pool.push(entry);
1188
1189        if tag == 5 || tag == 6 {
1190            pool.push(CpInfo::Unusable);
1191            index += 2;
1192        } else {
1193            index += 1;
1194        }
1195    }
1196
1197    Ok(pool)
1198}
1199
1200fn read_u2_table(reader: &mut ByteReader<'_>) -> Result<Vec<u16>, ClassReadError> {
1201    let count = reader.read_u2()? as usize;
1202    let mut values = Vec::with_capacity(count);
1203    for _ in 0..count {
1204        values.push(reader.read_u2()?);
1205    }
1206    Ok(values)
1207}
1208
1209fn read_fields(
1210    reader: &mut ByteReader<'_>,
1211    cp: &[CpInfo],
1212) -> Result<Vec<FieldInfo>, ClassReadError> {
1213    let count = reader.read_u2()? as usize;
1214    let mut fields = Vec::with_capacity(count);
1215    for _ in 0..count {
1216        let access_flags = reader.read_u2()?;
1217        let name_index = reader.read_u2()?;
1218        let descriptor_index = reader.read_u2()?;
1219        let attributes = read_attributes(reader, cp)?;
1220        fields.push(FieldInfo {
1221            access_flags,
1222            name_index,
1223            descriptor_index,
1224            attributes,
1225        });
1226    }
1227    Ok(fields)
1228}
1229
1230fn read_methods(
1231    reader: &mut ByteReader<'_>,
1232    cp: &[CpInfo],
1233) -> Result<Vec<MethodInfo>, ClassReadError> {
1234    let count = reader.read_u2()? as usize;
1235    let mut methods = Vec::with_capacity(count);
1236    for _ in 0..count {
1237        let access_flags = reader.read_u2()?;
1238        let name_index = reader.read_u2()?;
1239        let descriptor_index = reader.read_u2()?;
1240        let attributes = read_attributes(reader, cp)?;
1241        methods.push(MethodInfo {
1242            access_flags,
1243            name_index,
1244            descriptor_index,
1245            attributes,
1246        });
1247    }
1248    Ok(methods)
1249}
1250
1251fn read_attributes(
1252    reader: &mut ByteReader<'_>,
1253    cp: &[CpInfo],
1254) -> Result<Vec<AttributeInfo>, ClassReadError> {
1255    let count = reader.read_u2()? as usize;
1256    let mut attributes = Vec::with_capacity(count);
1257    for _ in 0..count {
1258        let name_index = reader.read_u2()?;
1259        let length = reader.read_u4()? as usize;
1260        let name = cp_utf8(cp, name_index)?;
1261        let info = reader.read_bytes(length)?;
1262        let attribute = parse_attribute(name, info, cp)?;
1263        attributes.push(attribute);
1264    }
1265    Ok(attributes)
1266}
1267
1268fn parse_attribute(
1269    name: &str,
1270    info: Vec<u8>,
1271    cp: &[CpInfo],
1272) -> Result<AttributeInfo, ClassReadError> {
1273    let mut reader = ByteReader::new(&info);
1274    let attribute = match name {
1275        "Code" => {
1276            let max_stack = reader.read_u2()?;
1277            let max_locals = reader.read_u2()?;
1278            let code_length = reader.read_u4()? as usize;
1279            let code = reader.read_bytes(code_length)?;
1280            let instructions = parse_code_instructions(&code)?;
1281            let exception_table_length = reader.read_u2()? as usize;
1282            let mut exception_table = Vec::with_capacity(exception_table_length);
1283            for _ in 0..exception_table_length {
1284                exception_table.push(ExceptionTableEntry {
1285                    start_pc: reader.read_u2()?,
1286                    end_pc: reader.read_u2()?,
1287                    handler_pc: reader.read_u2()?,
1288                    catch_type: reader.read_u2()?,
1289                });
1290            }
1291            let attributes = read_attributes(&mut reader, cp)?;
1292            let (mut insn_nodes, try_catch_blocks, label_by_offset) =
1293                build_insn_nodes(&code, &exception_table, cp)?;
1294            let line_numbers = attributes.iter().find_map(|attr| match attr {
1295                AttributeInfo::LineNumberTable { entries } => Some(entries.as_slice()),
1296                _ => None,
1297            });
1298            if let Some(entries) = line_numbers {
1299                insn_nodes = attach_line_numbers(insn_nodes, entries, &label_by_offset);
1300            }
1301            AttributeInfo::Code(CodeAttribute {
1302                max_stack,
1303                max_locals,
1304                code,
1305                instructions,
1306                insn_nodes,
1307                exception_table,
1308                try_catch_blocks,
1309                attributes,
1310            })
1311        }
1312        "ConstantValue" => AttributeInfo::ConstantValue {
1313            constantvalue_index: reader.read_u2()?,
1314        },
1315        "Exceptions" => {
1316            let count = reader.read_u2()? as usize;
1317            let mut exception_index_table = Vec::with_capacity(count);
1318            for _ in 0..count {
1319                exception_index_table.push(reader.read_u2()?);
1320            }
1321            AttributeInfo::Exceptions {
1322                exception_index_table,
1323            }
1324        }
1325        "SourceFile" => AttributeInfo::SourceFile {
1326            sourcefile_index: reader.read_u2()?,
1327        },
1328        "LineNumberTable" => {
1329            let count = reader.read_u2()? as usize;
1330            let mut entries = Vec::with_capacity(count);
1331            for _ in 0..count {
1332                entries.push(LineNumber {
1333                    start_pc: reader.read_u2()?,
1334                    line_number: reader.read_u2()?,
1335                });
1336            }
1337            AttributeInfo::LineNumberTable { entries }
1338        }
1339        "LocalVariableTable" => {
1340            let count = reader.read_u2()? as usize;
1341            let mut entries = Vec::with_capacity(count);
1342            for _ in 0..count {
1343                entries.push(LocalVariable {
1344                    start_pc: reader.read_u2()?,
1345                    length: reader.read_u2()?,
1346                    name_index: reader.read_u2()?,
1347                    descriptor_index: reader.read_u2()?,
1348                    index: reader.read_u2()?,
1349                });
1350            }
1351            AttributeInfo::LocalVariableTable { entries }
1352        }
1353        "Signature" => AttributeInfo::Signature {
1354            signature_index: reader.read_u2()?,
1355        },
1356        "StackMapTable" => {
1357            let count = reader.read_u2()? as usize;
1358            let mut entries = Vec::with_capacity(count);
1359            for _ in 0..count {
1360                let frame_type = reader.read_u1()?;
1361                let frame = match frame_type {
1362                    0..=63 => StackMapFrame::SameFrame {
1363                        offset_delta: frame_type as u16,
1364                    },
1365                    64..=127 => StackMapFrame::SameLocals1StackItemFrame {
1366                        offset_delta: (frame_type - 64) as u16,
1367                        stack: parse_verification_type(&mut reader)?,
1368                    },
1369                    247 => StackMapFrame::SameLocals1StackItemFrameExtended {
1370                        offset_delta: reader.read_u2()?,
1371                        stack: parse_verification_type(&mut reader)?,
1372                    },
1373                    248..=250 => StackMapFrame::ChopFrame {
1374                        offset_delta: reader.read_u2()?,
1375                        k: 251 - frame_type,
1376                    },
1377                    251 => StackMapFrame::SameFrameExtended {
1378                        offset_delta: reader.read_u2()?,
1379                    },
1380                    252..=254 => {
1381                        let offset_delta = reader.read_u2()?;
1382                        let locals_count = (frame_type - 251) as usize;
1383                        let mut locals = Vec::with_capacity(locals_count);
1384                        for _ in 0..locals_count {
1385                            locals.push(parse_verification_type(&mut reader)?);
1386                        }
1387                        StackMapFrame::AppendFrame {
1388                            offset_delta,
1389                            locals,
1390                        }
1391                    }
1392                    255 => {
1393                        let offset_delta = reader.read_u2()?;
1394                        let locals_count = reader.read_u2()? as usize;
1395                        let mut locals = Vec::with_capacity(locals_count);
1396                        for _ in 0..locals_count {
1397                            locals.push(parse_verification_type(&mut reader)?);
1398                        }
1399                        let stack_count = reader.read_u2()? as usize;
1400                        let mut stack = Vec::with_capacity(stack_count);
1401                        for _ in 0..stack_count {
1402                            stack.push(parse_verification_type(&mut reader)?);
1403                        }
1404                        StackMapFrame::FullFrame {
1405                            offset_delta,
1406                            locals,
1407                            stack,
1408                        }
1409                    }
1410                    _ => {
1411                        return Err(ClassReadError::InvalidAttribute(
1412                            "StackMapTable".to_string(),
1413                        ));
1414                    }
1415                };
1416                entries.push(frame);
1417            }
1418            AttributeInfo::StackMapTable { entries }
1419        }
1420        "Deprecated" => AttributeInfo::Deprecated,
1421        "Synthetic" => AttributeInfo::Synthetic,
1422        "InnerClasses" => {
1423            let count = reader.read_u2()? as usize;
1424            let mut classes = Vec::with_capacity(count);
1425            for _ in 0..count {
1426                classes.push(InnerClass {
1427                    inner_class_info_index: reader.read_u2()?,
1428                    outer_class_info_index: reader.read_u2()?,
1429                    inner_name_index: reader.read_u2()?,
1430                    inner_class_access_flags: reader.read_u2()?,
1431                });
1432            }
1433            AttributeInfo::InnerClasses { classes }
1434        }
1435        "EnclosingMethod" => AttributeInfo::EnclosingMethod {
1436            class_index: reader.read_u2()?,
1437            method_index: reader.read_u2()?,
1438        },
1439        "Module" => AttributeInfo::Module(parse_module_attribute(&mut reader)?),
1440        "ModulePackages" => {
1441            let count = reader.read_u2()? as usize;
1442            let mut package_index_table = Vec::with_capacity(count);
1443            for _ in 0..count {
1444                package_index_table.push(reader.read_u2()?);
1445            }
1446            AttributeInfo::ModulePackages {
1447                package_index_table,
1448            }
1449        }
1450        "ModuleMainClass" => AttributeInfo::ModuleMainClass {
1451            main_class_index: reader.read_u2()?,
1452        },
1453        "BootstrapMethods" => {
1454            let count = reader.read_u2()? as usize;
1455            let mut methods = Vec::with_capacity(count);
1456            for _ in 0..count {
1457                let bootstrap_method_ref = reader.read_u2()?;
1458                let arg_count = reader.read_u2()? as usize;
1459                let mut bootstrap_arguments = Vec::with_capacity(arg_count);
1460                for _ in 0..arg_count {
1461                    bootstrap_arguments.push(reader.read_u2()?);
1462                }
1463                methods.push(BootstrapMethod {
1464                    bootstrap_method_ref,
1465                    bootstrap_arguments,
1466                });
1467            }
1468            AttributeInfo::BootstrapMethods { methods }
1469        }
1470        "MethodParameters" => {
1471            let count = reader.read_u1()? as usize;
1472            let mut parameters = Vec::with_capacity(count);
1473            for _ in 0..count {
1474                parameters.push(MethodParameter {
1475                    name_index: reader.read_u2()?,
1476                    access_flags: reader.read_u2()?,
1477                });
1478            }
1479            AttributeInfo::MethodParameters { parameters }
1480        }
1481        "RuntimeVisibleAnnotations" => {
1482            let annotations = parse_annotations(&mut reader)?;
1483            AttributeInfo::RuntimeVisibleAnnotations { annotations }
1484        }
1485        "RuntimeInvisibleAnnotations" => {
1486            let annotations = parse_annotations(&mut reader)?;
1487            AttributeInfo::RuntimeInvisibleAnnotations { annotations }
1488        }
1489        "RuntimeVisibleParameterAnnotations" => {
1490            let parameters = parse_parameter_annotations(&mut reader)?;
1491            AttributeInfo::RuntimeVisibleParameterAnnotations { parameters }
1492        }
1493        "RuntimeInvisibleParameterAnnotations" => {
1494            let parameters = parse_parameter_annotations(&mut reader)?;
1495            AttributeInfo::RuntimeInvisibleParameterAnnotations { parameters }
1496        }
1497        "RuntimeVisibleTypeAnnotations" => {
1498            let annotations = parse_type_annotations(&mut reader)?;
1499            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations }
1500        }
1501        "RuntimeInvisibleTypeAnnotations" => {
1502            let annotations = parse_type_annotations(&mut reader)?;
1503            AttributeInfo::RuntimeInvisibleTypeAnnotations { annotations }
1504        }
1505        _ => {
1506            return Ok(AttributeInfo::Unknown {
1507                name: name.to_string(),
1508                info,
1509            });
1510        }
1511    };
1512
1513    if reader.remaining() != 0 {
1514        return Err(ClassReadError::InvalidAttribute(name.to_string()));
1515    }
1516
1517    Ok(attribute)
1518}
1519
1520fn parse_module_attribute(reader: &mut ByteReader<'_>) -> Result<ModuleAttribute, ClassReadError> {
1521    let module_name_index = reader.read_u2()?;
1522    let module_flags = reader.read_u2()?;
1523    let module_version_index = reader.read_u2()?;
1524
1525    let requires_count = reader.read_u2()? as usize;
1526    let mut requires = Vec::with_capacity(requires_count);
1527    for _ in 0..requires_count {
1528        requires.push(ModuleRequire {
1529            requires_index: reader.read_u2()?,
1530            requires_flags: reader.read_u2()?,
1531            requires_version_index: reader.read_u2()?,
1532        });
1533    }
1534
1535    let exports_count = reader.read_u2()? as usize;
1536    let mut exports = Vec::with_capacity(exports_count);
1537    for _ in 0..exports_count {
1538        let exports_index = reader.read_u2()?;
1539        let exports_flags = reader.read_u2()?;
1540        let exports_to_count = reader.read_u2()? as usize;
1541        let mut exports_to_index = Vec::with_capacity(exports_to_count);
1542        for _ in 0..exports_to_count {
1543            exports_to_index.push(reader.read_u2()?);
1544        }
1545        exports.push(ModuleExport {
1546            exports_index,
1547            exports_flags,
1548            exports_to_index,
1549        });
1550    }
1551
1552    let opens_count = reader.read_u2()? as usize;
1553    let mut opens = Vec::with_capacity(opens_count);
1554    for _ in 0..opens_count {
1555        let opens_index = reader.read_u2()?;
1556        let opens_flags = reader.read_u2()?;
1557        let opens_to_count = reader.read_u2()? as usize;
1558        let mut opens_to_index = Vec::with_capacity(opens_to_count);
1559        for _ in 0..opens_to_count {
1560            opens_to_index.push(reader.read_u2()?);
1561        }
1562        opens.push(ModuleOpen {
1563            opens_index,
1564            opens_flags,
1565            opens_to_index,
1566        });
1567    }
1568
1569    let uses_count = reader.read_u2()? as usize;
1570    let mut uses_index = Vec::with_capacity(uses_count);
1571    for _ in 0..uses_count {
1572        uses_index.push(reader.read_u2()?);
1573    }
1574
1575    let provides_count = reader.read_u2()? as usize;
1576    let mut provides = Vec::with_capacity(provides_count);
1577    for _ in 0..provides_count {
1578        let provides_index = reader.read_u2()?;
1579        let provides_with_count = reader.read_u2()? as usize;
1580        let mut provides_with_index = Vec::with_capacity(provides_with_count);
1581        for _ in 0..provides_with_count {
1582            provides_with_index.push(reader.read_u2()?);
1583        }
1584        provides.push(ModuleProvide {
1585            provides_index,
1586            provides_with_index,
1587        });
1588    }
1589
1590    Ok(ModuleAttribute {
1591        module_name_index,
1592        module_flags,
1593        module_version_index,
1594        requires,
1595        exports,
1596        opens,
1597        uses_index,
1598        provides,
1599    })
1600}
1601
1602fn parse_annotations(reader: &mut ByteReader) -> Result<Vec<Annotation>, ClassReadError> {
1603    let num = reader.read_u2()? as usize;
1604    let mut out = Vec::with_capacity(num);
1605    for _ in 0..num {
1606        out.push(parse_annotation(reader)?);
1607    }
1608    Ok(out)
1609}
1610
1611fn parse_annotation(reader: &mut ByteReader) -> Result<Annotation, ClassReadError> {
1612    let type_descriptor_index = reader.read_u2()?;
1613    let num_pairs = reader.read_u2()? as usize;
1614    let mut element_value_pairs = Vec::with_capacity(num_pairs);
1615    for _ in 0..num_pairs {
1616        let element_name_index = reader.read_u2()?;
1617        let value = parse_element_value(reader)?;
1618        element_value_pairs.push(ElementValuePair {
1619            element_name_index,
1620            value,
1621        });
1622    }
1623    Ok(Annotation {
1624        type_descriptor_index,
1625        element_value_pairs,
1626    })
1627}
1628
1629fn parse_parameter_annotations(
1630    reader: &mut ByteReader,
1631) -> Result<ParameterAnnotations, ClassReadError> {
1632    let num_params = reader.read_u1()? as usize;
1633    let mut parameters = Vec::with_capacity(num_params);
1634    for _ in 0..num_params {
1635        let num_ann = reader.read_u2()? as usize;
1636        let mut anns = Vec::with_capacity(num_ann);
1637        for _ in 0..num_ann {
1638            anns.push(parse_annotation(reader)?);
1639        }
1640        parameters.push(anns);
1641    }
1642    Ok(ParameterAnnotations { parameters })
1643}
1644
1645fn parse_type_annotations(reader: &mut ByteReader) -> Result<Vec<TypeAnnotation>, ClassReadError> {
1646    let num = reader.read_u2()? as usize;
1647    let mut out = Vec::with_capacity(num);
1648    for _ in 0..num {
1649        out.push(parse_type_annotation(reader)?);
1650    }
1651    Ok(out)
1652}
1653
1654fn parse_type_annotation(reader: &mut ByteReader) -> Result<TypeAnnotation, ClassReadError> {
1655    let target_type = reader.read_u1()?;
1656    let target_info = parse_type_annotation_target_info(reader, target_type)?;
1657    let target_path = parse_type_path(reader)?;
1658    let annotation = parse_annotation(reader)?;
1659    Ok(TypeAnnotation {
1660        target_type,
1661        target_info,
1662        target_path,
1663        annotation,
1664    })
1665}
1666
1667fn parse_type_path(reader: &mut ByteReader) -> Result<TypePath, ClassReadError> {
1668    let path_length = reader.read_u1()? as usize;
1669    let mut path = Vec::with_capacity(path_length);
1670    for _ in 0..path_length {
1671        path.push(TypePathEntry {
1672            type_path_kind: reader.read_u1()?,
1673            type_argument_index: reader.read_u1()?,
1674        });
1675    }
1676    Ok(TypePath { path })
1677}
1678
1679fn parse_type_annotation_target_info(
1680    reader: &mut ByteReader,
1681    target_type: u8,
1682) -> Result<TypeAnnotationTargetInfo, ClassReadError> {
1683    use crate::constants::*;
1684
1685    let ti = match target_type {
1686        TA_TARGET_CLASS_TYPE_PARAMETER | TA_TARGET_METHOD_TYPE_PARAMETER => {
1687            TypeAnnotationTargetInfo::TypeParameter {
1688                type_parameter_index: reader.read_u1()?,
1689            }
1690        }
1691
1692        TA_TARGET_CLASS_EXTENDS => TypeAnnotationTargetInfo::Supertype {
1693            supertype_index: reader.read_u2()?,
1694        },
1695
1696        TA_TARGET_CLASS_TYPE_PARAMETER_BOUND | TA_TARGET_METHOD_TYPE_PARAMETER_BOUND => {
1697            TypeAnnotationTargetInfo::TypeParameterBound {
1698                type_parameter_index: reader.read_u1()?,
1699                bound_index: reader.read_u1()?,
1700            }
1701        }
1702
1703        TA_TARGET_FIELD | TA_TARGET_METHOD_RETURN | TA_TARGET_METHOD_RECEIVER => {
1704            TypeAnnotationTargetInfo::Empty
1705        }
1706
1707        TA_TARGET_METHOD_FORMAL_PARAMETER => TypeAnnotationTargetInfo::FormalParameter {
1708            formal_parameter_index: reader.read_u1()?,
1709        },
1710
1711        TA_TARGET_THROWS => TypeAnnotationTargetInfo::Throws {
1712            throws_type_index: reader.read_u2()?,
1713        },
1714
1715        TA_TARGET_LOCAL_VARIABLE | TA_TARGET_RESOURCE_VARIABLE => {
1716            let table_length = reader.read_u2()? as usize;
1717            let mut table = Vec::with_capacity(table_length);
1718            for _ in 0..table_length {
1719                table.push(LocalVarTargetTableEntry {
1720                    start_pc: reader.read_u2()?,
1721                    length: reader.read_u2()?,
1722                    index: reader.read_u2()?,
1723                });
1724            }
1725            TypeAnnotationTargetInfo::LocalVar { table }
1726        }
1727
1728        TA_TARGET_EXCEPTION_PARAMETER => TypeAnnotationTargetInfo::Catch {
1729            exception_table_index: reader.read_u2()?,
1730        },
1731
1732        TA_TARGET_INSTANCEOF
1733        | TA_TARGET_NEW
1734        | TA_TARGET_CONSTRUCTOR_REFERENCE_RECEIVER
1735        | TA_TARGET_METHOD_REFERENCE_RECEIVER => TypeAnnotationTargetInfo::Offset {
1736            offset: reader.read_u2()?,
1737        },
1738
1739        TA_TARGET_CAST
1740        | TA_TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT
1741        | TA_TARGET_METHOD_INVOCATION_TYPE_ARGUMENT
1742        | TA_TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT
1743        | TA_TARGET_METHOD_REFERENCE_TYPE_ARGUMENT => TypeAnnotationTargetInfo::TypeArgument {
1744            offset: reader.read_u2()?,
1745            type_argument_index: reader.read_u1()?,
1746        },
1747
1748        _ => {
1749            return Err(ClassReadError::InvalidAttribute(format!(
1750                "TypeAnnotationTargetInfo(target_type=0x{:02X})",
1751                target_type
1752            )));
1753        }
1754    };
1755
1756    Ok(ti)
1757}
1758
1759fn parse_element_value(reader: &mut ByteReader) -> Result<ElementValue, ClassReadError> {
1760    let tag = reader.read_u1()?;
1761    let v = match tag {
1762        b'B' | b'C' | b'D' | b'F' | b'I' | b'J' | b'S' | b'Z' | b's' => {
1763            ElementValue::ConstValueIndex {
1764                tag,
1765                const_value_index: reader.read_u2()?,
1766            }
1767        }
1768        b'e' => ElementValue::EnumConstValue {
1769            type_name_index: reader.read_u2()?,
1770            const_name_index: reader.read_u2()?,
1771        },
1772        b'c' => ElementValue::ClassInfoIndex {
1773            class_info_index: reader.read_u2()?,
1774        },
1775        b'@' => ElementValue::AnnotationValue(Box::new(parse_annotation(reader)?)),
1776        b'[' => {
1777            let n = reader.read_u2()? as usize;
1778            let mut items = Vec::with_capacity(n);
1779            for _ in 0..n {
1780                items.push(parse_element_value(reader)?);
1781            }
1782            ElementValue::ArrayValue(items)
1783        }
1784        _ => {
1785            return Err(ClassReadError::InvalidAttribute(
1786                "AnnotationElementValue".to_string(),
1787            ));
1788        }
1789    };
1790    Ok(v)
1791}
1792
1793fn parse_verification_type(
1794    reader: &mut ByteReader<'_>,
1795) -> Result<VerificationTypeInfo, ClassReadError> {
1796    let tag = reader.read_u1()?;
1797    let kind = match tag {
1798        0 => VerificationTypeInfo::Top,
1799        1 => VerificationTypeInfo::Integer,
1800        2 => VerificationTypeInfo::Float,
1801        3 => VerificationTypeInfo::Double,
1802        4 => VerificationTypeInfo::Long,
1803        5 => VerificationTypeInfo::Null,
1804        6 => VerificationTypeInfo::UninitializedThis,
1805        7 => VerificationTypeInfo::Object {
1806            cpool_index: reader.read_u2()?,
1807        },
1808        8 => VerificationTypeInfo::Uninitialized {
1809            offset: reader.read_u2()?,
1810        },
1811        _ => {
1812            return Err(ClassReadError::InvalidAttribute(
1813                "StackMapTable".to_string(),
1814            ));
1815        }
1816    };
1817    Ok(kind)
1818}
1819
1820fn cp_utf8(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
1821    match cp.get(index as usize) {
1822        Some(CpInfo::Utf8(value)) => Ok(value.as_str()),
1823        _ => Err(ClassReadError::InvalidIndex(index)),
1824    }
1825}
1826
1827fn cp_class_name(cp: &[CpInfo], index: u16) -> Result<&str, ClassReadError> {
1828    match cp.get(index as usize) {
1829        Some(CpInfo::Class { name_index }) => cp_utf8(cp, *name_index),
1830        _ => Err(ClassReadError::InvalidIndex(index)),
1831    }
1832}
1833
1834fn cp_name_and_type(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
1835    match cp.get(index as usize) {
1836        Some(CpInfo::NameAndType {
1837            name_index,
1838            descriptor_index,
1839        }) => Ok((cp_utf8(cp, *name_index)?, cp_utf8(cp, *descriptor_index)?)),
1840        _ => Err(ClassReadError::InvalidIndex(index)),
1841    }
1842}
1843
1844fn cp_field_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str), ClassReadError> {
1845    match cp.get(index as usize) {
1846        Some(CpInfo::Fieldref {
1847            class_index,
1848            name_and_type_index,
1849        }) => {
1850            let owner = cp_class_name(cp, *class_index)?;
1851            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1852            Ok((owner, name, desc))
1853        }
1854        _ => Err(ClassReadError::InvalidIndex(index)),
1855    }
1856}
1857
1858fn cp_method_ref(cp: &[CpInfo], index: u16) -> Result<(&str, &str, &str, bool), ClassReadError> {
1859    match cp.get(index as usize) {
1860        Some(CpInfo::Methodref {
1861            class_index,
1862            name_and_type_index,
1863        }) => {
1864            let owner = cp_class_name(cp, *class_index)?;
1865            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1866            Ok((owner, name, desc, false))
1867        }
1868        Some(CpInfo::InterfaceMethodref {
1869            class_index,
1870            name_and_type_index,
1871        }) => {
1872            let owner = cp_class_name(cp, *class_index)?;
1873            let (name, desc) = cp_name_and_type(cp, *name_and_type_index)?;
1874            Ok((owner, name, desc, true))
1875        }
1876        _ => Err(ClassReadError::InvalidIndex(index)),
1877    }
1878}
1879
1880fn cp_invoke_dynamic(cp: &[CpInfo], index: u16) -> Result<(&str, &str), ClassReadError> {
1881    match cp.get(index as usize) {
1882        Some(CpInfo::InvokeDynamic {
1883            name_and_type_index,
1884            ..
1885        }) => cp_name_and_type(cp, *name_and_type_index),
1886        _ => Err(ClassReadError::InvalidIndex(index)),
1887    }
1888}
1889
1890fn cp_ldc_constant(cp: &[CpInfo], index: u16) -> Result<LdcConstant, ClassReadError> {
1891    match cp.get(index as usize) {
1892        Some(CpInfo::Integer(value)) => Ok(LdcConstant::Integer(*value)),
1893        Some(CpInfo::Float(value)) => Ok(LdcConstant::Float(*value)),
1894        Some(CpInfo::Long(value)) => Ok(LdcConstant::Long(*value)),
1895        Some(CpInfo::Double(value)) => Ok(LdcConstant::Double(*value)),
1896        Some(CpInfo::String { string_index }) => {
1897            Ok(LdcConstant::String(cp_utf8(cp, *string_index)?.to_string()))
1898        }
1899        Some(CpInfo::Class { name_index }) => {
1900            Ok(LdcConstant::Class(cp_utf8(cp, *name_index)?.to_string()))
1901        }
1902        Some(CpInfo::MethodType { descriptor_index }) => Ok(LdcConstant::MethodType(
1903            cp_utf8(cp, *descriptor_index)?.to_string(),
1904        )),
1905        Some(CpInfo::MethodHandle {
1906            reference_kind,
1907            reference_index,
1908        }) => Ok(LdcConstant::MethodHandle {
1909            reference_kind: *reference_kind,
1910            reference_index: *reference_index,
1911        }),
1912        Some(CpInfo::Dynamic { .. }) => Ok(LdcConstant::Dynamic),
1913        _ => Err(ClassReadError::InvalidIndex(index)),
1914    }
1915}
1916
1917fn decode_modified_utf8(bytes: &[u8]) -> Result<String, ClassReadError> {
1918    let mut code_units = Vec::with_capacity(bytes.len());
1919    let mut i = 0;
1920    while i < bytes.len() {
1921        let byte = bytes[i];
1922        if byte & 0x80 == 0 {
1923            code_units.push(byte as u16);
1924            i += 1;
1925        } else if byte & 0xE0 == 0xC0 {
1926            if i + 1 >= bytes.len() {
1927                return Err(ClassReadError::Utf8Error("truncated 2-byte".to_string()));
1928            }
1929            let byte2 = bytes[i + 1];
1930            if byte2 & 0xC0 != 0x80 {
1931                return Err(ClassReadError::Utf8Error("invalid 2-byte".to_string()));
1932            }
1933            let value = (((byte & 0x1F) as u16) << 6) | ((byte2 & 0x3F) as u16);
1934            code_units.push(value);
1935            i += 2;
1936        } else if byte & 0xF0 == 0xE0 {
1937            if i + 2 >= bytes.len() {
1938                return Err(ClassReadError::Utf8Error("truncated 3-byte".to_string()));
1939            }
1940            let byte2 = bytes[i + 1];
1941            let byte3 = bytes[i + 2];
1942            if byte2 & 0xC0 != 0x80 || byte3 & 0xC0 != 0x80 {
1943                return Err(ClassReadError::Utf8Error("invalid 3-byte".to_string()));
1944            }
1945            let value = (((byte & 0x0F) as u16) << 12)
1946                | (((byte2 & 0x3F) as u16) << 6)
1947                | ((byte3 & 0x3F) as u16);
1948            code_units.push(value);
1949            i += 3;
1950        } else {
1951            return Err(ClassReadError::Utf8Error(
1952                "invalid leading byte".to_string(),
1953            ));
1954        }
1955    }
1956
1957    String::from_utf16(&code_units)
1958        .map_err(|_| ClassReadError::Utf8Error("invalid utf16".to_string()))
1959}
1960
1961fn parse_code_instructions(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
1962    let mut reader = ByteReader::new(code);
1963    let mut insns = Vec::new();
1964
1965    while reader.remaining() > 0 {
1966        let opcode_offset = reader.pos();
1967        let opcode = reader.read_u1()?;
1968        let insn = match opcode {
1969            opcodes::NOP..=opcodes::DCONST_1 => Insn::Simple(opcode.into()),
1970            opcodes::BIPUSH => Insn::Int(IntInsnNode {
1971                insn: opcode.into(),
1972                operand: reader.read_i1()? as i32,
1973            }),
1974            opcodes::SIPUSH => Insn::Int(IntInsnNode {
1975                insn: opcode.into(),
1976                operand: reader.read_i2()? as i32,
1977            }),
1978            opcodes::LDC => Insn::Ldc(LdcInsnNode {
1979                insn: opcode.into(),
1980                value: LdcValue::Index(reader.read_u1()? as u16),
1981            }),
1982            opcodes::LDC_W | opcodes::LDC2_W => Insn::Ldc(LdcInsnNode {
1983                insn: opcode.into(),
1984                value: LdcValue::Index(reader.read_u2()?),
1985            }),
1986            opcodes::ILOAD..=opcodes::ALOAD => Insn::Var(VarInsnNode {
1987                insn: opcode.into(),
1988                var_index: reader.read_u1()? as u16,
1989            }),
1990            opcodes::ILOAD_0..=opcodes::SALOAD => Insn::Simple(opcode.into()),
1991            opcodes::ISTORE..=opcodes::ASTORE => Insn::Var(VarInsnNode {
1992                insn: opcode.into(),
1993                var_index: reader.read_u1()? as u16,
1994            }),
1995            opcodes::ISTORE_0..=opcodes::SASTORE => Insn::Simple(opcode.into()),
1996            opcodes::POP..=opcodes::LXOR => Insn::Simple(opcode.into()),
1997            opcodes::IINC => Insn::Iinc(IincInsnNode {
1998                insn: opcode.into(),
1999                var_index: reader.read_u1()? as u16,
2000                increment: reader.read_i1()? as i16,
2001            }),
2002            opcodes::I2L..=opcodes::DCMPG => Insn::Simple(opcode.into()),
2003            opcodes::IFEQ..=opcodes::JSR => Insn::Jump(JumpInsnNode {
2004                insn: opcode.into(),
2005                offset: reader.read_i2()? as i32,
2006            }),
2007            opcodes::RET => Insn::Var(VarInsnNode {
2008                insn: opcode.into(),
2009                var_index: reader.read_u1()? as u16,
2010            }),
2011            opcodes::TABLESWITCH => read_table_switch(&mut reader, opcode_offset)?,
2012            opcodes::LOOKUPSWITCH => read_lookup_switch(&mut reader, opcode_offset)?,
2013            opcodes::IRETURN..=opcodes::RETURN => Insn::Simple(InsnNode { opcode }),
2014            opcodes::GETSTATIC..=opcodes::PUTFIELD => Insn::Field(FieldInsnNode {
2015                insn: opcode.into(),
2016                field_ref: MemberRef::Index(reader.read_u2()?),
2017            }),
2018            opcodes::INVOKEVIRTUAL..=opcodes::INVOKESTATIC => Insn::Method(MethodInsnNode {
2019                insn: opcode.into(),
2020                method_ref: MemberRef::Index(reader.read_u2()?),
2021            }),
2022            opcodes::INVOKEINTERFACE => {
2023                let method_index = reader.read_u2()?;
2024                let count = reader.read_u1()?;
2025                let _ = reader.read_u1()?;
2026                Insn::InvokeInterface(InvokeInterfaceInsnNode {
2027                    insn: opcode.into(),
2028                    method_index,
2029                    count,
2030                })
2031            }
2032            opcodes::INVOKEDYNAMIC => {
2033                let method_index = reader.read_u2()?;
2034                let _ = reader.read_u2()?;
2035                Insn::InvokeDynamic(InvokeDynamicInsnNode::from_index(method_index))
2036            }
2037            opcodes::NEW => Insn::Type(TypeInsnNode {
2038                insn: opcode.into(),
2039                type_index: reader.read_u2()?,
2040            }),
2041            opcodes::NEWARRAY => Insn::Int(IntInsnNode {
2042                insn: opcode.into(),
2043                operand: reader.read_u1()? as i32,
2044            }),
2045            opcodes::ANEWARRAY => Insn::Type(TypeInsnNode {
2046                insn: opcode.into(),
2047                type_index: reader.read_u2()?,
2048            }),
2049            opcodes::ARRAYLENGTH | opcodes::ATHROW => Insn::Simple(opcode.into()),
2050            opcodes::CHECKCAST | opcodes::INSTANCEOF => Insn::Type(TypeInsnNode {
2051                insn: opcode.into(),
2052                type_index: reader.read_u2()?,
2053            }),
2054            opcodes::MONITORENTER | opcodes::MONITOREXIT => Insn::Simple(opcode.into()),
2055            opcodes::WIDE => read_wide(&mut reader)?,
2056            opcodes::MULTIANEWARRAY => Insn::MultiANewArray(MultiANewArrayInsnNode {
2057                insn: opcode.into(),
2058                type_index: reader.read_u2()?,
2059                dimensions: reader.read_u1()?,
2060            }),
2061            opcodes::IFNULL | opcodes::IFNONNULL => Insn::Jump(JumpInsnNode {
2062                insn: opcode.into(),
2063                offset: reader.read_i2()? as i32,
2064            }),
2065            opcodes::GOTO_W | opcodes::JSR_W => Insn::Jump(JumpInsnNode {
2066                insn: opcode.into(),
2067                offset: reader.read_i4()?,
2068            }),
2069            opcodes::BREAKPOINT => Insn::Simple(opcode.into()),
2070            opcodes::IMPDEP1 | opcodes::IMPDEP2 => Insn::Simple(opcode.into()),
2071            _ => {
2072                return Err(ClassReadError::InvalidOpcode {
2073                    opcode,
2074                    offset: opcode_offset,
2075                });
2076            }
2077        };
2078
2079        insns.push(insn);
2080    }
2081
2082    Ok(insns)
2083}
2084
2085pub(crate) fn parse_code_instructions_public(code: &[u8]) -> Result<Vec<Insn>, ClassReadError> {
2086    parse_code_instructions(code)
2087}
2088
2089#[derive(Debug, Clone)]
2090struct ParsedInstruction {
2091    offset: u16,
2092    insn: Insn,
2093}
2094
2095fn parse_code_instructions_with_offsets(
2096    code: &[u8],
2097) -> Result<Vec<ParsedInstruction>, ClassReadError> {
2098    let mut reader = ByteReader::new(code);
2099    let mut insns = Vec::new();
2100
2101    while reader.remaining() > 0 {
2102        let opcode_offset = reader.pos();
2103        let opcode = reader.read_u1()?;
2104        let insn = match opcode {
2105            opcodes::NOP..=opcodes::DCONST_1 => Insn::Simple(opcode.into()),
2106            opcodes::BIPUSH => Insn::Int(IntInsnNode {
2107                insn: opcode.into(),
2108                operand: reader.read_i1()? as i32,
2109            }),
2110            opcodes::SIPUSH => Insn::Int(IntInsnNode {
2111                insn: opcode.into(),
2112                operand: reader.read_i2()? as i32,
2113            }),
2114            opcodes::LDC => Insn::Ldc(LdcInsnNode {
2115                insn: opcode.into(),
2116                value: LdcValue::Index(reader.read_u1()? as u16),
2117            }),
2118            opcodes::LDC_W | opcodes::LDC2_W => Insn::Ldc(LdcInsnNode {
2119                insn: opcode.into(),
2120                value: LdcValue::Index(reader.read_u2()?),
2121            }),
2122            opcodes::ILOAD..=opcodes::ALOAD => Insn::Var(VarInsnNode {
2123                insn: opcode.into(),
2124                var_index: reader.read_u1()? as u16,
2125            }),
2126            opcodes::ILOAD_0..=opcodes::SALOAD => Insn::Simple(opcode.into()),
2127            opcodes::ISTORE..=opcodes::ASTORE => Insn::Var(VarInsnNode {
2128                insn: opcode.into(),
2129                var_index: reader.read_u1()? as u16,
2130            }),
2131            opcodes::ISTORE_0..=opcodes::SASTORE => Insn::Simple(opcode.into()),
2132            opcodes::POP..=opcodes::LXOR => Insn::Simple(opcode.into()),
2133            opcodes::IINC => Insn::Iinc(IincInsnNode {
2134                insn: opcode.into(),
2135                var_index: reader.read_u1()? as u16,
2136                increment: reader.read_i1()? as i16,
2137            }),
2138            opcodes::I2L..=opcodes::DCMPG => Insn::Simple(opcode.into()),
2139            opcodes::IFEQ..=opcodes::JSR => Insn::Jump(JumpInsnNode {
2140                insn: opcode.into(),
2141                offset: reader.read_i2()? as i32,
2142            }),
2143            opcodes::RET => Insn::Var(VarInsnNode {
2144                insn: opcode.into(),
2145                var_index: reader.read_u1()? as u16,
2146            }),
2147            opcodes::TABLESWITCH => read_table_switch(&mut reader, opcode_offset)?,
2148            opcodes::LOOKUPSWITCH => read_lookup_switch(&mut reader, opcode_offset)?,
2149            opcodes::IRETURN..=opcodes::RETURN => Insn::Simple(opcode.into()),
2150            opcodes::GETSTATIC..=opcodes::PUTFIELD => Insn::Field(FieldInsnNode {
2151                insn: opcode.into(),
2152                field_ref: MemberRef::Index(reader.read_u2()?),
2153            }),
2154            opcodes::INVOKEVIRTUAL..=opcodes::INVOKESTATIC => Insn::Method(MethodInsnNode {
2155                insn: opcode.into(),
2156                method_ref: MemberRef::Index(reader.read_u2()?),
2157            }),
2158            opcodes::INVOKEINTERFACE => {
2159                let method_index = reader.read_u2()?;
2160                let count = reader.read_u1()?;
2161                let _ = reader.read_u1()?;
2162                Insn::InvokeInterface(InvokeInterfaceInsnNode {
2163                    insn: opcode.into(),
2164                    method_index,
2165                    count,
2166                })
2167            }
2168            opcodes::INVOKEDYNAMIC => {
2169                let method_index = reader.read_u2()?;
2170                let _ = reader.read_u2()?;
2171                Insn::InvokeDynamic(InvokeDynamicInsnNode::from_index(method_index))
2172            }
2173            opcodes::NEW => Insn::Type(TypeInsnNode {
2174                insn: opcode.into(),
2175                type_index: reader.read_u2()?,
2176            }),
2177            opcodes::NEWARRAY => Insn::Int(IntInsnNode {
2178                insn: opcode.into(),
2179                operand: reader.read_u1()? as i32,
2180            }),
2181            opcodes::ANEWARRAY => Insn::Type(TypeInsnNode {
2182                insn: opcode.into(),
2183                type_index: reader.read_u2()?,
2184            }),
2185            opcodes::ARRAYLENGTH | opcodes::ATHROW => Insn::Simple(opcode.into()),
2186            opcodes::CHECKCAST | opcodes::INSTANCEOF => Insn::Type(TypeInsnNode {
2187                insn: opcode.into(),
2188                type_index: reader.read_u2()?,
2189            }),
2190            opcodes::MONITORENTER | opcodes::MONITOREXIT => Insn::Simple(opcode.into()),
2191            opcodes::WIDE => read_wide(&mut reader)?,
2192            opcodes::MULTIANEWARRAY => Insn::MultiANewArray(MultiANewArrayInsnNode {
2193                insn: opcode.into(),
2194                type_index: reader.read_u2()?,
2195                dimensions: reader.read_u1()?,
2196            }),
2197            opcodes::IFNULL | opcodes::IFNONNULL => Insn::Jump(JumpInsnNode {
2198                insn: opcode.into(),
2199                offset: reader.read_i2()? as i32,
2200            }),
2201            opcodes::GOTO_W | opcodes::JSR_W => Insn::Jump(JumpInsnNode {
2202                insn: opcode.into(),
2203                offset: reader.read_i4()?,
2204            }),
2205            opcodes::BREAKPOINT => Insn::Simple(opcode.into()),
2206            opcodes::IMPDEP1 | opcodes::IMPDEP2 => Insn::Simple(opcode.into()),
2207            _ => {
2208                return Err(ClassReadError::InvalidOpcode {
2209                    opcode,
2210                    offset: opcode_offset,
2211                });
2212            }
2213        };
2214
2215        insns.push(ParsedInstruction {
2216            offset: opcode_offset as u16,
2217            insn,
2218        });
2219    }
2220
2221    Ok(insns)
2222}
2223
2224fn build_insn_nodes(
2225    code: &[u8],
2226    exception_table: &[ExceptionTableEntry],
2227    cp: &[CpInfo],
2228) -> Result<
2229    (
2230        Vec<AbstractInsnNode>,
2231        Vec<TryCatchBlockNode>,
2232        std::collections::HashMap<u16, LabelNode>,
2233    ),
2234    ClassReadError,
2235> {
2236    let instructions = parse_code_instructions_with_offsets(code)?;
2237    let mut offsets = std::collections::HashSet::new();
2238    for instruction in &instructions {
2239        offsets.insert(instruction.offset);
2240        match &instruction.insn {
2241            Insn::Jump(node) => {
2242                offsets.insert((instruction.offset as i32 + node.offset) as u16);
2243            }
2244            Insn::TableSwitch(node) => {
2245                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
2246                for offset in &node.offsets {
2247                    offsets.insert((instruction.offset as i32 + *offset) as u16);
2248                }
2249            }
2250            Insn::LookupSwitch(node) => {
2251                offsets.insert((instruction.offset as i32 + node.default_offset) as u16);
2252                for (_, offset) in &node.pairs {
2253                    offsets.insert((instruction.offset as i32 + *offset) as u16);
2254                }
2255            }
2256            _ => {}
2257        }
2258    }
2259    for entry in exception_table {
2260        offsets.insert(entry.start_pc);
2261        offsets.insert(entry.end_pc);
2262        offsets.insert(entry.handler_pc);
2263    }
2264    offsets.insert(code.len() as u16);
2265
2266    let mut label_by_offset = std::collections::HashMap::new();
2267    for (next_id, offset) in offsets.into_iter().enumerate() {
2268        label_by_offset.insert(offset, LabelNode { id: next_id });
2269    }
2270
2271    let mut nodes = Vec::new();
2272    for instruction in instructions {
2273        if let Some(label) = label_by_offset.get(&{ instruction.offset }) {
2274            nodes.push(AbstractInsnNode::Label(*label));
2275        }
2276        nodes.push(AbstractInsnNode::Insn(instruction.insn));
2277    }
2278    if let Some(label) = label_by_offset.get(&(code.len() as u16)) {
2279        nodes.push(AbstractInsnNode::Label(*label));
2280    }
2281
2282    let mut try_catch_blocks = Vec::new();
2283    for entry in exception_table {
2284        let start = *label_by_offset
2285            .get(&entry.start_pc)
2286            .ok_or_else(|| ClassReadError::InvalidAttribute("missing start label".to_string()))?;
2287        let end = *label_by_offset
2288            .get(&entry.end_pc)
2289            .ok_or_else(|| ClassReadError::InvalidAttribute("missing end label".to_string()))?;
2290        let handler = *label_by_offset
2291            .get(&entry.handler_pc)
2292            .ok_or_else(|| ClassReadError::InvalidAttribute("missing handler label".to_string()))?;
2293        let catch_type = if entry.catch_type == 0 {
2294            None
2295        } else {
2296            Some(cp_class_name(cp, entry.catch_type)?.to_string())
2297        };
2298        try_catch_blocks.push(TryCatchBlockNode {
2299            start,
2300            end,
2301            handler,
2302            catch_type,
2303        });
2304    }
2305
2306    Ok((nodes, try_catch_blocks, label_by_offset))
2307}
2308
2309pub(crate) fn build_insn_nodes_public(
2310    code: &[u8],
2311    exception_table: &[ExceptionTableEntry],
2312    cp: &[CpInfo],
2313) -> Result<(Vec<AbstractInsnNode>, Vec<TryCatchBlockNode>), ClassReadError> {
2314    let (nodes, try_catch_blocks, _) = build_insn_nodes(code, exception_table, cp)?;
2315    Ok((nodes, try_catch_blocks))
2316}
2317
2318fn attach_line_numbers(
2319    nodes: Vec<AbstractInsnNode>,
2320    entries: &[LineNumber],
2321    label_by_offset: &std::collections::HashMap<u16, LabelNode>,
2322) -> Vec<AbstractInsnNode> {
2323    let mut lines_by_label = std::collections::HashMap::<usize, Vec<LineNumberInsnNode>>::new();
2324    for entry in entries {
2325        if let Some(label) = label_by_offset.get(&entry.start_pc) {
2326            lines_by_label
2327                .entry(label.id)
2328                .or_default()
2329                .push(LineNumberInsnNode {
2330                    line: entry.line_number,
2331                    start: *label,
2332                });
2333        }
2334    }
2335
2336    let mut merged = Vec::with_capacity(nodes.len() + entries.len());
2337    for node in nodes {
2338        let label_id = match &node {
2339            AbstractInsnNode::Label(label) => Some(label.id),
2340            _ => None,
2341        };
2342        merged.push(node);
2343        if let Some(label_id) = label_id
2344            && let Some(lines) = lines_by_label.remove(&label_id)
2345        {
2346            for line in lines {
2347                merged.push(AbstractInsnNode::LineNumber(line));
2348            }
2349        }
2350    }
2351    merged
2352}
2353
2354fn read_table_switch(
2355    reader: &mut ByteReader<'_>,
2356    opcode_offset: usize,
2357) -> Result<Insn, ClassReadError> {
2358    reader.align4(opcode_offset)?;
2359    let default_offset = reader.read_i4()?;
2360    let low = reader.read_i4()?;
2361    let high = reader.read_i4()?;
2362    let count = if high < low {
2363        0
2364    } else {
2365        (high - low + 1) as usize
2366    };
2367    let mut offsets = Vec::with_capacity(count);
2368    for _ in 0..count {
2369        offsets.push(reader.read_i4()?);
2370    }
2371    Ok(Insn::TableSwitch(TableSwitchInsnNode {
2372        insn: opcodes::TABLESWITCH.into(),
2373        default_offset,
2374        low,
2375        high,
2376        offsets,
2377    }))
2378}
2379
2380fn read_lookup_switch(
2381    reader: &mut ByteReader<'_>,
2382    opcode_offset: usize,
2383) -> Result<Insn, ClassReadError> {
2384    reader.align4(opcode_offset)?;
2385    let default_offset = reader.read_i4()?;
2386    let npairs = reader.read_i4()? as usize;
2387    let mut pairs = Vec::with_capacity(npairs);
2388    for _ in 0..npairs {
2389        let key = reader.read_i4()?;
2390        let offset = reader.read_i4()?;
2391        pairs.push((key, offset));
2392    }
2393    Ok(Insn::LookupSwitch(LookupSwitchInsnNode {
2394        insn: opcodes::LOOKUPSWITCH.into(),
2395        default_offset,
2396        pairs,
2397    }))
2398}
2399
2400fn read_wide(reader: &mut ByteReader<'_>) -> Result<Insn, ClassReadError> {
2401    let opcode = reader.read_u1()?;
2402    match opcode {
2403        opcodes::ILOAD..=opcodes::ALOAD | opcodes::ISTORE..=opcodes::ASTORE | opcodes::RET => {
2404            Ok(Insn::Var(VarInsnNode {
2405                insn: opcode.into(),
2406                var_index: reader.read_u2()?,
2407            }))
2408        }
2409        opcodes::IINC => Ok(Insn::Iinc(IincInsnNode {
2410            insn: opcode.into(),
2411            var_index: reader.read_u2()?,
2412            increment: reader.read_i2()?,
2413        })),
2414        _ => Err(ClassReadError::InvalidOpcode {
2415            opcode,
2416            offset: reader.pos().saturating_sub(1),
2417        }),
2418    }
2419}
2420
2421fn visit_instruction(
2422    cp: &[CpInfo],
2423    offset: i32,
2424    insn: Insn,
2425    mv: &mut dyn MethodVisitor,
2426) -> Result<(), ClassReadError> {
2427    match insn {
2428        Insn::Simple(node) => {
2429            mv.visit_insn(node.opcode);
2430        }
2431        Insn::Int(node) => {
2432            mv.visit_int_insn(node.insn.opcode, node.operand);
2433        }
2434        Insn::Var(node) => {
2435            mv.visit_var_insn(node.insn.opcode, node.var_index);
2436        }
2437        Insn::Type(node) => {
2438            let type_name = cp_class_name(cp, node.type_index)?;
2439            mv.visit_type_insn(node.insn.opcode, type_name);
2440        }
2441        Insn::Field(node) => {
2442            let index = match node.field_ref {
2443                MemberRef::Index(index) => index,
2444                MemberRef::Symbolic { .. } => {
2445                    return Err(ClassReadError::InvalidIndex(0));
2446                }
2447            };
2448            let (owner, name, desc) = cp_field_ref(cp, index)?;
2449            mv.visit_field_insn(node.insn.opcode, owner, name, desc);
2450        }
2451        Insn::Method(node) => {
2452            let index = match node.method_ref {
2453                MemberRef::Index(index) => index,
2454                MemberRef::Symbolic { .. } => {
2455                    return Err(ClassReadError::InvalidIndex(0));
2456                }
2457            };
2458            let (owner, name, desc, is_interface) = cp_method_ref(cp, index)?;
2459            mv.visit_method_insn(node.insn.opcode, owner, name, desc, is_interface);
2460        }
2461        Insn::InvokeInterface(node) => {
2462            let (owner, name, desc, _is_interface) = cp_method_ref(cp, node.method_index)?;
2463            mv.visit_method_insn(node.insn.opcode, owner, name, desc, true);
2464        }
2465        Insn::InvokeDynamic(node) => {
2466            let (name, desc) = cp_invoke_dynamic(cp, node.method_index)?;
2467            mv.visit_invoke_dynamic_insn(name, desc);
2468        }
2469        Insn::Jump(node) => {
2470            let target = offset + node.offset;
2471            mv.visit_jump_insn(node.insn.opcode, target);
2472        }
2473        Insn::Ldc(node) => {
2474            let index = match node.value {
2475                LdcValue::Index(index) => index,
2476                LdcValue::String(value) => {
2477                    mv.visit_ldc_insn(LdcConstant::String(value));
2478                    return Ok(());
2479                }
2480                LdcValue::Type(value) => {
2481                    match value.clone() {
2482                        Type::Method { .. } => {
2483                            mv.visit_ldc_insn(LdcConstant::MethodType(value.get_descriptor()));
2484                        }
2485                        _ => {
2486                            mv.visit_ldc_insn(LdcConstant::Class(value.get_descriptor()));
2487                        }
2488                    }
2489
2490                    return Ok(());
2491                }
2492                LdcValue::Int(value) => {
2493                    mv.visit_ldc_insn(LdcConstant::Integer(value));
2494                    return Ok(());
2495                }
2496                LdcValue::Float(value) => {
2497                    mv.visit_ldc_insn(LdcConstant::Float(value));
2498                    return Ok(());
2499                }
2500                LdcValue::Long(value) => {
2501                    mv.visit_ldc_insn(LdcConstant::Long(value));
2502                    return Ok(());
2503                }
2504                LdcValue::Double(value) => {
2505                    mv.visit_ldc_insn(LdcConstant::Double(value));
2506                    return Ok(());
2507                }
2508            };
2509            let constant = cp_ldc_constant(cp, index)?;
2510            mv.visit_ldc_insn(constant);
2511        }
2512        Insn::Iinc(node) => {
2513            mv.visit_iinc_insn(node.var_index, node.increment);
2514        }
2515        Insn::TableSwitch(node) => {
2516            let targets = node
2517                .offsets
2518                .iter()
2519                .map(|value| offset + *value)
2520                .collect::<Vec<_>>();
2521            mv.visit_table_switch(offset + node.default_offset, node.low, node.high, &targets);
2522        }
2523        Insn::LookupSwitch(node) => {
2524            let pairs = node
2525                .pairs
2526                .iter()
2527                .map(|(key, value)| (*key, offset + *value))
2528                .collect::<Vec<_>>();
2529            mv.visit_lookup_switch(offset + node.default_offset, &pairs);
2530        }
2531        Insn::MultiANewArray(node) => {
2532            let type_name = cp_class_name(cp, node.type_index)?;
2533            mv.visit_multi_anewarray_insn(type_name, node.dimensions);
2534        }
2535    }
2536    Ok(())
2537}
2538
2539pub struct ByteReader<'a> {
2540    data: &'a [u8],
2541    pos: usize,
2542}
2543
2544impl<'a> ByteReader<'a> {
2545    pub fn new(data: &'a [u8]) -> Self {
2546        Self { data, pos: 0 }
2547    }
2548
2549    pub fn remaining(&self) -> usize {
2550        self.data.len().saturating_sub(self.pos)
2551    }
2552
2553    pub fn pos(&self) -> usize {
2554        self.pos
2555    }
2556
2557    pub fn align4(&mut self, opcode_offset: usize) -> Result<(), ClassReadError> {
2558        let mut padding = (4 - ((opcode_offset + 1) % 4)) % 4;
2559        while padding > 0 {
2560            self.read_u1()?;
2561            padding -= 1;
2562        }
2563        Ok(())
2564    }
2565
2566    pub fn read_u1(&mut self) -> Result<u8, ClassReadError> {
2567        if self.pos >= self.data.len() {
2568            return Err(ClassReadError::UnexpectedEof);
2569        }
2570        let value = self.data[self.pos];
2571        self.pos += 1;
2572        Ok(value)
2573    }
2574
2575    pub fn read_i1(&mut self) -> Result<i8, ClassReadError> {
2576        Ok(self.read_u1()? as i8)
2577    }
2578
2579    pub fn read_u2(&mut self) -> Result<u16, ClassReadError> {
2580        let bytes = self.read_bytes(2)?;
2581        Ok(u16::from_be_bytes([bytes[0], bytes[1]]))
2582    }
2583
2584    pub fn read_i2(&mut self) -> Result<i16, ClassReadError> {
2585        Ok(self.read_u2()? as i16)
2586    }
2587
2588    pub fn read_u4(&mut self) -> Result<u32, ClassReadError> {
2589        let bytes = self.read_bytes(4)?;
2590        Ok(u32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
2591    }
2592
2593    pub fn read_i4(&mut self) -> Result<i32, ClassReadError> {
2594        let bytes = self.read_bytes(4)?;
2595        Ok(i32::from_be_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
2596    }
2597
2598    pub fn read_u8(&mut self) -> Result<u64, ClassReadError> {
2599        let bytes = self.read_bytes(8)?;
2600        Ok(u64::from_be_bytes([
2601            bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7],
2602        ]))
2603    }
2604
2605    pub fn read_bytes(&mut self, len: usize) -> Result<Vec<u8>, ClassReadError> {
2606        if self.pos + len > self.data.len() {
2607            return Err(ClassReadError::UnexpectedEof);
2608        }
2609        let bytes = self.data[self.pos..self.pos + len].to_vec();
2610        self.pos += len;
2611        Ok(bytes)
2612    }
2613}
2614
2615#[cfg(test)]
2616mod tests {
2617    use crate::class_writer::ClassWriter;
2618    use crate::constants::*;
2619    use crate::insn::{Label, LabelNode};
2620    use crate::opcodes;
2621
2622    use super::*;
2623    use std::cell::RefCell;
2624    use std::rc::Rc;
2625
2626    // A mock visitor to capture parsing results
2627    struct MockClassVisitor {
2628        pub visited_name: Rc<RefCell<Option<String>>>,
2629        pub visited_methods: Rc<RefCell<Vec<String>>>,
2630    }
2631
2632    impl MockClassVisitor {
2633        fn new() -> Self {
2634            Self {
2635                visited_name: Rc::new(RefCell::new(None)),
2636                visited_methods: Rc::new(RefCell::new(Vec::new())),
2637            }
2638        }
2639    }
2640
2641    impl ClassVisitor for MockClassVisitor {
2642        fn visit(
2643            &mut self,
2644            _major: u16,
2645            _minor: u16,
2646            _access_flags: u16,
2647            name: &str,
2648            _super_name: Option<&str>,
2649            _interfaces: &[String],
2650        ) {
2651            *self.visited_name.borrow_mut() = Some(name.to_string());
2652        }
2653
2654        fn visit_method(
2655            &mut self,
2656            _access_flags: u16,
2657            name: &str,
2658            _descriptor: &str,
2659        ) -> Option<Box<dyn MethodVisitor>> {
2660            self.visited_methods.borrow_mut().push(name.to_string());
2661            None
2662        }
2663    }
2664
2665    /// Helper to generate a minimal valid class file byte array (Java 8).
2666    /// Class Name: "TestClass"
2667    fn generate_minimal_class() -> Vec<u8> {
2668        let mut w = Vec::new();
2669        // Magic
2670        w.extend_from_slice(&0xCAFEBABE_u32.to_be_bytes());
2671        // Version (Java 8 = 52.0)
2672        w.extend_from_slice(&0_u16.to_be_bytes()); // minor
2673        w.extend_from_slice(&52_u16.to_be_bytes()); // major
2674
2675        // Constant Pool (Count: 5)
2676        // 1: UTF8 "TestClass"
2677        // 2: Class #1
2678        // 3: UTF8 "java/lang/Object"
2679        // 4: Class #3
2680        w.extend_from_slice(&5_u16.to_be_bytes()); // Count (N+1)
2681
2682        // #1 UTF8
2683        w.push(1);
2684        let name = "TestClass";
2685        w.extend_from_slice(&(name.len() as u16).to_be_bytes());
2686        w.extend_from_slice(name.as_bytes());
2687
2688        // #2 Class
2689        w.push(7);
2690        w.extend_from_slice(&1_u16.to_be_bytes());
2691
2692        // #3 UTF8
2693        w.push(1);
2694        let obj = "java/lang/Object";
2695        w.extend_from_slice(&(obj.len() as u16).to_be_bytes());
2696        w.extend_from_slice(obj.as_bytes());
2697
2698        // #4 Class
2699        w.push(7);
2700        w.extend_from_slice(&3_u16.to_be_bytes());
2701
2702        // Access Flags (PUBLIC)
2703        w.extend_from_slice(&0x0021_u16.to_be_bytes());
2704        // This Class (#2)
2705        w.extend_from_slice(&2_u16.to_be_bytes());
2706        // Super Class (#4)
2707        w.extend_from_slice(&4_u16.to_be_bytes());
2708
2709        // Interfaces Count
2710        w.extend_from_slice(&0_u16.to_be_bytes());
2711        // Fields Count
2712        w.extend_from_slice(&0_u16.to_be_bytes());
2713        // Methods Count
2714        w.extend_from_slice(&0_u16.to_be_bytes());
2715        // Attributes Count
2716        w.extend_from_slice(&0_u16.to_be_bytes());
2717
2718        w
2719    }
2720
2721    fn generate_module_info_class() -> Vec<u8> {
2722        let mut writer = ClassWriter::new(0);
2723        writer.visit(V9, 0, ACC_MODULE, "module-info", None, &[]);
2724
2725        let mut module = writer.visit_module("com.example.app", ACC_OPEN, Some("1.0"));
2726        module.visit_main_class("com/example/app/Main");
2727        module.visit_package("com/example/api");
2728        module.visit_package("com/example/internal");
2729        module.visit_require("java.base", ACC_MANDATED, None);
2730        module.visit_require(
2731            "com.example.lib",
2732            ACC_TRANSITIVE | ACC_STATIC_PHASE,
2733            Some("2.1"),
2734        );
2735        module.visit_export("com/example/api", 0, &["com.example.consumer"]);
2736        module.visit_open("com/example/internal", 0, &["com.example.runtime"]);
2737        module.visit_use("com/example/spi/Service");
2738        module.visit_provide("com/example/spi/Service", &["com/example/impl/ServiceImpl"]);
2739        module.visit_end(&mut writer);
2740
2741        writer.to_bytes().expect("module-info should encode")
2742    }
2743
2744    #[test]
2745    fn test_class_reader_header() {
2746        let bytes = generate_minimal_class();
2747        let reader = ClassReader::new(&bytes);
2748        let mut visitor = MockClassVisitor::new();
2749
2750        let result = reader.accept(&mut visitor, 0);
2751
2752        assert!(result.is_ok(), "Should parse valid class file");
2753        assert_eq!(
2754            *visitor.visited_name.borrow(),
2755            Some("TestClass".to_string())
2756        );
2757    }
2758
2759    #[test]
2760    fn test_invalid_magic() {
2761        // expected CA FE BA BE
2762        let bytes = vec![0x00, 0x00, 0x00, 0x00];
2763        let reader = ClassReader::new(&bytes);
2764        let mut visitor = MockClassVisitor::new();
2765
2766        let result = reader.accept(&mut visitor, 0);
2767        assert!(matches!(result, Err(ClassReadError::InvalidMagic(_))));
2768    }
2769
2770    #[test]
2771    fn test_code_reader_alignment() {
2772        // Test internal alignment logic for switch instructions
2773        let data = vec![0x00, 0x00, 0x00, 0x00]; // 4 bytes
2774        let mut reader = super::ByteReader::new(&data);
2775
2776        // If we are at pos 1, padding to 4-byte boundary
2777        reader.pos = 1;
2778        // 1 -> align 4 -> skips 3 bytes -> pos 4
2779        assert!(reader.align4(0).is_ok());
2780        assert_eq!(reader.pos(), 4);
2781    }
2782
2783    #[test]
2784    fn test_parse_runtime_visible_type_annotations_supertype() {
2785        // RuntimeVisibleTypeAnnotations:
2786        // u2 num_annotations = 1
2787        // type_annotation:
2788        //   u1 target_type = TA_TARGET_CLASS_EXTENDS
2789        //   u2 supertype_index = 5
2790        //   type_path: u1 path_len=0
2791        //   annotation:
2792        //     u2 type_descriptor_index=10
2793        //     u2 num_pairs=0
2794        let mut info = vec![];
2795        u2(1, &mut info);
2796        u1(TA_TARGET_CLASS_EXTENDS, &mut info);
2797        u2(5, &mut info);
2798        u1(0, &mut info);
2799        u2(10, &mut info);
2800        u2(0, &mut info);
2801
2802        let cp: Vec<CpInfo> = vec![];
2803        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2804
2805        match attr {
2806            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2807                assert_eq!(annotations.len(), 1);
2808                let a = &annotations[0];
2809                assert_eq!(a.target_type, TA_TARGET_CLASS_EXTENDS);
2810                assert!(matches!(
2811                    a.target_info,
2812                    TypeAnnotationTargetInfo::Supertype { supertype_index: 5 }
2813                ));
2814                assert_eq!(a.target_path.path.len(), 0);
2815                assert_eq!(a.annotation.type_descriptor_index, 10);
2816                assert_eq!(a.annotation.element_value_pairs.len(), 0);
2817            }
2818            other => panic!("unexpected attr: {:?}", other),
2819        }
2820    }
2821
2822    #[test]
2823    fn test_parse_runtime_visible_type_annotations_formal_parameter_with_path() {
2824        // target_type = TA_TARGET_METHOD_FORMAL_PARAMETER
2825        // u1 formal_parameter_index = 2
2826        // type_path len=1 entry(kind=TA_TYPE_PATH_ARRAY, arg_index=0)
2827        // annotation: type_index=9, num_pairs=0
2828        let mut info = vec![];
2829        u2(1, &mut info);
2830        u1(TA_TARGET_METHOD_FORMAL_PARAMETER, &mut info);
2831        u1(2, &mut info);
2832
2833        u1(1, &mut info); // path_length
2834        u1(TA_TYPE_PATH_ARRAY, &mut info);
2835        u1(0, &mut info);
2836
2837        u2(9, &mut info);
2838        u2(0, &mut info);
2839
2840        let cp: Vec<CpInfo> = vec![];
2841        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2842
2843        match attr {
2844            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2845                let a = &annotations[0];
2846                assert_eq!(a.target_type, TA_TARGET_METHOD_FORMAL_PARAMETER);
2847                assert!(matches!(
2848                    a.target_info,
2849                    TypeAnnotationTargetInfo::FormalParameter {
2850                        formal_parameter_index: 2
2851                    }
2852                ));
2853                assert_eq!(a.target_path.path.len(), 1);
2854                assert_eq!(a.target_path.path[0].type_path_kind, TA_TYPE_PATH_ARRAY);
2855                assert_eq!(a.target_path.path[0].type_argument_index, 0);
2856            }
2857            other => panic!("unexpected attr: {:?}", other),
2858        }
2859    }
2860
2861    #[test]
2862    fn test_parse_runtime_visible_type_annotations_localvar_table() {
2863        // target_type = TA_TARGET_LOCAL_VARIABLE
2864        // u2 table_length = 1
2865        // entry: start_pc=1 length=2 index=3
2866        // type_path len=0
2867        // annotation: type_index=8, num_pairs=0
2868        let mut info = vec![];
2869        u2(1, &mut info);
2870        u1(TA_TARGET_LOCAL_VARIABLE, &mut info);
2871
2872        u2(1, &mut info); // table_length
2873        u2(1, &mut info);
2874        u2(2, &mut info);
2875        u2(3, &mut info);
2876
2877        u1(0, &mut info); // path_length
2878        u2(8, &mut info);
2879        u2(0, &mut info);
2880
2881        let cp: Vec<CpInfo> = vec![];
2882        let attr = parse_attribute("RuntimeVisibleTypeAnnotations", info, &cp).unwrap();
2883
2884        match attr {
2885            AttributeInfo::RuntimeVisibleTypeAnnotations { annotations } => {
2886                let a = &annotations[0];
2887                assert_eq!(a.target_type, TA_TARGET_LOCAL_VARIABLE);
2888                match &a.target_info {
2889                    TypeAnnotationTargetInfo::LocalVar { table } => {
2890                        assert_eq!(table.len(), 1);
2891                        assert_eq!(table[0].start_pc, 1);
2892                        assert_eq!(table[0].length, 2);
2893                        assert_eq!(table[0].index, 3);
2894                    }
2895                    other => panic!("unexpected target_info: {:?}", other),
2896                }
2897            }
2898            other => panic!("unexpected attr: {:?}", other),
2899        }
2900    }
2901
2902    #[test]
2903    fn test_parse_module_attribute_family() {
2904        let mut module_info = vec![];
2905        u2(1, &mut module_info);
2906        u2(ACC_OPEN, &mut module_info);
2907        u2(2, &mut module_info);
2908        u2(1, &mut module_info);
2909        u2(3, &mut module_info);
2910        u2(ACC_TRANSITIVE | ACC_STATIC_PHASE, &mut module_info);
2911        u2(4, &mut module_info);
2912        u2(1, &mut module_info);
2913        u2(5, &mut module_info);
2914        u2(ACC_MANDATED, &mut module_info);
2915        u2(2, &mut module_info);
2916        u2(6, &mut module_info);
2917        u2(7, &mut module_info);
2918        u2(1, &mut module_info);
2919        u2(8, &mut module_info);
2920        u2(0, &mut module_info);
2921        u2(1, &mut module_info);
2922        u2(9, &mut module_info);
2923        u2(1, &mut module_info);
2924        u2(10, &mut module_info);
2925        u2(1, &mut module_info);
2926        u2(11, &mut module_info);
2927        u2(2, &mut module_info);
2928        u2(12, &mut module_info);
2929        u2(13, &mut module_info);
2930
2931        let attr = parse_attribute("Module", module_info, &[]).expect("module attr should parse");
2932        match attr {
2933            AttributeInfo::Module(module) => {
2934                assert_eq!(module.module_name_index, 1);
2935                assert_eq!(module.module_flags, ACC_OPEN);
2936                assert_eq!(module.module_version_index, 2);
2937                assert_eq!(
2938                    module.requires,
2939                    vec![ModuleRequire {
2940                        requires_index: 3,
2941                        requires_flags: ACC_TRANSITIVE | ACC_STATIC_PHASE,
2942                        requires_version_index: 4,
2943                    }]
2944                );
2945                assert_eq!(
2946                    module.exports,
2947                    vec![ModuleExport {
2948                        exports_index: 5,
2949                        exports_flags: ACC_MANDATED,
2950                        exports_to_index: vec![6, 7],
2951                    }]
2952                );
2953                assert_eq!(
2954                    module.opens,
2955                    vec![ModuleOpen {
2956                        opens_index: 8,
2957                        opens_flags: 0,
2958                        opens_to_index: vec![9],
2959                    }]
2960                );
2961                assert_eq!(module.uses_index, vec![10]);
2962                assert_eq!(
2963                    module.provides,
2964                    vec![ModuleProvide {
2965                        provides_index: 11,
2966                        provides_with_index: vec![12, 13],
2967                    }]
2968                );
2969            }
2970            other => panic!("unexpected attr: {:?}", other),
2971        }
2972
2973        let mut packages_info = vec![];
2974        u2(2, &mut packages_info);
2975        u2(21, &mut packages_info);
2976        u2(22, &mut packages_info);
2977        let attr = parse_attribute("ModulePackages", packages_info, &[])
2978            .expect("module packages attr should parse");
2979        match attr {
2980            AttributeInfo::ModulePackages {
2981                package_index_table,
2982            } => {
2983                assert_eq!(package_index_table, vec![21, 22]);
2984            }
2985            other => panic!("unexpected attr: {:?}", other),
2986        }
2987
2988        let mut main_class_info = vec![];
2989        u2(23, &mut main_class_info);
2990        let attr = parse_attribute("ModuleMainClass", main_class_info, &[])
2991            .expect("module main class attr should parse");
2992        match attr {
2993            AttributeInfo::ModuleMainClass { main_class_index } => {
2994                assert_eq!(main_class_index, 23);
2995            }
2996            other => panic!("unexpected attr: {:?}", other),
2997        }
2998    }
2999
3000    fn u1(v: u8, out: &mut Vec<u8>) {
3001        out.push(v);
3002    }
3003    fn u2(v: u16, out: &mut Vec<u8>) {
3004        out.extend_from_slice(&v.to_be_bytes());
3005    }
3006
3007    #[test]
3008    fn test_method_node_contains_offsets_and_line_numbers() {
3009        let mut writer = ClassWriter::new(0);
3010        writer.visit(
3011            52,
3012            0,
3013            ACC_PUBLIC,
3014            "TestNodeData",
3015            Some("java/lang/Object"),
3016            &[],
3017        );
3018
3019        let mut ctor = writer.visit_method(ACC_PUBLIC, "<init>", "()V");
3020        ctor.visit_code();
3021        ctor.visit_var_insn(opcodes::ALOAD, 0);
3022        ctor.visit_method_insn(
3023            opcodes::INVOKESPECIAL,
3024            "java/lang/Object",
3025            "<init>",
3026            "()V",
3027            false,
3028        );
3029        ctor.visit_insn(opcodes::RETURN);
3030        ctor.visit_maxs(1, 1);
3031        ctor.visit_end(&mut writer);
3032
3033        let mut method = writer.visit_method(ACC_PUBLIC | ACC_STATIC, "answer", "()I");
3034        let start = Label::new();
3035        method.visit_code();
3036        method.visit_label(start);
3037        method.visit_line_number(123, LabelNode::from_label(start));
3038        method.visit_insn(opcodes::ICONST_1);
3039        method.visit_insn(opcodes::IRETURN);
3040        method.visit_maxs(1, 0);
3041        method.visit_end(&mut writer);
3042
3043        let bytes = writer.to_bytes().expect("class should encode");
3044        let class = ClassReader::new(&bytes)
3045            .to_class_node()
3046            .expect("class should decode");
3047        let method = class
3048            .methods
3049            .iter()
3050            .find(|method| method.name == "answer")
3051            .expect("method should exist");
3052
3053        assert_eq!(method.instruction_offsets, vec![0, 1]);
3054        assert_eq!(method.line_numbers.len(), 1);
3055        assert_eq!(method.line_numbers[0].line_number, 123);
3056        assert!(
3057            method
3058                .insn_nodes
3059                .iter()
3060                .any(|node| matches!(node, AbstractInsnNode::LineNumber(_)))
3061        );
3062        assert!(
3063            method
3064                .insn_nodes
3065                .iter()
3066                .any(|node| matches!(node, AbstractInsnNode::Label(_)))
3067        );
3068        assert!(method.try_catch_blocks.is_empty());
3069    }
3070
3071    #[test]
3072    fn test_method_node_contains_try_catch_blocks() {
3073        let mut writer = ClassWriter::new(0);
3074        writer.visit(
3075            52,
3076            0,
3077            ACC_PUBLIC,
3078            "TestTryCatchNode",
3079            Some("java/lang/Object"),
3080            &[],
3081        );
3082
3083        let mut ctor = writer.visit_method(ACC_PUBLIC, "<init>", "()V");
3084        ctor.visit_code();
3085        ctor.visit_var_insn(opcodes::ALOAD, 0);
3086        ctor.visit_method_insn(
3087            opcodes::INVOKESPECIAL,
3088            "java/lang/Object",
3089            "<init>",
3090            "()V",
3091            false,
3092        );
3093        ctor.visit_insn(opcodes::RETURN);
3094        ctor.visit_maxs(1, 1);
3095        ctor.visit_end(&mut writer);
3096
3097        let start = Label::new();
3098        let end = Label::new();
3099        let handler = Label::new();
3100        let mut method =
3101            writer.visit_method(ACC_PUBLIC | ACC_STATIC, "safeLen", "(Ljava/lang/String;)I");
3102        method.visit_code();
3103        method.visit_label(start);
3104        method.visit_var_insn(opcodes::ALOAD, 0);
3105        method.visit_method_insn(
3106            opcodes::INVOKEVIRTUAL,
3107            "java/lang/String",
3108            "length",
3109            "()I",
3110            false,
3111        );
3112        method.visit_insn(opcodes::IRETURN);
3113        method.visit_label(end);
3114        method.visit_label(handler);
3115        method.visit_var_insn(opcodes::ASTORE, 1);
3116        method.visit_insn(opcodes::ICONST_M1);
3117        method.visit_insn(opcodes::IRETURN);
3118        method.visit_try_catch_block(start, end, handler, Some("java/lang/RuntimeException"));
3119        method.visit_maxs(1, 2);
3120        method.visit_end(&mut writer);
3121
3122        let bytes = writer.to_bytes().expect("class should encode");
3123        let class = ClassReader::new(&bytes)
3124            .to_class_node()
3125            .expect("class should decode");
3126        let method = class
3127            .methods
3128            .iter()
3129            .find(|method| method.name == "safeLen")
3130            .expect("method should exist");
3131
3132        assert_eq!(method.exception_table.len(), 1);
3133        assert_eq!(method.try_catch_blocks.len(), 1);
3134        assert_eq!(
3135            method.try_catch_blocks[0].catch_type.as_deref(),
3136            Some("java/lang/RuntimeException")
3137        );
3138    }
3139
3140    #[test]
3141    fn test_parse_runtime_visible_annotations_one_empty() {
3142        // u2 num_annotations=1
3143        // annotation: type=10, pairs=0
3144        let mut info = vec![];
3145        u2(1, &mut info);
3146        u2(10, &mut info);
3147        u2(0, &mut info);
3148
3149        let cp: Vec<CpInfo> = vec![];
3150        let attr = parse_attribute("RuntimeVisibleAnnotations", info, &cp).unwrap();
3151        match attr {
3152            AttributeInfo::RuntimeVisibleAnnotations { annotations } => {
3153                assert_eq!(annotations.len(), 1);
3154                assert_eq!(annotations[0].type_descriptor_index, 10);
3155                assert_eq!(annotations[0].element_value_pairs.len(), 0);
3156            }
3157            other => panic!("unexpected attr: {:?}", other),
3158        }
3159    }
3160
3161    #[test]
3162    fn test_parse_runtime_visible_parameter_annotations_two_params() {
3163        // u1 num_params=2
3164        // p0: u2 num_ann=1, annotation(type=10,pairs=0)
3165        // p1: u2 num_ann=0
3166        let mut info = vec![];
3167        u1(2, &mut info);
3168        u2(1, &mut info);
3169        u2(10, &mut info);
3170        u2(0, &mut info);
3171        u2(0, &mut info);
3172
3173        let cp: Vec<CpInfo> = vec![];
3174        let attr = parse_attribute("RuntimeVisibleParameterAnnotations", info, &cp).unwrap();
3175        match attr {
3176            AttributeInfo::RuntimeVisibleParameterAnnotations { parameters } => {
3177                assert_eq!(parameters.parameters.len(), 2);
3178                assert_eq!(parameters.parameters[0].len(), 1);
3179                assert_eq!(parameters.parameters[1].len(), 0);
3180            }
3181            other => panic!("unexpected attr: {:?}", other),
3182        }
3183    }
3184
3185    #[test]
3186    fn test_class_reader_decodes_module_info_node() {
3187        let bytes = generate_module_info_class();
3188        let class = ClassReader::new(&bytes)
3189            .to_class_node()
3190            .expect("module-info should decode");
3191
3192        assert_eq!(class.name, "module-info");
3193        assert_eq!(class.access_flags, ACC_MODULE);
3194
3195        let module = class.module.expect("module descriptor should be decoded");
3196        assert_eq!(module.name, "com.example.app");
3197        assert_eq!(module.access_flags, ACC_OPEN);
3198        assert_eq!(module.version.as_deref(), Some("1.0"));
3199        assert_eq!(module.main_class.as_deref(), Some("com/example/app/Main"));
3200        assert_eq!(
3201            module.packages,
3202            vec![
3203                "com/example/api".to_string(),
3204                "com/example/internal".to_string()
3205            ]
3206        );
3207        assert_eq!(module.requires.len(), 2);
3208        assert_eq!(module.requires[0].module, "java.base");
3209        assert_eq!(module.requires[0].access_flags, ACC_MANDATED);
3210        assert_eq!(module.requires[0].version, None);
3211        assert_eq!(module.requires[1].module, "com.example.lib");
3212        assert_eq!(
3213            module.requires[1].access_flags,
3214            ACC_TRANSITIVE | ACC_STATIC_PHASE
3215        );
3216        assert_eq!(module.requires[1].version.as_deref(), Some("2.1"));
3217        assert_eq!(module.exports.len(), 1);
3218        assert_eq!(module.exports[0].package, "com/example/api");
3219        assert_eq!(
3220            module.exports[0].modules,
3221            vec!["com.example.consumer".to_string()]
3222        );
3223        assert_eq!(module.opens.len(), 1);
3224        assert_eq!(module.opens[0].package, "com/example/internal");
3225        assert_eq!(
3226            module.opens[0].modules,
3227            vec!["com.example.runtime".to_string()]
3228        );
3229        assert_eq!(module.uses, vec!["com/example/spi/Service".to_string()]);
3230        assert_eq!(module.provides.len(), 1);
3231        assert_eq!(module.provides[0].service, "com/example/spi/Service");
3232        assert_eq!(
3233            module.provides[0].providers,
3234            vec!["com/example/impl/ServiceImpl".to_string()]
3235        );
3236    }
3237}