From 1e51bcebae9860ae287f6ce67d8e8b111b9a3a56 Mon Sep 17 00:00:00 2001 From: Miguel Saldivar Date: Mon, 22 Jun 2020 22:09:23 -0700 Subject: [PATCH] Add the ability to demangle java resource files --- build.rs | 3 +- src/ast.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/build.rs b/build.rs index 1de4f3d..096d3c5 100644 --- a/build.rs +++ b/build.rs @@ -135,8 +135,7 @@ use std::fmt::Write; let mut s: HashSet<_> = (0..86).collect(); s.extend(87..89); s.extend(91..93); - s.extend(94..105); - s.extend(106..113); + s.extend(94..113); s.extend(115..118); s.extend(119..120); s.extend(121..124); diff --git a/src/ast.rs b/src/ast.rs index c8810bc..fdd5855 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -7265,6 +7265,7 @@ where /// ::= TF # typinfo function /// ::= TH # TLS initialization function /// ::= TW # TLS wrapper function +/// ::= Gr # Java Resource /// ``` #[derive(Clone, Debug, PartialEq, Eq)] pub enum SpecialName { @@ -7304,6 +7305,9 @@ pub enum SpecialName { /// A TLS wrapper function. TlsWrapper(Name), + + /// A Java Resource. + JavaResource(Vec), } impl Parse for SpecialName { @@ -7393,6 +7397,26 @@ impl Parse for SpecialName { }; Ok((SpecialName::GuardTemporary(name, idx), tail)) } + b"Gr" => { + let (resource_name_len, tail) = parse_number(10, false, tail)?; + if resource_name_len == 0 { + return Err(error::Error::UnexpectedText); + } + + let (head, tail) = match tail.try_split_at(resource_name_len as _) { + Some((head, tail)) => (head, tail), + None => return Err(error::Error::UnexpectedEnd), + }; + + let head = consume(b"_", head)?; + + let (resource_names, empty) = zero_or_more::(ctx, subs, head)?; + if !empty.is_empty() { + return Err(error::Error::UnexpectedText); + } + + Ok((SpecialName::JavaResource(resource_names), tail)) + } _ => Err(error::Error::UnexpectedText), } } @@ -7480,10 +7504,100 @@ where write!(ctx, "TLS wrapper function for ")?; name.demangle(ctx, scope) } + SpecialName::JavaResource(ref names) => { + write!(ctx, "java resource ")?; + for name in names { + name.demangle(ctx, scope)?; + } + Ok(()) + } } } } +/// The `` pseudo-terminal. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct ResourceName { + start: usize, + end: usize, +} + +impl Parse for ResourceName { + fn parse<'a, 'b>( + ctx: &'a ParseContext, + _subs: &'a mut SubstitutionTable, + input: IndexStr<'b>, + ) -> Result<(ResourceName, IndexStr<'b>)> { + try_begin_parse!("ResourceName", ctx, input); + + if input.is_empty() { + return Err(error::Error::UnexpectedEnd); + } + + let mut end = input + .as_ref() + .iter() + .map(|&c| c as char) + .take_while(|&c| c != '$' || c.is_digit(36)) + .count(); + + if end == 0 { + return Err(error::Error::UnexpectedText); + } + + if input.range_from(end..).peek() == Some(b'$') { + match input.range_from(end..).peek_second() { + Some(b'S') | Some(b'_') | Some(b'$') => end += 2, + _ => return Err(error::Error::UnexpectedText) + } + } + + let tail = input.range_from(end..); + + let resource_name = ResourceName { + start: input.index(), + end: tail.index(), + }; + + Ok((resource_name, tail)) + } +} + +impl<'subs, W> Demangle<'subs, W> for ResourceName +where + W: 'subs + DemangleWrite, +{ + #[inline] + fn demangle<'prev, 'ctx>( + &'subs self, + ctx: &'ctx mut DemangleContext<'subs, W>, + scope: Option>, + ) -> fmt::Result { + let ctx = try_begin_demangle!(self, ctx, scope); + + let mut i = self.start; + while i < self.end { + let ch = ctx.input[i]; + if ch == b'$' { + // Skip past the '$' + i += 1; + match ctx.input[i] { + b'S' => write!(ctx, "{}", '/')?, + b'_' => write!(ctx, "{}", '.')?, + b'$' => write!(ctx, "{}", '$')?, + _ => { + // Fall through + }, + } + } else { + write!(ctx, "{}", ch as char)?; + } + i += 1; + } + + Ok(()) + } +} /// Expect and consume the given byte str, and return the advanced `IndexStr` if /// we saw the expectation. Otherwise return an error of kind /// `error::Error::UnexpectedText` if the input doesn't match, or @@ -7598,7 +7712,7 @@ mod tests { FunctionParam, FunctionType, GlobalCtorDtor, Identifier, Initializer, LambdaSig, LocalName, MangledName, MemberName, Name, NestedName, NonSubstitution, Number, NvOffset, OperatorName, Parse, ParseContext, PointerToMemberType, Prefix, - PrefixHandle, RefQualifier, SeqId, SimpleId, SimpleOperatorName, SourceName, + PrefixHandle, RefQualifier, ResourceName, SeqId, SimpleId, SimpleOperatorName, SourceName, SpecialName, StandardBuiltinType, Substitution, TaggedName, TemplateArg, TemplateArgs, TemplateParam, TemplateTemplateParam, TemplateTemplateParamHandle, Type, TypeHandle, UnnamedTypeName, UnqualifiedName, UnresolvedName, @@ -10398,6 +10512,13 @@ mod tests { 1), b"..." } + b"Gr4_abc..." => { + SpecialName::JavaResource(vec![ResourceName { + start: 4, + end: 7, + }]), + b"..." + } b"TCc7_i..." => { SpecialName::ConstructionVtable( TypeHandle::Builtin(BuiltinType::Standard(StandardBuiltinType::Char)), @@ -10440,6 +10561,7 @@ mod tests { b"GR3abc0" => Error::UnexpectedEnd, // This number is not allowed to be negative. b"TCcn7_i..." => Error::UnexpectedText, + b"Gr3abc0" => Error::UnexpectedText, } }); }