<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap><loc>https://rankdblp.com/sitemap-1.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-2.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-3.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-4.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-5.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-6.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-7.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-8.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-9.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-10.xml.gz</loc></sitemap>
  <sitemap><loc>https://rankdblp.com/sitemap-11.xml.gz</loc></sitemap>
</sitemapindex>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>redb/extractors/decompiler/apk/method_extractor.py</title>
<style>
:root {
  --bg: #0d1117;
  --panel: #161b22;
  --text: #c9d1d9;
  --muted: #8b949e;
  --accent: #58a6ff;
  --border: #30363d;
}
* { box-sizing: border-box; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
header {
  padding: 14px 20px;
  background: var(--panel);
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}
header a { color: var(--accent); text-decoration: none; font-weight: 600; }
header a:hover { text-decoration: underline; }
.path { color: var(--muted); font-size: 0.9em; word-break: break-all; }
.note {
  padding: 10px 20px;
  background: #21262d;
  border-bottom: 1px solid var(--border);
  color: var(--muted);
  font-size: 0.85em;
}
main { padding: 0; }
pre {
  margin: 0;
  padding: 16px 20px 40px 20px;
  overflow-x: auto;
  font-size: 13px;
  line-height: 1.5;
}
code { font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace; }
.container { max-width: 1000px; margin: 30px auto; padding: 0 20px 60px; }
h1 { font-size: 1.6em; }
.meta { color: var(--muted); font-size: 0.9em; margin-bottom: 20px; }
ul.tree { list-style: none; padding-left: 18px; margin: 6px 0; }
ul.tree > li { margin: 4px 0; }
.dir-name { font-weight: 600; color: var(--text); }
.file a { color: var(--accent); text-decoration: none; }
.file a:hover { text-decoration: underline; }
.badge {
  display: inline-block;
  font-size: 0.72em;
  color: var(--muted);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1px 8px;
  margin-left: 6px;
}
.skipped { color: var(--muted); font-size: 0.85em; margin-top: 30px; }

/* Syntax highlighting: generated in Rust, no JavaScript involved. */
.c { color: #8b949e; font-style: italic; }
.s { color: #a5d6ff; }
.n { color: #79c0ff; }
.k { color: #ff7b72; font-weight: 600; }
</style>
</head>
<body>
<header>
  <a href="../../../../index.html">&larr; Index</a>
  <span class="path">redb/extractors/decompiler/apk/method_extractor.py</span>
  <span class="badge">python</span>
</header>
<main>
<pre><code><span class="s">&quot;&quot;&quot;Per-method content extraction, hashing, and similarity computation.

Handles SHA-256 content hashing, ssdeep/TLSH fuzzy hashing, MinHash
computation, and obfuscation indicator detection for APK methods.
&quot;&quot;&quot;</span>

<span class="k">import</span> hashlib
<span class="k">import</span> re
<span class="k">from</span> typing <span class="k">import</span> Dict, List, Optional

<span class="k">from</span> redb.extractors.decompiler.apk.smali_normalization <span class="k">import</span> (
    categorize_opcode,
    normalize_method_body,
)
<span class="k">from</span> redb.extractors.decompiler.apk.smali_parser <span class="k">import</span> SmaliParser


<span class="c"># ---------------------------------------------------------------------------</span>
<span class="c"># Smali Prime Product — semantic primes matching Binary Ninja&#39;s LLIL primes</span>
<span class="c"># ---------------------------------------------------------------------------</span>
<span class="c"># Each Dalvik semantic category maps to the same prime its LLIL counterpart</span>
<span class="c"># uses in cfg_features.py. This makes prime products semantically comparable</span>
<span class="c"># for APK-vs-APK similarity (not numerically comparable to Binja values).</span>

SMALI_OP_PRIMES = {
    <span class="s">&quot;ALU&quot;</span>: <span class="n">37</span>,       <span class="c"># ADD/SUB → same prime as LLIL_ADD</span>
    <span class="s">&quot;CONV&quot;</span>: <span class="n">131</span>,     <span class="c"># Type conversions → same as LLIL_SX</span>
    <span class="s">&quot;CMP&quot;</span>: <span class="n">103</span>,      <span class="c"># Comparisons → same as LLIL_CMP_E</span>
    <span class="s">&quot;MOV&quot;</span>: <span class="n">2</span>,        <span class="c"># Register moves → same as LLIL_SET_REG</span>
    <span class="s">&quot;CONST&quot;</span>: <span class="n">2</span>,      <span class="c"># Constants → SET_REG equivalent</span>
    <span class="s">&quot;LOAD&quot;</span>: <span class="n">5</span>,       <span class="c"># Field/array reads → same as LLIL_LOAD</span>
    <span class="s">&quot;STORE&quot;</span>: <span class="n">7</span>,      <span class="c"># Field/array writes → same as LLIL_STORE</span>
    <span class="s">&quot;CALL&quot;</span>: <span class="n">17</span>,      <span class="c"># invoke-* → same as LLIL_CALL</span>
    <span class="s">&quot;BRANCH&quot;</span>: <span class="n">29</span>,    <span class="c"># if-* → same as LLIL_IF</span>
    <span class="s">&quot;JMP&quot;</span>: <span class="n">31</span>,       <span class="c"># goto → same as LLIL_GOTO</span>
    <span class="s">&quot;SWITCH&quot;</span>: <span class="n">151</span>,   <span class="c"># switch → same as LLIL_JUMP_TO</span>
    <span class="s">&quot;RET&quot;</span>: <span class="n">23</span>,       <span class="c"># return → same as LLIL_RET</span>
    <span class="s">&quot;ALLOC&quot;</span>: <span class="n">5</span>,      <span class="c"># new-instance/new-array → LOAD-adjacent (heap access)</span>
    <span class="s">&quot;TYPE&quot;</span>: <span class="n">1</span>,       <span class="c"># check-cast/instance-of → identity (metadata)</span>
    <span class="s">&quot;ARR&quot;</span>: <span class="n">5</span>,        <span class="c"># array-length/fill-array → LOAD-adjacent</span>
    <span class="s">&quot;EXC&quot;</span>: <span class="n">23</span>,       <span class="c"># throw → RET-adjacent (control transfer out)</span>
    <span class="s">&quot;SYNC&quot;</span>: <span class="n">1</span>,       <span class="c"># monitor → identity (no LLIL equivalent)</span>
    <span class="s">&quot;OTHER&quot;</span>: <span class="n">1</span>,      <span class="c"># Unknown → identity</span>
}


<span class="k">def</span> compute_prime_product_smali(smali_body: str) -&gt; int:
    <span class="s">&quot;&quot;&quot;Multiplicative hash of normalized Dalvik opcodes. Mod 2^64.

    Same algorithm as cfg_features.compute_prime_product but using
    Dalvik semantic categories instead of LLIL operation enums.
    &quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="k">not</span> smali_body:
        <span class="k">return</span> <span class="n">0</span>

    product = <span class="n">1</span>
    <span class="k">for</span> line <span class="k">in</span> smali_body.splitlines():
        stripped = line.strip()
        <span class="k">if</span> <span class="k">not</span> stripped <span class="k">or</span> stripped.startswith((<span class="s">&quot;.&quot;</span>, <span class="s">&quot;:&quot;</span>, <span class="s">&quot;#&quot;</span>)):
            <span class="k">continue</span>
        opcode = stripped.split()[<span class="n">0</span>].split(<span class="s">&quot;/&quot;</span>)[<span class="n">0</span>] <span class="k">if</span> stripped <span class="k">else</span> <span class="s">&quot;&quot;</span>
        category = categorize_opcode(opcode)
        prime = SMALI_OP_PRIMES.get(category, <span class="n">1</span>)
        product = (product * prime) % (<span class="n">2</span>**<span class="n">64</span>)

    <span class="k">return</span> product


<span class="k">def</span> count_call_instructions(smali_body: str) -&gt; int:
    <span class="s">&quot;&quot;&quot;Count invoke-* instructions in a smali method body.&quot;&quot;&quot;</span>
    <span class="k">if</span> <span class="k">not</span> smali_body:
        <span class="k">return</span> <span class="n">0</span>
    count = <span class="n">0</span>
    <span class="k">for</span> line <span class="k">in</span> smali_body.splitlines():
        stripped = line.strip()
        <span class="k">if</span> stripped.startswith(<span class="s">&quot;invoke-&quot;</span>):
            count += <span class="n">1</span>
    <span class="k">return</span> count


<span class="k">def</span> compute_sha256(content: str) -&gt; str:
    <span class="s">&quot;&quot;&quot;Compute SHA-256 hash of normalized content.&quot;&quot;&quot;</span>
    <span class="k">return</span> hashlib.sha256(content.encode(<span class="s">&quot;utf-8&quot;</span>)).hexdigest()


<span class="k">def</span> compute_ssdeep(content: str) -&gt; Optional[str]:
    <span class="s">&quot;&quot;&quot;Compute ssdeep fuzzy hash of content.&quot;&quot;&quot;</span>
    <span class="k">try</span>:
        <span class="k">import</span> ppdeep
        data = content.encode(<span class="s">&quot;utf-8&quot;</span>)
        <span class="k">if</span> len(data) &lt; <span class="n">50</span>:
            <span class="k">return</span> <span class="k">None</span>
        result = ppdeep.hash(data)
        <span class="k">return</span> result <span class="k">if</span> result <span class="k">else</span> <span class="k">None</span>
    <span class="k">except</span> (ImportError, Exception):
        <span class="k">return</span> <span class="k">None</span>


<span class="k">def</span> compute_tlsh(content: str) -&gt; Optional[str]:
    <span class="s">&quot;&quot;&quot;Compute TLSH fuzzy hash of content.&quot;&quot;&quot;</span>
    <span class="k">try</span>:
        <span class="k">import</span> tlsh
        data = content.encode(<span class="s">&quot;utf-8&quot;</span>)
        <span class="k">if</span> len(data) &lt; <span class="n">50</span>:
            <span class="k">return</span> <span class="k">None</span>
        result = tlsh.hash(data)
        <span class="k">return</span> result <span class="k">if</span> result <span class="k">else</span> <span class="k">None</span>
    <span class="k">except</span> (ImportError, Exception):
        <span class="k">return</span> <span class="k">None</span>


<span class="k">def</span> compute_minhash(
    content: str,
    n: int = <span class="n">3</span>,
    normalization_level: str = <span class="s">&quot;opcode_api&quot;</span>,
) -&gt; Optional[List[int]]:
    <span class="s">&quot;&quot;&quot;Compute MinHash signature from semantically normalized smali n-grams.

    Applies semantic normalization (analogous to Binary Ninja&#39;s LLIL) before
    computing the MinHash. This strips register allocation noise and
    instruction encoding variants while preserving operation semantics and
    API references.

    Uses the same algorithm and parameters as the Binary Ninja MinHasher
    (64 seeds from master seed 0xdeadbeef, 8-bit signature elements, mmh3)
    to ensure cross-platform similarity comparisons are compatible.

    Args:
        content: Raw smali method body.
        n: N-gram size (default 3).
        normalization_level: Normalization level for instructions.
            &#39;opcode_api&#39; (default) preserves API call/field references.
            &#39;category&#39; uses only semantic categories.
            &#39;opcode&#39; uses base opcodes without operands.
    &quot;&quot;&quot;</span>
    <span class="k">try</span>:
        <span class="k">import</span> mmh3
    <span class="k">except</span> ImportError:
        <span class="k">return</span> <span class="k">None</span>

    HASH_MAX = <span class="n">0xFFFFFFFF</span>
    SIGNATURE_LENGTH = <span class="n">64</span>
    SIGNATURE_BITS = <span class="n">8</span>

    <span class="c"># Semantically normalize instructions (like LLIL for native code)</span>
    lines = normalize_method_body(content, level=normalization_level)

    <span class="k">if</span> len(lines) &lt; n:
        <span class="k">return</span> <span class="k">None</span>

    <span class="c"># Build n-grams (tuples of normalized instruction strings)</span>
    shingles = [tuple(lines[i:i + n]) <span class="k">for</span> i <span class="k">in</span> range(len(lines) - n + <span class="n">1</span>)]

    <span class="k">if</span> <span class="k">not</span> shingles:
        <span class="k">return</span> <span class="k">None</span>

    <span class="c"># Generate deterministic seeds matching the Binary Ninja pipeline</span>
    <span class="k">import</span> random
    rng = random.Random(<span class="n">0xDEADBEEF</span>)
    seeds = [rng.randint(<span class="n">0</span>, HASH_MAX) <span class="k">for</span> _ <span class="k">in</span> range(SIGNATURE_LENGTH)]

    <span class="c"># For each seed, hash all shingles and take the minimum</span>
    signature = []
    <span class="k">for</span> seed <span class="k">in</span> seeds:
        min_val = HASH_MAX
        <span class="k">for</span> shingle <span class="k">in</span> shingles:
            text = <span class="s">&quot;|&quot;</span>.join(str(elem) <span class="k">for</span> elem <span class="k">in</span> shingle)
            h = mmh3.hash(text, seed) &amp; HASH_MAX
            <span class="k">if</span> h &lt; min_val:
                min_val = h
        <span class="c"># Truncate to signature bits</span>
        <span class="k">if</span> SIGNATURE_BITS &lt; <span class="n">32</span>:
            min_val %= (<span class="n">2</span> ** SIGNATURE_BITS)
        signature.append(min_val)

    <span class="k">return</span> signature


<span class="k">def</span> detect_obfuscation_indicators(
    method_name: str,
    class_name: str,
    smali_body: str,
    instruction_count: int,
) -&gt; Dict[str, bool]:
    <span class="s">&quot;&quot;&quot;Compute obfuscation indicators for a method.

    Returns dict with boolean indicators.
    &quot;&quot;&quot;</span>
    indicators = {}

    <span class="c"># Short method name (typical R8/ProGuard output)</span>
    indicators[<span class="s">&quot;short_method_name&quot;</span>] = len(method_name) &lt;= <span class="n">2</span>

    <span class="c"># Short class name — extract simple name from Dalvik descriptor</span>
    simple_class = class_name
    <span class="k">if</span> <span class="s">&quot;/&quot;</span> <span class="k">in</span> simple_class:
        simple_class = simple_class.rsplit(<span class="s">&quot;/&quot;</span>, <span class="n">1</span>)[-<span class="n">1</span>]
    simple_class = simple_class.rstrip(<span class="s">&quot;;&quot;</span>)
    indicators[<span class="s">&quot;short_class_name&quot;</span>] = len(simple_class) &lt;= <span class="n">2</span>

    <span class="c"># String encryption: const-string followed by decryption-pattern call</span>
    indicators[<span class="s">&quot;has_string_encryption&quot;</span>] = _detect_string_encryption(smali_body)

    <span class="c"># Reflection calls</span>
    indicators[<span class="s">&quot;has_reflection_calls&quot;</span>] = _detect_reflection_calls(smali_body)

    <span class="c"># Excessive goto count (control flow flattening)</span>
    goto_count = _count_goto_instructions(smali_body)
    threshold = max(<span class="n">5</span>, int(instruction_count * <span class="n">0.15</span>))
    indicators[<span class="s">&quot;excessive_goto_count&quot;</span>] = goto_count &gt; threshold

    <span class="k">return</span> indicators


<span class="k">def</span> _detect_string_encryption(smali_body: str) -&gt; bool:
    <span class="s">&quot;&quot;&quot;Detect const-string followed by decryption-pattern calls.&quot;&quot;&quot;</span>
    lines = smali_body.split(<span class="s">&quot;\n&quot;</span>)
    <span class="k">for</span> i, line <span class="k">in</span> enumerate(lines):
        stripped = line.strip()
        <span class="k">if</span> stripped.startswith(<span class="s">&quot;const-string&quot;</span>):
            <span class="c"># Check the next 3 lines for invoke-* to potential decryption</span>
            <span class="k">for</span> j <span class="k">in</span> range(i + <span class="n">1</span>, min(i + <span class="n">4</span>, len(lines))):
                next_line = lines[j].strip()
                <span class="k">if</span> next_line.startswith(<span class="s">&quot;invoke-&quot;</span>):
                    <span class="c"># Common decryption patterns</span>
                    <span class="k">if</span> any(
                        pat <span class="k">in</span> next_line
                        <span class="k">for</span> pat <span class="k">in</span> [
                            <span class="s">&quot;decrypt&quot;</span>,
                            <span class="s">&quot;decode&quot;</span>,
                            <span class="s">&quot;Cipher&quot;</span>,
                            <span class="s">&quot;DES&quot;</span>,
                            <span class="s">&quot;AES&quot;</span>,
                            <span class="s">&quot;Base64&quot;</span>,
                            <span class="s">&quot;getBytes&quot;</span>,
                        ]
                    ):
                        <span class="k">return</span> <span class="k">True</span>
    <span class="k">return</span> <span class="k">False</span>


<span class="k">def</span> _detect_reflection_calls(smali_body: str) -&gt; bool:
    <span class="s">&quot;&quot;&quot;Detect use of Java reflection APIs.&quot;&quot;&quot;</span>
    reflection_patterns = [
        <span class="s">&quot;Ljava/lang/reflect/&quot;</span>,
        <span class="s">&quot;Ljava/lang/Class;-&gt;forName&quot;</span>,
        <span class="s">&quot;Ljava/lang/Class;-&gt;getMethod&quot;</span>,
        <span class="s">&quot;Ljava/lang/Class;-&gt;getDeclaredMethod&quot;</span>,
        <span class="s">&quot;Ljava/lang/Class;-&gt;getField&quot;</span>,
        <span class="s">&quot;Ljava/lang/Class;-&gt;getDeclaredField&quot;</span>,
    ]
    <span class="k">for</span> pattern <span class="k">in</span> reflection_patterns:
        <span class="k">if</span> pattern <span class="k">in</span> smali_body:
            <span class="k">return</span> <span class="k">True</span>
    <span class="k">return</span> <span class="k">False</span>


<span class="k">def</span> _count_goto_instructions(smali_body: str) -&gt; int:
    <span class="s">&quot;&quot;&quot;Count goto/goto_16/goto_32 instructions.&quot;&quot;&quot;</span>
    count = <span class="n">0</span>
    <span class="k">for</span> line <span class="k">in</span> smali_body.split(<span class="s">&quot;\n&quot;</span>):
        stripped = line.strip()
        <span class="k">if</span> stripped.startswith((<span class="s">&quot;goto &quot;</span>, <span class="s">&quot;goto/16 &quot;</span>, <span class="s">&quot;goto/32 &quot;</span>)):
            count += <span class="n">1</span>
        <span class="k">elif</span> stripped <span class="k">in</span> (<span class="s">&quot;goto&quot;</span>, <span class="s">&quot;goto/16&quot;</span>, <span class="s">&quot;goto/32&quot;</span>):
            count += <span class="n">1</span>
    <span class="k">return</span> count


<span class="k">def</span> dalvik_to_java_class(descriptor: str) -&gt; str:
    <span class="s">&quot;&quot;&quot;Convert Dalvik class descriptor to Java dot notation.

    Lcom/example/Foo; -&gt; com.example.Foo
    &quot;&quot;&quot;</span>
    <span class="k">if</span> descriptor.startswith(<span class="s">&quot;L&quot;</span>) <span class="k">and</span> descriptor.endswith(<span class="s">&quot;;&quot;</span>):
        <span class="k">return</span> descriptor[<span class="n">1</span>:-<span class="n">1</span>].replace(<span class="s">&quot;/&quot;</span>, <span class="s">&quot;.&quot;</span>)
    <span class="k">return</span> descriptor.replace(<span class="s">&quot;/&quot;</span>, <span class="s">&quot;.&quot;</span>)


<span class="k">def</span> dalvik_type_to_java(type_desc: str) -&gt; str:
    <span class="s">&quot;&quot;&quot;Convert a Dalvik type descriptor to Java type name.&quot;&quot;&quot;</span>
    type_map = {
        <span class="s">&quot;V&quot;</span>: <span class="s">&quot;void&quot;</span>,
        <span class="s">&quot;Z&quot;</span>: <span class="s">&quot;boolean&quot;</span>,
        <span class="s">&quot;B&quot;</span>: <span class="s">&quot;byte&quot;</span>,
        <span class="s">&quot;S&quot;</span>: <span class="s">&quot;short&quot;</span>,
        <span class="s">&quot;C&quot;</span>: <span class="s">&quot;char&quot;</span>,
        <span class="s">&quot;I&quot;</span>: <span class="s">&quot;int&quot;</span>,
        <span class="s">&quot;J&quot;</span>: <span class="s">&quot;long&quot;</span>,
        <span class="s">&quot;F&quot;</span>: <span class="s">&quot;float&quot;</span>,
        <span class="s">&quot;D&quot;</span>: <span class="s">&quot;double&quot;</span>,
    }

    <span class="k">if</span> <span class="k">not</span> type_desc:
        <span class="k">return</span> <span class="s">&quot;void&quot;</span>

    <span class="k">if</span> type_desc <span class="k">in</span> type_map:
        <span class="k">return</span> type_map[type_desc]

    <span class="k">if</span> type_desc.startswith(<span class="s">&quot;[&quot;</span>):
        <span class="k">return</span> dalvik_type_to_java(type_desc[<span class="n">1</span>:]) + <span class="s">&quot;[]&quot;</span>

    <span class="k">if</span> type_desc.startswith(<span class="s">&quot;L&quot;</span>) <span class="k">and</span> type_desc.endswith(<span class="s">&quot;;&quot;</span>):
        full = type_desc[<span class="n">1</span>:-<span class="n">1</span>].replace(<span class="s">&quot;/&quot;</span>, <span class="s">&quot;.&quot;</span>)
        <span class="c"># Return simple name</span>
        <span class="k">return</span> full.rsplit(<span class="s">&quot;.&quot;</span>, <span class="n">1</span>)[-<span class="n">1</span>] <span class="k">if</span> <span class="s">&quot;.&quot;</span> <span class="k">in</span> full <span class="k">else</span> full

    <span class="k">return</span> type_desc


<span class="k">def</span> dalvik_to_java_prototype(
    method_name: str, signature: str, class_name: str = <span class="s">&quot;&quot;</span>
) -&gt; str:
    <span class="s">&quot;&quot;&quot;Convert Dalvik method signature to Java-style prototype.

    Input: method_name=&#39;onCreate&#39;, signature=&#39;(Landroid/os/Bundle;)V&#39;
    Output: &#39;void onCreate(Bundle)&#39;
    &quot;&quot;&quot;</span>
    <span class="c"># Parse return type and param types from signature</span>
    <span class="k">if</span> <span class="k">not</span> signature <span class="k">or</span> <span class="k">not</span> signature.startswith(<span class="s">&quot;(&quot;</span>):
        <span class="k">return</span> f<span class="s">&quot;void {method_name}()&quot;</span>

    close_paren = signature.find(<span class="s">&quot;)&quot;</span>)
    <span class="k">if</span> close_paren == -<span class="n">1</span>:
        <span class="k">return</span> f<span class="s">&quot;void {method_name}()&quot;</span>

    params_str = signature[<span class="n">1</span>:close_paren]
    return_type_str = signature[close_paren + <span class="n">1</span>:]

    return_type = dalvik_type_to_java(return_type_str)
    params = _parse_dalvik_params(params_str)
    param_java = <span class="s">&quot;, &quot;</span>.join(dalvik_type_to_java(p) <span class="k">for</span> p <span class="k">in</span> params)

    <span class="k">return</span> f<span class="s">&quot;{return_type} {method_name}({param_java})&quot;</span>


<span class="k">def</span> _parse_dalvik_params(params_str: str) -&gt; List[str]:
    <span class="s">&quot;&quot;&quot;Parse Dalvik parameter descriptor string into individual types.&quot;&quot;&quot;</span>
    params = []
    i = <span class="n">0</span>
    <span class="k">while</span> i &lt; len(params_str):
        ch = params_str[i]
        <span class="k">if</span> ch <span class="k">in</span> <span class="s">&quot;VZBSCIJFD&quot;</span>:
            params.append(ch)
            i += <span class="n">1</span>
        <span class="k">elif</span> ch == <span class="s">&quot;[&quot;</span>:
            <span class="c"># Array — find the base type</span>
            array_prefix = <span class="s">&quot;[&quot;</span>
            i += <span class="n">1</span>
            <span class="k">while</span> i &lt; len(params_str) <span class="k">and</span> params_str[i] == <span class="s">&quot;[&quot;</span>:
                array_prefix += <span class="s">&quot;[&quot;</span>
                i += <span class="n">1</span>
            <span class="k">if</span> i &lt; len(params_str):
                <span class="k">if</span> params_str[i] == <span class="s">&quot;L&quot;</span>:
                    end = params_str.find(<span class="s">&quot;;&quot;</span>, i)
                    <span class="k">if</span> end != -<span class="n">1</span>:
                        params.append(array_prefix + params_str[i : end + <span class="n">1</span>])
                        i = end + <span class="n">1</span>
                    <span class="k">else</span>:
                        <span class="k">break</span>
                <span class="k">else</span>:
                    params.append(array_prefix + params_str[i])
                    i += <span class="n">1</span>
        <span class="k">elif</span> ch == <span class="s">&quot;L&quot;</span>:
            end = params_str.find(<span class="s">&quot;;&quot;</span>, i)
            <span class="k">if</span> end != -<span class="n">1</span>:
                params.append(params_str[i : end + <span class="n">1</span>])
                i = end + <span class="n">1</span>
            <span class="k">else</span>:
                <span class="k">break</span>
        <span class="k">else</span>:
            i += <span class="n">1</span>
    <span class="k">return</span> params
</code></pre>
</main>
</body>
</html>
