1#![allow(dead_code)]
10
11use std::{
12 borrow::Cow,
13 fmt::{Debug, Formatter},
14};
15
16pub use crate::{
17 attribute::*,
18 cursor::{Cursor, ReadBytes},
19 error::{Error, Result},
20 field::*,
21 method::*,
22 utf8::Cesu8Bytes,
23};
24
25mod cursor;
26
27const MAGIC: u32 = 0xCAFE_BABE;
29
30const MIN_MAJOR_VERSION: u16 = 45;
32const MAX_MAJOR_VERSION: u16 = 52;
34
35pub type CpIndex = u16;
39
40mod error {
41 use std::fmt::{Display, Formatter};
42
43 use cesu8::Cesu8DecodingError;
44
45 use crate::CpIndex;
46
47 pub type Result<T> = std::result::Result<T, Error>;
49
50 #[derive(Debug)]
52 pub enum Error {
53 InvalidMagic {
54 magic: u32,
55 },
56 UnsupportedVersion {
57 major_version: u16,
58 minor_version: u16,
59 supported: std::ops::RangeInclusive<u16>,
60 },
61 InvalidConstantPoolCount {
62 count: u16,
63 },
64 InvalidConstantPoolTag {
65 tag: u8,
66 },
67 ConstantPoolOverflow {
68 index: CpIndex,
69 },
70 ConstantPoolIndexOutOfBounds {
71 index: CpIndex,
72 count: usize,
73 },
74 ConstantPoolIndexUnusable {
75 index: CpIndex,
76 },
77 UnexpectedConstantPoolEntry {
78 index: CpIndex,
79 expected: &'static str,
80 found: &'static str,
81 },
82 AttributeLengthMismatch {
83 name: String,
84 expected: usize,
85 consumed: usize,
86 },
87 InvalidReferenceKind {
88 kind: u8,
89 },
90 InvalidVerificationTypeTag {
91 tag: u8,
92 },
93 InvalidStackMapFrameTag {
94 tag: u8,
95 },
96 InvalidElementValueTag {
97 tag: u8,
98 },
99 InvalidTypeAnnotationTarget {
100 target_type: u8,
101 },
102 TrailingBytes {
103 count: usize,
104 },
105 InvalidCesu8(Cesu8DecodingError),
106 UnexpectedEof {
107 needed: usize,
108 available: usize,
109 },
110 }
111
112 impl Display for Error {
113 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
114 match self {
115 Self::InvalidMagic { magic } => write!(f, "invalid class magic 0x{magic:08X}"),
116 Self::UnsupportedVersion {
117 major_version,
118 minor_version,
119 supported,
120 } => write!(
121 f,
122 "unsupported class version {major_version}.{minor_version}, \
123 supported major versions are {}..={}",
124 supported.start(),
125 supported.end()
126 ),
127 Self::InvalidConstantPoolCount { count } => {
128 write!(
129 f,
130 "invalid constant pool count {count}, expected at least 1"
131 )
132 }
133 Self::InvalidConstantPoolTag { tag } => {
134 write!(f, "invalid constant pool tag {tag}")
135 }
136 Self::ConstantPoolOverflow { index } => write!(
137 f,
138 "wide constant at index {index} overflows the constant pool"
139 ),
140 Self::ConstantPoolIndexOutOfBounds { index, count } => write!(
141 f,
142 "constant pool index {index} is out of bounds (pool holds {count} slots)"
143 ),
144 Self::ConstantPoolIndexUnusable { index } => write!(
145 f,
146 "constant pool index {index} points at the unusable slot of a wide constant"
147 ),
148 Self::UnexpectedConstantPoolEntry {
149 index,
150 expected,
151 found,
152 } => write!(
153 f,
154 "constant pool index {index} refers to {found}, expected {expected}"
155 ),
156 Self::AttributeLengthMismatch {
157 name,
158 expected,
159 consumed,
160 } => write!(
161 f,
162 "attribute {name} declares {expected} bytes but {consumed} were consumed"
163 ),
164 Self::InvalidReferenceKind { kind } => {
165 write!(f, "invalid method handle reference kind {kind}")
166 }
167 Self::InvalidVerificationTypeTag { tag } => {
168 write!(f, "invalid verification type tag {tag}")
169 }
170 Self::InvalidStackMapFrameTag { tag } => {
171 write!(f, "invalid stack map frame tag {tag}")
172 }
173 Self::InvalidElementValueTag { tag } => {
174 write!(f, "invalid element value tag {tag} ({:?})", *tag as char)
175 }
176 Self::InvalidTypeAnnotationTarget { target_type } => {
177 write!(f, "invalid type annotation target type 0x{target_type:02X}")
178 }
179 Self::TrailingBytes { count } => {
180 write!(f, "{count} trailing bytes after the class file")
181 }
182 Self::InvalidCesu8(error) => write!(f, "invalid CESU-8 string: {error}"),
183 Self::UnexpectedEof { needed, available } => write!(
184 f,
185 "unexpected EOF: needed {needed} bytes, {available} available"
186 ),
187 }
188 }
189 }
190
191 impl std::error::Error for Error {
192 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
193 match self {
194 Self::InvalidCesu8(error) => Some(error),
195 _ => None,
196 }
197 }
198 }
199
200 impl From<Cesu8DecodingError> for Error {
201 fn from(value: Cesu8DecodingError) -> Self {
202 Self::InvalidCesu8(value)
203 }
204 }
205}
206
207mod utf8 {
208 use std::{
209 borrow::Cow,
210 fmt::{Debug, Display, Formatter},
211 };
212
213 use crate::error::Result;
214
215 #[derive(Clone, Copy, PartialEq, Eq)]
219 pub struct Cesu8Bytes<'a>(&'a [u8]);
220
221 impl<'a> Cesu8Bytes<'a> {
222 pub fn as_bytes(&self) -> &'a [u8] {
224 self.0
225 }
226
227 pub fn decode(&self) -> Result<Cow<'a, str>> {
229 Ok(cesu8::from_java_cesu8(self.0)?)
230 }
231
232 pub fn decode_owned(&self) -> Result<String> {
234 Ok(self.decode()?.into_owned())
235 }
236 }
237
238 impl Debug for Cesu8Bytes<'_> {
239 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
240 match self.decode() {
241 Ok(string) => Debug::fmt(&string, f),
242 Err(_) => write!(f, "<invalid cesu-8: {:02X?}>", self.0),
243 }
244 }
245 }
246
247 impl Display for Cesu8Bytes<'_> {
248 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
249 match self.decode() {
250 Ok(string) => f.write_str(&string),
251 Err(_) => write!(f, "<invalid cesu-8>"),
252 }
253 }
254 }
255
256 impl<'a> From<&'a [u8]> for Cesu8Bytes<'a> {
257 fn from(value: &'a [u8]) -> Self {
258 Self(value)
259 }
260 }
261
262 impl<'a> TryFrom<Cesu8Bytes<'a>> for String {
263 type Error = crate::error::Error;
264
265 fn try_from(value: Cesu8Bytes<'a>) -> Result<Self> {
266 value.decode_owned()
267 }
268 }
269}
270
271#[derive(Debug)]
275pub struct Class<'a> {
276 pub minor_version: u16,
277 pub major_version: u16,
278 pub constant_pool: ConstantPool<'a>,
279 pub access_flags: ClassAccessFlags,
280 pub this_class: CpIndex,
281 pub super_class: Option<CpIndex>,
282 pub interfaces: Vec<CpIndex>,
283 pub fields: Vec<FieldInfo<'a>>,
284 pub methods: Vec<MethodInfo<'a>>,
285 pub attributes: Vec<AttributeInfo<'a>>,
286}
287
288impl<'a> Class<'a> {
289 pub fn parse(bytes: &'a [u8]) -> Result<Self> {
291 let mut cursor = Cursor::new(bytes);
292 let class = Self::try_read(&mut cursor)?;
293
294 if !cursor.is_empty() {
295 return Err(Error::TrailingBytes {
296 count: cursor.len(),
297 });
298 }
299
300 Ok(class)
301 }
302
303 pub fn try_read(cursor: &mut Cursor<'a>) -> Result<Self> {
305 let magic = cursor.read_u32()?;
306
307 if magic != MAGIC {
308 return Err(Error::InvalidMagic { magic });
309 }
310
311 let minor_version = cursor.read_u16()?;
312 let major_version = cursor.read_u16()?;
313
314 if !(MIN_MAJOR_VERSION..=MAX_MAJOR_VERSION).contains(&major_version) {
315 return Err(Error::UnsupportedVersion {
316 major_version,
317 minor_version,
318 supported: MIN_MAJOR_VERSION..=MAX_MAJOR_VERSION,
319 });
320 }
321
322 let constant_pool = ConstantPool::try_read(cursor)?;
323
324 let access_flags = ClassAccessFlags::from_bits_truncate(cursor.read_u16()?);
325
326 let this_class = cursor.read_u16()?;
327 constant_pool.class_name_index(this_class)?;
328
329 let super_class = cursor.read_optional_index()?;
330 if let Some(super_class) = super_class {
331 constant_pool.class_name_index(super_class)?;
332 }
333
334 let interfaces = cursor.read_indices()?;
335 for &interface in &interfaces {
336 constant_pool.class_name_index(interface)?;
337 }
338
339 let fields = cursor.repeat_by_u16(|cursor| FieldInfo::try_read(&constant_pool, cursor))?;
340 let methods =
341 cursor.repeat_by_u16(|cursor| MethodInfo::try_read(&constant_pool, cursor))?;
342 let attributes = AttributeInfo::try_read_all(&constant_pool, cursor)?;
343
344 Ok(Self {
345 minor_version,
346 major_version,
347 constant_pool,
348 access_flags,
349 this_class,
350 super_class,
351 interfaces,
352 fields,
353 methods,
354 attributes,
355 })
356 }
357
358 pub fn name(&self) -> Result<Cow<'a, str>> {
360 let name_index = self.constant_pool.class_name_index(self.this_class)?;
361
362 self.constant_pool.str(name_index)
363 }
364
365 pub fn signature(&self, constant_pool: &ConstantPool<'a>) -> Result<Option<Cow<'a, str>>> {
367 let signature_index = match self
368 .attributes
369 .iter()
370 .find(|attr| matches!(attr, AttributeInfo::Signature { .. }))
371 {
372 Some(AttributeInfo::Signature { signature_index }) => *signature_index,
373 Some(_) => unreachable!(),
374 None => return Ok(None),
375 };
376
377 Ok(Some(constant_pool.str(signature_index)?))
378 }
379
380 pub fn inner_classes(&self) -> Result<Option<&Vec<InnerClass>>> {
382 for attribute in &self.attributes {
383 match attribute {
384 AttributeInfo::InnerClasses { classes } => return Ok(Some(classes)),
385 _ => continue,
386 }
387 }
388
389 Ok(None)
390 }
391}
392
393pub struct ConstantPool<'a> {
399 slots: Vec<Option<ConstantPoolInfo<'a>>>,
400}
401
402impl<'a> ConstantPool<'a> {
403 fn try_read(cursor: &mut Cursor<'a>) -> Result<Self> {
405 let count = cursor.read_u16()?;
406
407 if count < 1 {
408 return Err(Error::InvalidConstantPoolCount { count });
409 }
410
411 let count = count as usize;
412 let mut slots = Vec::with_capacity(count);
413 slots.push(None);
414
415 while slots.len() < count {
416 let index = slots.len() as CpIndex;
417 let entry = ConstantPoolInfo::try_read(cursor)?;
418 let width = entry.slot_width();
419
420 slots.push(Some(entry));
421
422 if width == 2 {
423 if slots.len() >= count {
424 return Err(Error::ConstantPoolOverflow { index });
425 }
426
427 slots.push(None);
428 }
429 }
430
431 Ok(Self { slots })
432 }
433
434 pub fn len(&self) -> usize {
436 self.slots.len()
437 }
438
439 pub fn is_empty(&self) -> bool {
441 self.slots.len() <= 1
442 }
443
444 pub fn iter(&self) -> impl Iterator<Item = (CpIndex, &ConstantPoolInfo<'a>)> {
446 self.slots
447 .iter()
448 .enumerate()
449 .filter_map(|(index, entry)| Some((index as CpIndex, entry.as_ref()?)))
450 }
451
452 pub fn get(&self, index: CpIndex) -> Result<&ConstantPoolInfo<'a>> {
454 match self.slots.get(index as usize) {
455 Some(Some(entry)) => Ok(entry),
456 Some(None) if index != 0 => Err(Error::ConstantPoolIndexUnusable { index }),
457 _ => Err(Error::ConstantPoolIndexOutOfBounds {
458 index,
459 count: self.slots.len(),
460 }),
461 }
462 }
463
464 pub fn class_name_index(&self, index: CpIndex) -> Result<CpIndex> {
466 match self.get(index)? {
467 ConstantPoolInfo::Class { name_index } => Ok(*name_index),
468 found => Err(unexpected_entry(index, "Class", found)),
469 }
470 }
471
472 pub fn utf8(&self, index: CpIndex) -> Result<Cesu8Bytes<'a>> {
474 match self.get(index)? {
475 ConstantPoolInfo::Utf8 { bytes } => Ok(*bytes),
476 found => Err(unexpected_entry(index, "Utf8", found)),
477 }
478 }
479
480 pub fn str(&self, index: CpIndex) -> Result<Cow<'a, str>> {
482 self.utf8(index)?.decode()
483 }
484
485 pub fn name_and_type(&self, index: CpIndex) -> Result<(CpIndex, CpIndex)> {
487 match self.get(index)? {
488 ConstantPoolInfo::NameAndType {
489 name_index,
490 descriptor_index,
491 } => Ok((*name_index, *descriptor_index)),
492 found => Err(unexpected_entry(index, "NameAndType", found)),
493 }
494 }
495
496 pub fn expect_constant_value(&self, index: CpIndex) -> Result<()> {
498 match self.get(index)? {
499 ConstantPoolInfo::Integer { .. }
500 | ConstantPoolInfo::Float { .. }
501 | ConstantPoolInfo::Long { .. }
502 | ConstantPoolInfo::Double { .. }
503 | ConstantPoolInfo::String { .. } => Ok(()),
504 found => Err(unexpected_entry(
505 index,
506 "Integer, Float, Long, Double or String",
507 found,
508 )),
509 }
510 }
511}
512
513fn unexpected_entry(index: CpIndex, expected: &'static str, found: &ConstantPoolInfo<'_>) -> Error {
515 Error::UnexpectedConstantPoolEntry {
516 index,
517 expected,
518 found: found.kind(),
519 }
520}
521
522impl Debug for ConstantPool<'_> {
523 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
524 f.debug_map().entries(self.iter()).finish()
525 }
526}
527
528#[derive(Debug)]
532pub enum ConstantPoolInfo<'a> {
533 Utf8 {
534 bytes: Cesu8Bytes<'a>,
535 },
536 Integer {
537 value: i32,
538 },
539 Float {
540 value: f32,
541 },
542 Long {
543 value: i64,
544 },
545 Double {
546 value: f64,
547 },
548 Class {
549 name_index: CpIndex,
550 },
551 String {
552 string_index: CpIndex,
553 },
554 FieldRef {
555 class_index: CpIndex,
556 name_and_type_index: CpIndex,
557 },
558 MethodRef {
559 class_index: CpIndex,
560 name_and_type_index: CpIndex,
561 },
562 InterfaceMethodRef {
563 class_index: CpIndex,
564 name_and_type_index: CpIndex,
565 },
566 NameAndType {
567 name_index: CpIndex,
568 descriptor_index: CpIndex,
569 },
570 MethodHandle {
571 reference_kind: ReferenceKind,
572 reference_index: CpIndex,
573 },
574 MethodType {
575 descriptor_index: CpIndex,
576 },
577 InvokeDynamic {
578 bootstrap_method_attr_index: u16,
579 name_and_type_index: CpIndex,
580 },
581}
582
583impl<'a> ConstantPoolInfo<'a> {
584 fn try_read(cursor: &mut Cursor<'a>) -> Result<Self> {
586 let info = match ConstantPoolTag::try_read(cursor)? {
587 ConstantPoolTag::Utf8 => {
588 let length = cursor.read_u16()? as usize;
589
590 Self::Utf8 {
591 bytes: Cesu8Bytes::from(cursor.read_bytes(length)?),
592 }
593 }
594 ConstantPoolTag::Integer => Self::Integer {
595 value: cursor.read_i32()?,
596 },
597 ConstantPoolTag::Float => Self::Float {
598 value: cursor.read_f32()?,
599 },
600 ConstantPoolTag::Long => Self::Long {
601 value: cursor.read_i64()?,
602 },
603 ConstantPoolTag::Double => Self::Double {
604 value: cursor.read_f64()?,
605 },
606 ConstantPoolTag::Class => Self::Class {
607 name_index: cursor.read_u16()?,
608 },
609 ConstantPoolTag::String => Self::String {
610 string_index: cursor.read_u16()?,
611 },
612 ConstantPoolTag::FieldRef => Self::FieldRef {
613 class_index: cursor.read_u16()?,
614 name_and_type_index: cursor.read_u16()?,
615 },
616 ConstantPoolTag::MethodRef => Self::MethodRef {
617 class_index: cursor.read_u16()?,
618 name_and_type_index: cursor.read_u16()?,
619 },
620 ConstantPoolTag::InterfaceMethodRef => Self::InterfaceMethodRef {
621 class_index: cursor.read_u16()?,
622 name_and_type_index: cursor.read_u16()?,
623 },
624 ConstantPoolTag::NameAndType => Self::NameAndType {
625 name_index: cursor.read_u16()?,
626 descriptor_index: cursor.read_u16()?,
627 },
628 ConstantPoolTag::MethodHandle => Self::MethodHandle {
629 reference_kind: ReferenceKind::try_read(cursor)?,
630 reference_index: cursor.read_u16()?,
631 },
632 ConstantPoolTag::MethodType => Self::MethodType {
633 descriptor_index: cursor.read_u16()?,
634 },
635 ConstantPoolTag::InvokeDynamic => Self::InvokeDynamic {
636 bootstrap_method_attr_index: cursor.read_u16()?,
637 name_and_type_index: cursor.read_u16()?,
638 },
639 };
640
641 Ok(info)
642 }
643
644 pub fn slot_width(&self) -> u16 {
646 match self {
647 Self::Long { .. } | Self::Double { .. } => 2,
648 _ => 1,
649 }
650 }
651
652 pub fn kind(&self) -> &'static str {
654 match self {
655 Self::Utf8 { .. } => "Utf8",
656 Self::Integer { .. } => "Integer",
657 Self::Float { .. } => "Float",
658 Self::Long { .. } => "Long",
659 Self::Double { .. } => "Double",
660 Self::Class { .. } => "Class",
661 Self::String { .. } => "String",
662 Self::FieldRef { .. } => "FieldRef",
663 Self::MethodRef { .. } => "MethodRef",
664 Self::InterfaceMethodRef { .. } => "InterfaceMethodRef",
665 Self::NameAndType { .. } => "NameAndType",
666 Self::MethodHandle { .. } => "MethodHandle",
667 Self::MethodType { .. } => "MethodType",
668 Self::InvokeDynamic { .. } => "InvokeDynamic",
669 }
670 }
671}
672
673#[derive(Debug, Clone, Copy, PartialEq, Eq)]
677#[repr(u8)]
678pub enum ConstantPoolTag {
679 Utf8 = 1,
680 Integer = 3,
681 Float = 4,
682 Long = 5,
683 Double = 6,
684 Class = 7,
685 String = 8,
686 FieldRef = 9,
687 MethodRef = 10,
688 InterfaceMethodRef = 11,
689 NameAndType = 12,
690 MethodHandle = 15,
691 MethodType = 16,
692 InvokeDynamic = 18,
693}
694
695impl TryFrom<u8> for ConstantPoolTag {
696 type Error = Error;
697
698 fn try_from(value: u8) -> Result<Self> {
699 let tag = match value {
700 1 => Self::Utf8,
701 3 => Self::Integer,
702 4 => Self::Float,
703 5 => Self::Long,
704 6 => Self::Double,
705 7 => Self::Class,
706 8 => Self::String,
707 9 => Self::FieldRef,
708 10 => Self::MethodRef,
709 11 => Self::InterfaceMethodRef,
710 12 => Self::NameAndType,
711 15 => Self::MethodHandle,
712 16 => Self::MethodType,
713 18 => Self::InvokeDynamic,
714 tag => return Err(Error::InvalidConstantPoolTag { tag }),
715 };
716
717 Ok(tag)
718 }
719}
720
721impl ConstantPoolTag {
722 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
724 Self::try_from(cursor.read_u8()?)
725 }
726}
727
728#[derive(Debug, Clone, Copy, PartialEq, Eq)]
732#[repr(u8)]
733pub enum ReferenceKind {
734 GetField = 1,
735 GetStatic = 2,
736 PutField = 3,
737 PutStatic = 4,
738 InvokeVirtual = 5,
739 InvokeStatic = 6,
740 InvokeSpecial = 7,
741 NewInvokeSpecial = 8,
742 InvokeInterface = 9,
743}
744
745impl TryFrom<u8> for ReferenceKind {
746 type Error = Error;
747
748 fn try_from(value: u8) -> Result<Self> {
749 let kind = match value {
750 1 => Self::GetField,
751 2 => Self::GetStatic,
752 3 => Self::PutField,
753 4 => Self::PutStatic,
754 5 => Self::InvokeVirtual,
755 6 => Self::InvokeStatic,
756 7 => Self::InvokeSpecial,
757 8 => Self::NewInvokeSpecial,
758 9 => Self::InvokeInterface,
759 kind => return Err(Error::InvalidReferenceKind { kind }),
760 };
761
762 Ok(kind)
763 }
764}
765
766impl ReferenceKind {
767 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
769 Self::try_from(cursor.read_u8()?)
770 }
771}
772
773bitflags::bitflags! {
774 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
778 pub struct ClassAccessFlags: u16 {
779 const PUBLIC = 0x0001;
780 const FINAL = 0x0010;
781 const SUPER = 0x0020;
782 const INTERFACE = 0x0200;
783 const ABSTRACT = 0x0400;
784 const SYNTHETIC = 0x1000;
785 const ANNOTATION = 0x2000;
786 const ENUM = 0x4000;
787 }
788}
789
790mod field {
791 use std::borrow::Cow;
792
793 use crate::{
794 AttributeInfo, ConstantPool, CpIndex,
795 cursor::{Cursor, ReadBytes},
796 error::Result,
797 };
798
799 #[derive(Debug)]
803 pub struct FieldInfo<'a> {
804 pub access_flags: FieldAccessFlags,
805 pub name_index: CpIndex,
806 pub descriptor_index: CpIndex,
807 pub attributes: Vec<AttributeInfo<'a>>,
808 }
809
810 impl<'a> FieldInfo<'a> {
811 pub fn try_read(constant_pool: &ConstantPool<'a>, cursor: &mut Cursor<'a>) -> Result<Self> {
813 let access_flags = FieldAccessFlags::from_bits_truncate(cursor.read_u16()?);
814
815 let name_index = cursor.read_u16()?;
816 constant_pool.utf8(name_index)?;
817
818 let descriptor_index = cursor.read_u16()?;
819 constant_pool.utf8(descriptor_index)?;
820
821 Ok(Self {
822 access_flags,
823 name_index,
824 descriptor_index,
825 attributes: AttributeInfo::try_read_all(constant_pool, cursor)?,
826 })
827 }
828
829 pub fn signature(&self, constant_pool: &ConstantPool<'a>) -> Result<Option<Cow<'a, str>>> {
831 let signature_index = match self
832 .attributes
833 .iter()
834 .find(|attr| matches!(attr, AttributeInfo::Signature { .. }))
835 {
836 Some(AttributeInfo::Signature { signature_index }) => *signature_index,
837 Some(_) => unreachable!(),
838 None => return Ok(None),
839 };
840
841 Ok(Some(constant_pool.str(signature_index)?))
842 }
843
844 pub fn name(&self, constant_pool: &ConstantPool<'a>) -> Result<Cow<'a, str>> {
846 constant_pool.str(self.name_index)
847 }
848
849 pub fn descriptor(&self, constant_pool: &ConstantPool<'a>) -> Result<Cow<'a, str>> {
851 constant_pool.str(self.descriptor_index)
852 }
853 }
854
855 bitflags::bitflags! {
856 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
860 pub struct FieldAccessFlags: u16 {
861 const PUBLIC = 0x0001;
862 const PRIVATE = 0x0002;
863 const PROTECTED = 0x0004;
864 const STATIC = 0x0008;
865 const FINAL = 0x0010;
866 const VOLATILE = 0x0040;
867 const TRANSIENT = 0x0080;
868 const SYNTHETIC = 0x1000;
869 const ENUM = 0x4000;
870 }
871 }
872}
873
874mod method {
875 use std::borrow::Cow;
876
877 use crate::{
878 AttributeInfo, ConstantPool, CpIndex,
879 cursor::{Cursor, ReadBytes},
880 error::Result,
881 };
882
883 #[derive(Debug)]
887 pub struct MethodInfo<'a> {
888 pub access_flags: MethodAccessFlags,
889 pub name_index: CpIndex,
890 pub descriptor_index: CpIndex,
891 pub attributes: Vec<AttributeInfo<'a>>,
892 }
893
894 impl<'a> MethodInfo<'a> {
895 pub fn try_read(constant_pool: &ConstantPool<'a>, cursor: &mut Cursor<'a>) -> Result<Self> {
897 let access_flags = MethodAccessFlags::from_bits_truncate(cursor.read_u16()?);
898
899 let name_index = cursor.read_u16()?;
900 constant_pool.utf8(name_index)?;
901
902 let descriptor_index = cursor.read_u16()?;
903 constant_pool.utf8(descriptor_index)?;
904
905 Ok(Self {
906 access_flags,
907 name_index,
908 descriptor_index,
909 attributes: AttributeInfo::try_read_all(constant_pool, cursor)?,
910 })
911 }
912
913 pub fn signature(&self, constant_pool: &ConstantPool<'a>) -> Result<Option<Cow<'a, str>>> {
915 let signature_index = match self
916 .attributes
917 .iter()
918 .find(|attr| matches!(attr, AttributeInfo::Signature { .. }))
919 {
920 Some(AttributeInfo::Signature { signature_index }) => *signature_index,
921 Some(_) => unreachable!(),
922 None => return Ok(None),
923 };
924
925 Ok(Some(constant_pool.str(signature_index)?))
926 }
927
928 pub fn name(&self, constant_pool: &ConstantPool<'a>) -> Result<Cow<'a, str>> {
930 constant_pool.str(self.name_index)
931 }
932
933 pub fn descriptor(&self, constant_pool: &ConstantPool<'a>) -> Result<Cow<'a, str>> {
935 constant_pool.str(self.descriptor_index)
936 }
937 }
938
939 bitflags::bitflags! {
940 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
944 pub struct MethodAccessFlags: u16 {
945 const PUBLIC = 0x0001;
946 const PRIVATE = 0x0002;
947 const PROTECTED = 0x0004;
948 const STATIC = 0x0008;
949 const FINAL = 0x0010;
950 const SYNCHRONIZED = 0x0020;
951 const BRIDGE = 0x0040;
952 const VARARGS = 0x0080;
953 const NATIVE = 0x0100;
954 const ABSTRACT = 0x0400;
955 const STRICT = 0x0800;
956 const SYNTHETIC = 0x1000;
957 }
958 }
959}
960
961mod attribute {
962 use crate::{
963 ConstantPool, CpIndex,
964 cursor::{Cursor, ReadBytes},
965 error::{Error, Result},
966 };
967
968 #[derive(Debug)]
974 pub enum AttributeInfo<'a> {
975 SourceFile {
976 sourcefile_index: CpIndex,
977 },
978 InnerClasses {
979 classes: Vec<InnerClass>,
980 },
981 EnclosingMethod {
982 class_index: CpIndex,
983 method_index: Option<CpIndex>,
984 },
985 SourceDebugExtension {
986 debug_extension: &'a [u8],
987 },
988 BootstrapMethods {
989 bootstrap_methods: Vec<BootstrapMethod>,
990 },
991 ConstantValue {
992 constantvalue_index: CpIndex,
993 },
994 Code {
995 max_stack: u16,
996 max_locals: u16,
997 code: &'a [u8],
998 exception_table: Vec<ExceptionHandler>,
999 attributes: Vec<AttributeInfo<'a>>,
1000 },
1001 Exceptions {
1002 exception_index_table: Vec<CpIndex>,
1003 },
1004 RuntimeVisibleParameterAnnotations {
1005 parameter_annotations: Vec<Vec<Annotation>>,
1006 },
1007 RuntimeInvisibleParameterAnnotations {
1008 parameter_annotations: Vec<Vec<Annotation>>,
1009 },
1010 AnnotationDefault {
1011 default_value: ElementValue,
1012 },
1013 MethodParameters {
1014 parameters: Vec<MethodParameter>,
1015 },
1016 Synthetic,
1017 Deprecated,
1018 Signature {
1019 signature_index: CpIndex,
1020 },
1021 RuntimeVisibleAnnotations {
1022 annotations: Vec<Annotation>,
1023 },
1024 RuntimeInvisibleAnnotations {
1025 annotations: Vec<Annotation>,
1026 },
1027 LineNumberTable {
1028 line_number_table: Vec<LineNumber>,
1029 },
1030 LocalVariableTable {
1031 local_variable_table: Vec<LocalVariable>,
1032 },
1033 LocalVariableTypeTable {
1034 local_variable_type_table: Vec<LocalVariableType>,
1035 },
1036 StackMapTable {
1037 entries: Vec<StackMapFrame>,
1038 },
1039 RuntimeVisibleTypeAnnotations {
1040 annotations: Vec<TypeAnnotation>,
1041 },
1042 RuntimeInvisibleTypeAnnotations {
1043 annotations: Vec<TypeAnnotation>,
1044 },
1045 Unknown {
1046 name: String,
1047 info: &'a [u8],
1048 },
1049 }
1050
1051 impl<'a> AttributeInfo<'a> {
1052 pub fn try_read_all(
1054 constant_pool: &ConstantPool<'a>,
1055 cursor: &mut Cursor<'a>,
1056 ) -> Result<Vec<Self>> {
1057 cursor.repeat_by_u16(|cursor| Self::try_read(constant_pool, cursor))
1058 }
1059
1060 pub fn try_read(constant_pool: &ConstantPool<'a>, cursor: &mut Cursor<'a>) -> Result<Self> {
1062 let attribute_name_index = cursor.read_u16()?;
1063 let name = constant_pool.utf8(attribute_name_index)?;
1064
1065 let attribute_length = cursor.read_u32()? as usize;
1066
1067 let mut info = Cursor::new(cursor.read_bytes(attribute_length)?);
1068
1069 let attribute = Self::try_read_body(constant_pool, name.as_bytes(), &mut info)?;
1070
1071 if !info.is_empty() {
1072 return Err(Error::AttributeLengthMismatch {
1073 name: name.decode_owned()?,
1074 expected: attribute_length,
1075 consumed: attribute_length - info.len(),
1076 });
1077 }
1078
1079 Ok(attribute)
1080 }
1081
1082 fn try_read_body(
1084 constant_pool: &ConstantPool<'a>,
1085 name: &[u8],
1086 cursor: &mut Cursor<'a>,
1087 ) -> Result<Self> {
1088 let attribute = match name {
1089 b"SourceFile" => {
1090 let sourcefile_index = cursor.read_u16()?;
1091 constant_pool.utf8(sourcefile_index)?;
1092
1093 Self::SourceFile { sourcefile_index }
1094 }
1095 b"InnerClasses" => Self::InnerClasses {
1096 classes: cursor
1097 .repeat_by_u16(|cursor| InnerClass::try_read(constant_pool, cursor))?,
1098 },
1099 b"EnclosingMethod" => {
1100 let class_index = cursor.read_u16()?;
1101 constant_pool.class_name_index(class_index)?;
1102
1103 let method_index = cursor.read_optional_index()?;
1104 if let Some(method_index) = method_index {
1105 constant_pool.name_and_type(method_index)?;
1106 }
1107
1108 Self::EnclosingMethod {
1109 class_index,
1110 method_index,
1111 }
1112 }
1113 b"SourceDebugExtension" => Self::SourceDebugExtension {
1114 debug_extension: cursor.read_rest(),
1115 },
1116 b"BootstrapMethods" => Self::BootstrapMethods {
1117 bootstrap_methods: cursor.repeat_by_u16(BootstrapMethod::try_read)?,
1118 },
1119 b"ConstantValue" => {
1120 let constantvalue_index = cursor.read_u16()?;
1121 constant_pool.expect_constant_value(constantvalue_index)?;
1122
1123 Self::ConstantValue {
1124 constantvalue_index,
1125 }
1126 }
1127 b"Code" => {
1128 let max_stack = cursor.read_u16()?;
1129 let max_locals = cursor.read_u16()?;
1130
1131 let code_length = cursor.read_u32()? as usize;
1132 let code = cursor.read_bytes(code_length)?;
1133
1134 let exception_table = cursor.repeat_by_u16(|cursor| {
1135 ExceptionHandler::try_read(constant_pool, cursor)
1136 })?;
1137
1138 Self::Code {
1139 max_stack,
1140 max_locals,
1141 code,
1142 exception_table,
1143 attributes: Self::try_read_all(constant_pool, cursor)?,
1144 }
1145 }
1146 b"Exceptions" => {
1147 let exception_index_table = cursor.read_indices()?;
1148 for &index in &exception_index_table {
1149 constant_pool.class_name_index(index)?;
1150 }
1151
1152 Self::Exceptions {
1153 exception_index_table,
1154 }
1155 }
1156 b"RuntimeVisibleParameterAnnotations" => Self::RuntimeVisibleParameterAnnotations {
1157 parameter_annotations: cursor
1158 .repeat_by_u8(|cursor| cursor.repeat_by_u16(Annotation::try_read))?,
1159 },
1160 b"RuntimeInvisibleParameterAnnotations" => {
1161 Self::RuntimeInvisibleParameterAnnotations {
1162 parameter_annotations: cursor
1163 .repeat_by_u8(|cursor| cursor.repeat_by_u16(Annotation::try_read))?,
1164 }
1165 }
1166 b"AnnotationDefault" => Self::AnnotationDefault {
1167 default_value: ElementValue::try_read(cursor)?,
1168 },
1169 b"MethodParameters" => Self::MethodParameters {
1170 parameters: cursor
1171 .repeat_by_u8(|cursor| MethodParameter::try_read(constant_pool, cursor))?,
1172 },
1173 b"Synthetic" => Self::Synthetic,
1174 b"Deprecated" => Self::Deprecated,
1175 b"Signature" => {
1176 let signature_index = cursor.read_u16()?;
1177 constant_pool.utf8(signature_index)?;
1178
1179 Self::Signature { signature_index }
1180 }
1181 b"RuntimeVisibleAnnotations" => Self::RuntimeVisibleAnnotations {
1182 annotations: cursor.repeat_by_u16(Annotation::try_read)?,
1183 },
1184 b"RuntimeInvisibleAnnotations" => Self::RuntimeInvisibleAnnotations {
1185 annotations: cursor.repeat_by_u16(Annotation::try_read)?,
1186 },
1187 b"LineNumberTable" => Self::LineNumberTable {
1188 line_number_table: cursor.repeat_by_u16(LineNumber::try_read)?,
1189 },
1190 b"LocalVariableTable" => Self::LocalVariableTable {
1191 local_variable_table: cursor
1192 .repeat_by_u16(|cursor| LocalVariable::try_read(constant_pool, cursor))?,
1193 },
1194 b"LocalVariableTypeTable" => Self::LocalVariableTypeTable {
1195 local_variable_type_table: cursor.repeat_by_u16(|cursor| {
1196 LocalVariableType::try_read(constant_pool, cursor)
1197 })?,
1198 },
1199 b"StackMapTable" => Self::StackMapTable {
1200 entries: cursor.repeat_by_u16(StackMapFrame::try_read)?,
1201 },
1202 b"RuntimeVisibleTypeAnnotations" => Self::RuntimeVisibleTypeAnnotations {
1203 annotations: cursor.repeat_by_u16(TypeAnnotation::try_read)?,
1204 },
1205 b"RuntimeInvisibleTypeAnnotations" => Self::RuntimeInvisibleTypeAnnotations {
1206 annotations: cursor.repeat_by_u16(TypeAnnotation::try_read)?,
1207 },
1208 _ => Self::Unknown {
1209 name: String::from_utf8_lossy(name).into_owned(),
1210 info: cursor.read_rest(),
1211 },
1212 };
1213
1214 Ok(attribute)
1215 }
1216 }
1217
1218 #[derive(Debug)]
1222 pub struct ExceptionHandler {
1223 pub start_pc: u16,
1224 pub end_pc: u16,
1225 pub handler_pc: u16,
1226 pub catch_type: Option<CpIndex>,
1227 }
1228
1229 impl ExceptionHandler {
1230 pub fn try_read(constant_pool: &ConstantPool<'_>, cursor: &mut Cursor<'_>) -> Result<Self> {
1232 let start_pc = cursor.read_u16()?;
1233 let end_pc = cursor.read_u16()?;
1234 let handler_pc = cursor.read_u16()?;
1235
1236 let catch_type = cursor.read_optional_index()?;
1237 if let Some(catch_type) = catch_type {
1238 constant_pool.class_name_index(catch_type)?;
1239 }
1240
1241 Ok(Self {
1242 start_pc,
1243 end_pc,
1244 handler_pc,
1245 catch_type,
1246 })
1247 }
1248 }
1249
1250 #[derive(Debug)]
1254 pub enum StackMapFrame {
1255 Same {
1256 offset_delta: u16,
1257 },
1258 SameLocals1StackItem {
1259 offset_delta: u16,
1260 stack: VerificationTypeInfo,
1261 },
1262 SameLocals1StackItemExtended {
1263 offset_delta: u16,
1264 stack: VerificationTypeInfo,
1265 },
1266 Chop {
1267 offset_delta: u16,
1268 absent_locals: u8,
1269 },
1270 SameExtended {
1271 offset_delta: u16,
1272 },
1273 Append {
1274 offset_delta: u16,
1275 locals: Vec<VerificationTypeInfo>,
1276 },
1277 Full {
1278 offset_delta: u16,
1279 locals: Vec<VerificationTypeInfo>,
1280 stack: Vec<VerificationTypeInfo>,
1281 },
1282 }
1283
1284 impl StackMapFrame {
1285 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1287 let tag = cursor.read_u8()?;
1288
1289 let frame = match tag {
1290 0..=63 => Self::Same {
1291 offset_delta: tag as u16,
1292 },
1293 64..=127 => Self::SameLocals1StackItem {
1294 offset_delta: (tag - 64) as u16,
1295 stack: VerificationTypeInfo::try_read(cursor)?,
1296 },
1297 247 => Self::SameLocals1StackItemExtended {
1298 offset_delta: cursor.read_u16()?,
1299 stack: VerificationTypeInfo::try_read(cursor)?,
1300 },
1301 248..=250 => Self::Chop {
1302 offset_delta: cursor.read_u16()?,
1303 absent_locals: 251 - tag,
1304 },
1305 251 => Self::SameExtended {
1306 offset_delta: cursor.read_u16()?,
1307 },
1308 252..=254 => {
1309 let offset_delta = cursor.read_u16()?;
1310 let locals = (0..tag - 251)
1311 .map(|_| VerificationTypeInfo::try_read(cursor))
1312 .collect::<Result<Vec<_>>>()?;
1313
1314 Self::Append {
1315 offset_delta,
1316 locals,
1317 }
1318 }
1319 255 => Self::Full {
1320 offset_delta: cursor.read_u16()?,
1321 locals: cursor.repeat_by_u16(VerificationTypeInfo::try_read)?,
1322 stack: cursor.repeat_by_u16(VerificationTypeInfo::try_read)?,
1323 },
1324 tag => return Err(Error::InvalidStackMapFrameTag { tag }),
1325 };
1326
1327 Ok(frame)
1328 }
1329 }
1330
1331 #[derive(Debug)]
1335 pub enum VerificationTypeInfo {
1336 Top,
1337 Integer,
1338 Float,
1339 Double,
1340 Long,
1341 Null,
1342 UninitializedThis,
1343 Object { cpool_index: CpIndex },
1344 Uninitialized { offset: u16 },
1345 }
1346
1347 impl VerificationTypeInfo {
1348 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1350 let info = match VerificationTypeTag::try_read(cursor)? {
1351 VerificationTypeTag::Top => Self::Top,
1352 VerificationTypeTag::Integer => Self::Integer,
1353 VerificationTypeTag::Float => Self::Float,
1354 VerificationTypeTag::Double => Self::Double,
1355 VerificationTypeTag::Long => Self::Long,
1356 VerificationTypeTag::Null => Self::Null,
1357 VerificationTypeTag::UninitializedThis => Self::UninitializedThis,
1358 VerificationTypeTag::Object => Self::Object {
1359 cpool_index: cursor.read_u16()?,
1360 },
1361 VerificationTypeTag::Uninitialized => Self::Uninitialized {
1362 offset: cursor.read_u16()?,
1363 },
1364 };
1365
1366 Ok(info)
1367 }
1368 }
1369
1370 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1374 #[repr(u8)]
1375 pub enum VerificationTypeTag {
1376 Top = 0,
1377 Integer = 1,
1378 Float = 2,
1379 Double = 3,
1380 Long = 4,
1381 Null = 5,
1382 UninitializedThis = 6,
1383 Object = 7,
1384 Uninitialized = 8,
1385 }
1386
1387 impl TryFrom<u8> for VerificationTypeTag {
1388 type Error = Error;
1389
1390 fn try_from(value: u8) -> Result<Self> {
1391 let tag = match value {
1392 0 => Self::Top,
1393 1 => Self::Integer,
1394 2 => Self::Float,
1395 3 => Self::Double,
1396 4 => Self::Long,
1397 5 => Self::Null,
1398 6 => Self::UninitializedThis,
1399 7 => Self::Object,
1400 8 => Self::Uninitialized,
1401 tag => return Err(Error::InvalidVerificationTypeTag { tag }),
1402 };
1403
1404 Ok(tag)
1405 }
1406 }
1407
1408 impl VerificationTypeTag {
1409 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1411 Self::try_from(cursor.read_u8()?)
1412 }
1413 }
1414
1415 #[derive(Debug)]
1419 pub struct InnerClass {
1420 pub inner_class_info_index: CpIndex,
1421 pub outer_class_info_index: Option<CpIndex>,
1422 pub inner_name_index: Option<CpIndex>,
1423 pub inner_class_access_flags: InnerClassAccessFlags,
1424 }
1425
1426 impl InnerClass {
1427 pub fn try_read(constant_pool: &ConstantPool<'_>, cursor: &mut Cursor<'_>) -> Result<Self> {
1429 let inner_class_info_index = cursor.read_u16()?;
1430 constant_pool.class_name_index(inner_class_info_index)?;
1431
1432 let outer_class_info_index = cursor.read_optional_index()?;
1433 if let Some(index) = outer_class_info_index {
1434 constant_pool.class_name_index(index)?;
1435 }
1436
1437 let inner_name_index = cursor.read_optional_index()?;
1438 if let Some(index) = inner_name_index {
1439 constant_pool.utf8(index)?;
1440 }
1441
1442 Ok(Self {
1443 inner_class_info_index,
1444 outer_class_info_index,
1445 inner_name_index,
1446 inner_class_access_flags: InnerClassAccessFlags::from_bits_truncate(
1447 cursor.read_u16()?,
1448 ),
1449 })
1450 }
1451 }
1452
1453 bitflags::bitflags! {
1454 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1458 pub struct InnerClassAccessFlags: u16 {
1459 const PUBLIC = 0x0001;
1460 const PRIVATE = 0x0002;
1461 const PROTECTED = 0x0004;
1462 const STATIC = 0x0008;
1463 const FINAL = 0x0010;
1464 const INTERFACE = 0x0200;
1465 const ABSTRACT = 0x0400;
1466 const SYNTHETIC = 0x1000;
1467 const ANNOTATION = 0x2000;
1468 const ENUM = 0x4000;
1469 }
1470 }
1471
1472 #[derive(Debug)]
1476 pub struct LineNumber {
1477 pub start_pc: u16,
1478 pub line_number: u16,
1479 }
1480
1481 impl LineNumber {
1482 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1484 Ok(Self {
1485 start_pc: cursor.read_u16()?,
1486 line_number: cursor.read_u16()?,
1487 })
1488 }
1489 }
1490
1491 #[derive(Debug)]
1495 pub struct LocalVariable {
1496 pub start_pc: u16,
1497 pub length: u16,
1498 pub name_index: CpIndex,
1499 pub descriptor_index: CpIndex,
1500 pub index: u16,
1501 }
1502
1503 impl LocalVariable {
1504 pub fn try_read(constant_pool: &ConstantPool<'_>, cursor: &mut Cursor<'_>) -> Result<Self> {
1506 let start_pc = cursor.read_u16()?;
1507 let length = cursor.read_u16()?;
1508
1509 let name_index = cursor.read_u16()?;
1510 constant_pool.utf8(name_index)?;
1511
1512 let descriptor_index = cursor.read_u16()?;
1513 constant_pool.utf8(descriptor_index)?;
1514
1515 Ok(Self {
1516 start_pc,
1517 length,
1518 name_index,
1519 descriptor_index,
1520 index: cursor.read_u16()?,
1521 })
1522 }
1523 }
1524
1525 #[derive(Debug)]
1529 pub struct LocalVariableType {
1530 pub start_pc: u16,
1531 pub length: u16,
1532 pub name_index: CpIndex,
1533 pub signature_index: CpIndex,
1534 pub index: u16,
1535 }
1536
1537 impl LocalVariableType {
1538 pub fn try_read(constant_pool: &ConstantPool<'_>, cursor: &mut Cursor<'_>) -> Result<Self> {
1540 let start_pc = cursor.read_u16()?;
1541 let length = cursor.read_u16()?;
1542
1543 let name_index = cursor.read_u16()?;
1544 constant_pool.utf8(name_index)?;
1545
1546 let signature_index = cursor.read_u16()?;
1547 constant_pool.utf8(signature_index)?;
1548
1549 Ok(Self {
1550 start_pc,
1551 length,
1552 name_index,
1553 signature_index,
1554 index: cursor.read_u16()?,
1555 })
1556 }
1557 }
1558
1559 #[derive(Debug)]
1563 pub struct Annotation {
1564 pub type_index: CpIndex,
1565 pub element_value_pairs: Vec<ElementValuePair>,
1566 }
1567
1568 impl Annotation {
1569 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1571 Ok(Self {
1572 type_index: cursor.read_u16()?,
1573 element_value_pairs: cursor.repeat_by_u16(ElementValuePair::try_read)?,
1574 })
1575 }
1576 }
1577
1578 #[derive(Debug)]
1582 pub struct ElementValuePair {
1583 pub element_name_index: CpIndex,
1584 pub value: ElementValue,
1585 }
1586
1587 impl ElementValuePair {
1588 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1590 Ok(Self {
1591 element_name_index: cursor.read_u16()?,
1592 value: ElementValue::try_read(cursor)?,
1593 })
1594 }
1595 }
1596
1597 #[derive(Debug)]
1601 pub enum ElementValue {
1602 Const {
1603 tag: u8,
1604 const_value_index: CpIndex,
1605 },
1606 Enum {
1607 type_name_index: CpIndex,
1608 const_name_index: CpIndex,
1609 },
1610 Class {
1611 class_info_index: CpIndex,
1612 },
1613 Annotation {
1614 annotation: Annotation,
1615 },
1616 Array {
1617 values: Vec<ElementValue>,
1618 },
1619 }
1620
1621 impl ElementValue {
1622 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1624 let tag = cursor.read_u8()?;
1625
1626 let value = match tag {
1627 b'B' | b'C' | b'D' | b'F' | b'I' | b'J' | b'S' | b'Z' | b's' => Self::Const {
1628 tag,
1629 const_value_index: cursor.read_u16()?,
1630 },
1631 b'e' => Self::Enum {
1632 type_name_index: cursor.read_u16()?,
1633 const_name_index: cursor.read_u16()?,
1634 },
1635 b'c' => Self::Class {
1636 class_info_index: cursor.read_u16()?,
1637 },
1638 b'@' => Self::Annotation {
1639 annotation: Annotation::try_read(cursor)?,
1640 },
1641 b'[' => Self::Array {
1642 values: cursor.repeat_by_u16(Self::try_read)?,
1643 },
1644 tag => return Err(Error::InvalidElementValueTag { tag }),
1645 };
1646
1647 Ok(value)
1648 }
1649 }
1650
1651 #[derive(Debug)]
1655 pub struct TypeAnnotation {
1656 pub target: TypeAnnotationTarget,
1657 pub target_path: TypePath,
1658 pub type_index: CpIndex,
1659 pub element_value_pairs: Vec<ElementValuePair>,
1660 }
1661
1662 impl TypeAnnotation {
1663 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1665 Ok(Self {
1666 target: TypeAnnotationTarget::try_read(cursor)?,
1667 target_path: TypePath::try_read(cursor)?,
1668 type_index: cursor.read_u16()?,
1669 element_value_pairs: cursor.repeat_by_u16(ElementValuePair::try_read)?,
1670 })
1671 }
1672 }
1673
1674 #[derive(Debug)]
1678 pub enum TypeAnnotationTarget {
1679 TypeParameter {
1680 type_parameter_index: u8,
1681 },
1682 SuperType {
1683 supertype_index: u16,
1684 },
1685 TypeParameterBound {
1686 type_parameter_index: u8,
1687 bound_index: u8,
1688 },
1689 Empty,
1690 FormalParameter {
1691 formal_parameter_index: u8,
1692 },
1693 Throws {
1694 throws_type_index: u16,
1695 },
1696 LocalVar {
1697 table: Vec<LocalVarTarget>,
1698 },
1699 Catch {
1700 exception_table_index: u16,
1701 },
1702 Offset {
1703 offset: u16,
1704 },
1705 TypeArgument {
1706 offset: u16,
1707 type_argument_index: u8,
1708 },
1709 }
1710
1711 impl TypeAnnotationTarget {
1712 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1714 let target = match cursor.read_u8()? {
1715 0x00 | 0x01 => Self::TypeParameter {
1716 type_parameter_index: cursor.read_u8()?,
1717 },
1718 0x10 => Self::SuperType {
1719 supertype_index: cursor.read_u16()?,
1720 },
1721 0x11 | 0x12 => Self::TypeParameterBound {
1722 type_parameter_index: cursor.read_u8()?,
1723 bound_index: cursor.read_u8()?,
1724 },
1725 0x13..=0x15 => Self::Empty,
1726 0x16 => Self::FormalParameter {
1727 formal_parameter_index: cursor.read_u8()?,
1728 },
1729 0x17 => Self::Throws {
1730 throws_type_index: cursor.read_u16()?,
1731 },
1732 0x40 | 0x41 => Self::LocalVar {
1733 table: cursor.repeat_by_u16(LocalVarTarget::try_read)?,
1734 },
1735 0x42 => Self::Catch {
1736 exception_table_index: cursor.read_u16()?,
1737 },
1738 0x43..=0x46 => Self::Offset {
1739 offset: cursor.read_u16()?,
1740 },
1741 0x47..=0x4B => Self::TypeArgument {
1742 offset: cursor.read_u16()?,
1743 type_argument_index: cursor.read_u8()?,
1744 },
1745 target_type => return Err(Error::InvalidTypeAnnotationTarget { target_type }),
1746 };
1747
1748 Ok(target)
1749 }
1750 }
1751
1752 #[derive(Debug)]
1756 pub struct LocalVarTarget {
1757 pub start_pc: u16,
1758 pub length: u16,
1759 pub index: u16,
1760 }
1761
1762 impl LocalVarTarget {
1763 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1765 Ok(Self {
1766 start_pc: cursor.read_u16()?,
1767 length: cursor.read_u16()?,
1768 index: cursor.read_u16()?,
1769 })
1770 }
1771 }
1772
1773 #[derive(Debug)]
1777 pub struct TypePath {
1778 pub path: Vec<TypePathEntry>,
1779 }
1780
1781 impl TypePath {
1782 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1784 Ok(Self {
1785 path: cursor.repeat_by_u8(TypePathEntry::try_read)?,
1786 })
1787 }
1788 }
1789
1790 #[derive(Debug)]
1794 pub struct TypePathEntry {
1795 pub type_path_kind: u8,
1796 pub type_argument_index: u8,
1797 }
1798
1799 impl TypePathEntry {
1800 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1802 Ok(Self {
1803 type_path_kind: cursor.read_u8()?,
1804 type_argument_index: cursor.read_u8()?,
1805 })
1806 }
1807 }
1808
1809 #[derive(Debug)]
1813 pub struct BootstrapMethod {
1814 pub bootstrap_method_ref: CpIndex,
1815 pub bootstrap_arguments: Vec<CpIndex>,
1816 }
1817
1818 impl BootstrapMethod {
1819 pub fn try_read(cursor: &mut Cursor<'_>) -> Result<Self> {
1821 Ok(Self {
1822 bootstrap_method_ref: cursor.read_u16()?,
1823 bootstrap_arguments: cursor.read_indices()?,
1824 })
1825 }
1826 }
1827
1828 #[derive(Debug)]
1832 pub struct MethodParameter {
1833 pub name_index: Option<CpIndex>,
1834 pub access_flags: MethodParameterAccessFlags,
1835 }
1836
1837 impl MethodParameter {
1838 pub fn try_read(constant_pool: &ConstantPool<'_>, cursor: &mut Cursor<'_>) -> Result<Self> {
1840 let name_index = cursor.read_optional_index()?;
1841 if let Some(name_index) = name_index {
1842 constant_pool.utf8(name_index)?;
1843 }
1844
1845 Ok(Self {
1846 name_index,
1847 access_flags: MethodParameterAccessFlags::from_bits_truncate(cursor.read_u16()?),
1848 })
1849 }
1850 }
1851
1852 bitflags::bitflags! {
1853 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1857 pub struct MethodParameterAccessFlags: u16 {
1858 const FINAL = 0x0010;
1859 const SYNTHETIC = 0x1000;
1860 const MANDATED = 0x8000;
1861 }
1862 }
1863}