From 61c9454a718b1cf87029833d5fb493e09990dbfe Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sat, 25 Jan 2020 19:12:52 +0100
Subject: Handled the MUTF-8 U+0000 code point.

---
 plugins/dex/dex-int.c   |   2 +-
 plugins/dexbnf/simple.c |   2 +-
 src/common/utf8.c       | 120 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/common/utf8.h       |   3 ++
 4 files changed, 125 insertions(+), 2 deletions(-)

diff --git a/plugins/dex/dex-int.c b/plugins/dex/dex-int.c
index 843db32..fc1db58 100644
--- a/plugins/dex/dex-int.c
+++ b/plugins/dex/dex-int.c
@@ -210,7 +210,7 @@ bool read_dex_string_data_item(const GDexFormat *format, vmpa2t *pos, vmpa2t *in
 
             tmp = g_binary_content_get_raw_access(content, pos, maxsize);
 
-            ch = decode_utf8_char(tmp, maxsize, &used);
+            ch = decode_mutf8_char(tmp, maxsize, &used);
 
             if (IS_UTF8_ERROR(ch))
                 result = false;
diff --git a/plugins/dexbnf/simple.c b/plugins/dexbnf/simple.c
index f06fc4d..fd7b8ab 100644
--- a/plugins/dexbnf/simple.c
+++ b/plugins/dexbnf/simple.c
@@ -132,7 +132,7 @@ static size_t dcd_simple_name_char(input_buffer *buffer)
     text = get_input_buffer_text_access(buffer);
     remaining = count_input_buffer_remaining(buffer);
 
-    wc = decode_utf8_char((unsigned char *)text, remaining, &result);
+    wc = decode_mutf8_char((unsigned char *)text, remaining, &result);
 
     if (IS_UTF8_ERROR(wc))
         return 0;
diff --git a/src/common/utf8.c b/src/common/utf8.c
index c5cfa03..9250fef 100644
--- a/src/common/utf8.c
+++ b/src/common/utf8.c
@@ -148,3 +148,123 @@ unichar_t decode_utf8_char(const unsigned char *text, size_t len, size_t *consum
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : text     = position courante dans une chaîne de caractères.  *
+*                len      = nombre d'octets de cette même chaîne.             *
+*                consumed = nombre d'octets lus pendant l'opération. [OUT]    *
+*                                                                             *
+*  Description : Procède à la lecture d'un caractère d'une chaîne en MUTF-8.  *
+*                                                                             *
+*  Retour      : Caractère sur 32 bits lu ou code d'erreur en cas de soucis.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+unichar_t decode_mutf8_char(const unsigned char *text, size_t len, size_t *consumed)
+{
+    unichar_t result;                       /* Valeur à retourner          */
+    size_t expected;                        /* Quantité à traiter          */
+    unichar_t minval;                       /* Valeur codée minimale       */
+    size_t i;                               /* Boucle de parcours          */
+
+    /**
+     * Le format suivant est détaillé à la page :
+     * https://source.android.com/devices/tech/dalvik/dex-format#mutf-8
+     */
+
+    result = text[0];
+
+    /**
+     * ASCII ?
+     */
+    if (result < 0x80)
+    {
+        *consumed = 1;
+        goto duc_done;
+    }
+
+    /**
+     * Deux caractères (au moins) doivent être présents.
+     * Le premier mot doit donc au moins commencer par 0b1100 = 0xc.
+     */
+    else if (result < 0xc0)
+    {
+        result = UTF8_ERROR_MALFORMED;
+        goto duc_done;
+    }
+
+    /**
+     * Valeur inférieure à 0xe, donc taille inférieure à 3 (0b1110).
+     */
+    else if (result < 0xe0)
+    {
+        expected = 2;
+        result &= 0x1f;
+        minval = 1 << 7;
+    }
+
+    /**
+     * Valeur inférieure à 0xf0, donc taille inférieure à 4 (0b11110000).
+     */
+    else if (result < 0xf0)
+    {
+        expected = 3;
+        result &= 0x0f;
+        minval = 1 << 11;
+    }
+
+    /**
+     * Erreur : l'encodage MUTF-8 ne dépasse pas 3 octets.
+     */
+    else
+    {
+        result = UTF8_ERROR_TOO_LONG;
+        goto duc_done;
+    }
+
+    /**
+     * Erreur : pas assez de données.
+     */
+    if (expected > len)
+    {
+        result = UTF8_ERROR_TOO_LONG;
+        goto duc_done;
+    }
+
+    /**
+     * Intégration des octets restants, avec vérifications qu'ils participent
+     * bien à la constitution de la valeur finale.
+     */
+    for (i = 1; i < expected; i++)
+    {
+        if ((text[i] & 0xc0) != 0x80)
+        {
+            result = UTF8_ERROR_MISSING;
+            goto duc_done;
+        }
+
+        result <<= 6;
+        result |= (text[i] & 0x3f);
+
+    }
+
+    /**
+     * Validation finale.
+     */
+    if (result < minval && (result != 0 || expected != 2))
+    {
+        result = UTF8_ERROR_WASTING;
+        goto duc_done;
+    }
+
+    *consumed = expected;
+
+ duc_done:
+
+    return result;
+
+}
diff --git a/src/common/utf8.h b/src/common/utf8.h
index 4b8437d..88ebd20 100644
--- a/src/common/utf8.h
+++ b/src/common/utf8.h
@@ -50,6 +50,9 @@ typedef uint32_t unichar_t;
 /* Procède à la lecture d'un caractère dans une chaîne en UTF-8. */
 unichar_t decode_utf8_char(const unsigned char *, size_t, size_t *);
 
+/* Procède à la lecture d'un caractère d'une chaîne en MUTF-8. */
+unichar_t decode_mutf8_char(const unsigned char *, size_t, size_t *);
+
 
 
 #endif  /* _COMMON_UTF8_H */
-- 
cgit v0.11.2-87-g4458