Skip to main content

java_serialization/
types.rs

1use crate::constants;
2
3/// Parsed Java serialization stream.
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[derive(Debug, Clone)]
6pub struct SerializationStream {
7    pub version: u16,
8    pub contents: Vec<ContentElement>,
9}
10
11/// Top-level content elements in a serialization stream.
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13#[derive(Debug, Clone)]
14pub enum ContentElement {
15    Object(StreamObject),
16    BlockData(BlockData),
17}
18
19/// An object in the serialization stream.
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[derive(Debug, Clone)]
22pub enum StreamObject {
23    NewObject(NewObject),
24    NewClass(NewClass),
25    NewArray(NewArray),
26    NewString(StreamString),
27    NewEnum(NewEnum),
28    NewClassDesc(ClassDesc),
29    PrevObject { handle: u32 },
30    NullReference,
31    Exception,
32    Reset,
33}
34
35/// TC_OBJECT: new object.
36#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
37#[derive(Debug, Clone)]
38pub struct NewObject {
39    pub class_desc: ClassDescRef,
40    pub handle: u32,
41    pub class_data: Vec<ClassData>,
42}
43
44/// TC_CLASS: reference to a class.
45#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
46#[derive(Debug, Clone)]
47pub struct NewClass {
48    pub class_desc: ClassDescRef,
49    pub handle: u32,
50}
51
52/// TC_ARRAY: new array.
53#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
54#[derive(Debug, Clone)]
55pub struct NewArray {
56    pub class_desc: ClassDescRef,
57    pub handle: u32,
58    pub size: u32,
59    pub values: ArrayValues,
60}
61
62/// Array values based on component type.
63#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
64#[derive(Debug, Clone)]
65pub enum ArrayValues {
66    Byte(Vec<i8>),
67    Char(Vec<u16>),
68    Double(Vec<f64>),
69    Float(Vec<f32>),
70    Int(Vec<i32>),
71    Long(Vec<i64>),
72    Short(Vec<i16>),
73    Boolean(Vec<u8>),
74    Object(Vec<Option<StreamObject>>),
75}
76
77/// TC_STRING / TC_LONGSTRING.
78#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
79#[derive(Debug, Clone)]
80pub struct StreamString {
81    pub value: String,
82    pub handle: u32,
83    pub is_long: bool,
84}
85
86/// TC_ENUM: new enum constant.
87#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
88#[derive(Debug, Clone)]
89pub struct NewEnum {
90    pub class_desc: ClassDescRef,
91    pub handle: u32,
92    pub constant_name: StreamString,
93}
94
95/// Reference to a class descriptor - either inline or a back-reference.
96#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
97#[derive(Debug, Clone)]
98pub enum ClassDescRef {
99    /// Inline class descriptor.
100    Inline(Box<ClassDesc>),
101    /// Null reference (no superclass).
102    Null,
103    /// Back-reference to a previously seen class descriptor by handle.
104    Reference { handle: u32 },
105}
106
107/// Class descriptor: either a normal class or a proxy class.
108#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
109#[derive(Debug, Clone)]
110pub enum ClassDesc {
111    Normal(Box<NormalClassDesc>),
112    Proxy(ProxyClassDesc),
113}
114
115/// TC_CLASSDESC: normal class descriptor.
116#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
117#[derive(Debug, Clone)]
118pub struct NormalClassDesc {
119    pub class_name: String,
120    pub serial_version_uid: i64,
121    pub handle: u32,
122    pub flags: u8,
123    pub fields: Vec<FieldDesc>,
124    pub class_annotation: Vec<AnnotationElement>,
125    pub super_class_desc: Box<ClassDescRef>,
126}
127
128/// TC_PROXYCLASSDESC: proxy class descriptor.
129#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
130#[derive(Debug, Clone)]
131pub struct ProxyClassDesc {
132    pub handle: u32,
133    pub interface_names: Vec<String>,
134    pub class_annotation: Vec<AnnotationElement>,
135    pub super_class_desc: Box<ClassDescRef>,
136}
137
138/// Field descriptor in a class descriptor.
139#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
140#[derive(Debug, Clone)]
141pub enum FieldDesc {
142    Primitive(PrimitiveFieldDesc),
143    Object(ObjectFieldDesc),
144}
145
146/// Primitive field descriptor.
147#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
148#[derive(Debug, Clone)]
149pub struct PrimitiveFieldDesc {
150    pub type_code: u8,
151    pub field_name: String,
152}
153
154/// Object field descriptor.
155#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
156#[derive(Debug, Clone)]
157pub struct ObjectFieldDesc {
158    pub type_code: u8,
159    pub field_name: String,
160    pub class_name: String,
161}
162
163/// Elements in class annotation (between classDescInfo and superClassDesc).
164#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
165#[derive(Debug, Clone)]
166pub enum AnnotationElement {
167    Object(StreamObject),
168    BlockData(BlockData),
169}
170
171/// Block data.
172#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
173#[derive(Debug, Clone)]
174pub enum BlockData {
175    Short { data: Vec<u8> },
176    Long { data: Vec<u8> },
177}
178
179/// Class data for one class level in an object.
180#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
181#[derive(Debug, Clone)]
182pub enum ClassData {
183    /// SC_SERIALIZABLE without SC_WRITE_METHOD: just field values.
184    NoWriteMethod(FieldValueSet),
185    /// SC_SERIALIZABLE with SC_WRITE_METHOD, and defaultWriteObject() was called:
186    /// field values followed by object annotation.
187    WriteMethodWithFields(FieldValueSet, ObjectAnnotation),
188    /// SC_SERIALIZABLE with SC_WRITE_METHOD, and defaultWriteObject() was NOT called:
189    /// entire classdata is an objectAnnotation.
190    WriteMethod(ObjectAnnotation),
191    /// SC_EXTERNALIZABLE without SC_BLOCK_DATA: raw external contents.
192    ExternalContents(Vec<u8>),
193    /// SC_EXTERNALIZABLE with SC_BLOCK_DATA: object annotation format.
194    ExternalBlockData(ObjectAnnotation),
195}
196
197/// Set of field values for a class.
198#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
199#[derive(Debug, Clone)]
200pub struct FieldValueSet {
201    pub values: Vec<FieldValue>,
202}
203
204/// A single field value.
205#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
206#[derive(Debug, Clone)]
207pub enum FieldValue {
208    Byte(i8),
209    Char(u16),
210    Double(f64),
211    Float(f32),
212    Int(i32),
213    Long(i64),
214    Short(i16),
215    Boolean(bool),
216    Object(Option<Box<StreamObject>>),
217}
218
219/// Object annotation: contents between the class data and TC_ENDBLOCKDATA.
220#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
221#[derive(Debug, Clone)]
222pub struct ObjectAnnotation {
223    pub contents: Vec<AnnotationElement>,
224}
225
226impl NormalClassDesc {
227    pub fn has_write_method(&self) -> bool {
228        self.flags & constants::SC_WRITE_METHOD != 0
229    }
230
231    pub fn is_serializable(&self) -> bool {
232        self.flags & constants::SC_SERIALIZABLE != 0
233    }
234
235    pub fn is_externalizable(&self) -> bool {
236        self.flags & constants::SC_EXTERNALIZABLE != 0
237    }
238
239    pub fn has_block_data(&self) -> bool {
240        self.flags & constants::SC_BLOCK_DATA != 0
241    }
242
243    pub fn is_enum(&self) -> bool {
244        self.flags & constants::SC_ENUM != 0
245    }
246}
247
248impl BlockData {
249    /// Get the raw data bytes from block data.
250    pub fn data(&self) -> &[u8] {
251        match self {
252            BlockData::Short { data } => data,
253            BlockData::Long { data } => data,
254        }
255    }
256}
257
258impl ClassDescRef {
259    /// Try to get the class name from this class descriptor reference.
260    /// Returns None for Null references and unresolved Reference types.
261    pub fn class_name(&self) -> Option<&str> {
262        match self {
263            ClassDescRef::Inline(cd) => cd.class_name(),
264            ClassDescRef::Null => None,
265            ClassDescRef::Reference { .. } => None,
266        }
267    }
268}
269
270impl ClassDesc {
271    /// Get the class name from this class descriptor.
272    pub fn class_name(&self) -> Option<&str> {
273        match self {
274            ClassDesc::Normal(desc) => Some(&desc.class_name),
275            ClassDesc::Proxy(_) => None,
276        }
277    }
278}
279
280impl NewObject {
281    /// Get the class name of this object, if resolvable.
282    pub fn class_name(&self) -> Option<&str> {
283        self.class_desc.class_name()
284    }
285}
286
287impl NewArray {
288    /// Get the array class name (e.g., "[B", "[Ljava/lang/Object;").
289    pub fn class_name(&self) -> Option<&str> {
290        self.class_desc.class_name()
291    }
292}
293
294impl StreamObject {
295    /// Get the handle assigned to this object, if any.
296    pub fn handle(&self) -> Option<u32> {
297        match self {
298            StreamObject::NewObject(o) => Some(o.handle),
299            StreamObject::NewClass(c) => Some(c.handle),
300            StreamObject::NewArray(a) => Some(a.handle),
301            StreamObject::NewString(s) => Some(s.handle),
302            StreamObject::NewEnum(e) => Some(e.handle),
303            StreamObject::NewClassDesc(ClassDesc::Normal(d)) => Some(d.handle),
304            StreamObject::NewClassDesc(ClassDesc::Proxy(d)) => Some(d.handle),
305            StreamObject::PrevObject { handle } => Some(*handle),
306            StreamObject::NullReference | StreamObject::Exception | StreamObject::Reset => None,
307        }
308    }
309}
310
311impl SerializationStream {
312    /// Iterate over all top-level objects in the stream.
313    pub fn objects(&self) -> impl Iterator<Item = &StreamObject> {
314        self.contents.iter().filter_map(|c| match c {
315            ContentElement::Object(obj) => Some(obj),
316            ContentElement::BlockData(_) => None,
317        })
318    }
319}