[PATCH 06/11] [Kernel32]: ActCtx: first shot at manifest parsing

Eric Pouech eric.pouech at wanadoo.fr
Wed May 9 15:08:03 CDT 2007


From: Jacek Caban <jacek at codeweavers.com>


---

 dlls/kernel32/actctx.c |  323 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 321 insertions(+), 2 deletions(-)

diff --git a/dlls/kernel32/actctx.c b/dlls/kernel32/actctx.c
index 854f454..8dfacf3 100644
--- a/dlls/kernel32/actctx.c
+++ b/dlls/kernel32/actctx.c
@@ -1,4 +1,4 @@
-*/*
+/*
  * Activation contexts
  *
  * Copyright 2004 Jon Griffiths
@@ -78,10 +78,24 @@ struct version
     ULONG               revision;
 };
 
+enum assembly_id_type
+{
+    TYPE_NONE,
+    TYPE_WIN32
+};
+
+enum assembly_id_arch
+{
+    ARCH_NONE,
+    ARCH_X86
+};
+
 struct assembly_identity
 {
     LPWSTR              name;
     struct version      version;
+    enum assembly_id_type type;
+    enum assembly_id_arch arch;
 };
 
 enum assembly_type
@@ -126,11 +140,36 @@ static WCHAR* strdupW(const WCHAR* str)
     return strcpyW(ptr, str);
 }
 
-static BOOL xmlstr_cmp(xmlstr_t* xmlstr, const char* str)
+static WCHAR* strdupXW(const xmlstr_t* str)
+{
+    WCHAR*      ptr;
+    unsigned    len;
+
+    len = MultiByteToWideChar(CP_ACP, 0, str->ptr, str->len, NULL, 0);
+    ptr = HeapAlloc(GetProcessHeap(), 0, (len + 1) * sizeof(WCHAR));
+    if (ptr)
+    {
+        MultiByteToWideChar(CP_ACP, 0, str->ptr, str->len, ptr, len);
+        ptr[len] = '\0';
+    }
+    return ptr;
+}
+
+static inline BOOL xmlstr_cmp(xmlstr_t* xmlstr, const char* str)
 {
     return !strncmp(xmlstr->ptr, str, xmlstr->len);
 }
 
+static inline BOOL xmlstr_icmp(xmlstr_t* xmlstr, const char* str)
+{
+    return !strncasecmp(xmlstr->ptr, str, xmlstr->len);
+}
+
+static inline const char* debugstr_xmlstr(const xmlstr_t* str)
+{
+    return debugstr_an(str->ptr, str->len);
+}
+
 static struct assembly* add_assembly(struct actctx* actctx, enum assembly_type at)
 {
     struct assembly*    assembly;
@@ -265,6 +304,84 @@ done:
     return ret;
 }
 
+#define ASSEMBLY_ELEM                   "assembly"
+#define ASSEMBLYIDENTITY_ELEM           "assemblyIdentity"
+
+#define ELEM_END(elem) "/" elem
+
+#define MANIFESTVERSION_ATTR            "manifestVersion"
+#define NAME_ATTR                       "name"
+#define PROCESSORARCHITECTURE_ATTR      "processorArchitecture"
+#define TYPE_ATTR                       "type"
+#define VERSION_ATTR                    "version"
+#define XMLNS_ATTR                      "xmlns"
+
+#define MANIFEST_NAMESPACE              "urn:schemas-microsoft-com:asm.v1"
+
+static BOOL next_xml_attr(xmlbuf_t* xmlbuf, xmlstr_t* name, xmlstr_t* value,
+                          BOOL* error, BOOL* end)
+{
+    const char* ptr;
+
+    *error = TRUE;
+
+    while (xmlbuf->ptr < xmlbuf->end && isspace(*xmlbuf->ptr))
+        xmlbuf->ptr++;
+
+    if (xmlbuf->ptr == xmlbuf->end) return FALSE;
+
+    if (*xmlbuf->ptr == '/')
+    {
+        xmlbuf->ptr++;
+        if (xmlbuf->ptr == xmlbuf->end || *xmlbuf->ptr != '>')
+            return FALSE;
+
+        xmlbuf->ptr++;
+        *end = TRUE;
+        *error = FALSE;
+        return FALSE;
+    }
+
+    if (*xmlbuf->ptr == '>')
+    {
+        xmlbuf->ptr++;
+        *error = FALSE;
+        return FALSE;
+    }
+
+    for (ptr = xmlbuf->ptr;
+         ptr < xmlbuf->end && *ptr != '=' && *ptr != '>' && !isspace(*ptr);
+         ptr++)
+        ;
+
+    if (ptr == xmlbuf->end || *ptr != '=') return FALSE;
+
+    name->ptr = xmlbuf->ptr;
+    name->len = ptr-xmlbuf->ptr;
+    xmlbuf->ptr = ptr;
+
+    ptr++;
+    if (ptr == xmlbuf->end || *ptr != '\"') return FALSE;
+
+    value->ptr = ++ptr;
+    if (ptr == xmlbuf->end) return FALSE;
+
+    ptr = memchr(ptr, '\"', xmlbuf->end - ptr);
+    if (!ptr)
+    {
+        xmlbuf->ptr = xmlbuf->end;
+        return FALSE;
+    }
+
+    value->len = ptr - value->ptr;
+    xmlbuf->ptr = ptr + 1;
+
+    if (xmlbuf->ptr == xmlbuf->end) return FALSE;
+
+    *error = FALSE;
+    return TRUE;
+}
+
 static BOOL next_xml_elem(xmlbuf_t* xmlbuf, xmlstr_t* elem)
 {
     const char* ptr;
@@ -288,6 +405,193 @@ static BOOL next_xml_elem(xmlbuf_t* xmlbuf, xmlstr_t* elem)
     return xmlbuf->ptr != xmlbuf->end;
 }
 
+/* major.minor.build.revision */
+static BOOL parse_version(const xmlstr_t* str, struct version* version)
+{
+    LPCSTR      curr;
+    ULONG*      where = &version->major;
+
+    /* major.minor.build.revision */
+    version->major = version->minor = version->build = version->revision = 0x10000;
+    for (curr = str->ptr; curr < str->ptr + str->len; curr++)
+    {
+        if (*curr >= '0' && *curr <= '9')
+        {
+            if (*where == 0x10000) *where = 0;
+            if ((*where) * 10 + *curr - '0' >= 0x10000) break;
+            *where = (*where) * 10 + *curr - '0';
+        }
+        else if (*curr == '.') where++; /* FIXME: hackish */
+        else break;
+    }
+    if (version->major == 0x10000 || version->minor == 0x10000 ||
+        version->build == 0x10000 || version->revision == 0x10000 ||
+        curr < str->ptr + str->len)
+    {
+        WARN("Wrong version definition in manifest file (%s)\n",
+             debugstr_xmlstr(str));
+        return FALSE;
+    }
+    return TRUE;
+}
+
+static BOOL parse_expect_elem(xmlbuf_t* xmlbuf, const char* name)
+{
+    xmlstr_t    elem;
+    return next_xml_elem(xmlbuf, &elem) && xmlstr_cmp(&elem, name);
+}
+
+static BOOL parse_expect_no_attr(xmlbuf_t* xmlbuf, BOOL* end)
+{
+    xmlstr_t    attr_name, attr_value;
+    BOOL        error;
+
+    if (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, end))
+    {
+        WARN("unexpected attr %s=%s\n", debugstr_xmlstr(&attr_name),
+             debugstr_xmlstr(&attr_value));
+        return FALSE;
+    }
+
+    return !error;
+}
+
+static BOOL parse_end_element(xmlbuf_t *xmlbuf)
+{
+    BOOL end = FALSE;
+    return parse_expect_no_attr(xmlbuf, &end) && !end;
+}
+
+static BOOL parse_assembly_identity_elem(xmlbuf_t* xmlbuf, struct actctx* actctx,
+                                         struct assembly_identity* ai)
+{
+    xmlstr_t    attr_name, attr_value;
+    BOOL        end = FALSE, error;
+
+    TRACE("\n");
+
+    memset(ai, 0, sizeof(*ai));
+    while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+    {
+        if (xmlstr_cmp(&attr_name, NAME_ATTR))
+        {
+            if (!(ai->name = strdupXW(&attr_value))) return FALSE;
+        }
+        else if (xmlstr_cmp(&attr_name, VERSION_ATTR))
+        {
+            if (!parse_version(&attr_value, &ai->version))
+                return FALSE;
+        }
+        else if (xmlstr_cmp(&attr_name, TYPE_ATTR))
+        {
+            if (!xmlstr_cmp(&attr_value, "win32"))
+            {
+                WARN("wrong type attr %s\n", debugstr_xmlstr(&attr_value));
+                return FALSE;
+            }
+            ai->type = TYPE_WIN32;
+        }
+        else if (xmlstr_cmp(&attr_name, PROCESSORARCHITECTURE_ATTR))
+        {
+            if (!xmlstr_icmp(&attr_value, "x86"))
+            {
+                WARN("wrong processorArchitecture attr %s\n",
+                     debugstr_xmlstr(&attr_value));
+                return FALSE;
+            }
+            ai->arch = ARCH_X86;
+        }
+        else
+        {
+            WARN("unknown attr %s=%s\n", debugstr_xmlstr(&attr_name),
+                 debugstr_xmlstr(&attr_value));
+            return FALSE;
+        }
+    }
+
+    if (error || end) return end;
+    return parse_expect_elem(xmlbuf, ELEM_END(ASSEMBLYIDENTITY_ELEM)) && parse_end_element(xmlbuf);
+}
+
+static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
+                                struct assembly* assembly,
+                                struct assembly_identity* expected_ai)
+{
+    xmlstr_t    attr_name, attr_value, elem;
+    BOOL        end = FALSE, error, version = FALSE, xmlns = FALSE, ret = TRUE;
+    struct assembly_identity ai;
+
+    TRACE("(%p)\n", xmlbuf);
+
+    while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+    {
+        if (xmlstr_cmp(&attr_name, MANIFESTVERSION_ATTR))
+        {
+            if (!xmlstr_cmp(&attr_value, "1.0"))
+            {
+                WARN("wrong version %s\n", debugstr_xmlstr(&attr_value));
+                return FALSE;
+            }
+            version = TRUE;
+        }
+        else if (xmlstr_cmp(&attr_name, XMLNS_ATTR))
+        {
+            if (!xmlstr_cmp(&attr_value, MANIFEST_NAMESPACE))
+            {
+                WARN("wrong namespace %s\n", debugstr_xmlstr(&attr_value));
+                return FALSE;
+            }
+            xmlns = TRUE;
+        }
+        else
+        {
+            WARN("wrong attr %s=%s\n", debugstr_xmlstr(&attr_name),
+                 debugstr_xmlstr(&attr_value));
+            return FALSE;
+        }
+    }
+
+    if (error || end || !xmlns || !version) return FALSE;
+    if (!next_xml_elem(xmlbuf, &elem)) return FALSE;
+
+    if (!xmlstr_cmp(&elem, ASSEMBLYIDENTITY_ELEM))
+    {
+        WARN("expected assemblyIdentity element, got %s\n", debugstr_xmlstr(&elem));
+        return FALSE;
+    }
+
+    if (!parse_assembly_identity_elem(xmlbuf, acl->actctx, &ai)) return FALSE;
+
+    if (expected_ai)
+    {
+        /* FIXME: more tests */
+        if (assembly->type == ASSEMBLY_MANIFEST &&
+            memcmp(&ai.version, &expected_ai->version, sizeof(ai.version)))
+        {
+            WARN("wrong version\n");
+            return FALSE;
+        }
+    }
+
+    assembly->id = ai;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp(&elem, ELEM_END(ASSEMBLY_ELEM)))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else
+        {
+            WARN("wrong element %s\n", debugstr_xmlstr(&elem));
+            ret = FALSE;
+        }
+    }
+
+    return ret;
+}
+
 static BOOL parse_xml_header(xmlbuf_t* xmlbuf)
 {
     /* FIXME: parse attibutes */
@@ -319,6 +623,21 @@ static DWORD parse_manifest(struct actctx_loader* acl, struct assembly_identity*
         (!parse_xml_header(xmlbuf) || !next_xml_elem(xmlbuf, &elem)))
         return ERROR_SXS_CANT_GEN_ACTCTX;
 
+    if (!xmlstr_cmp(&elem, ASSEMBLY_ELEM))
+    {
+        WARN("root element is %s, not <assembly>\n", debugstr_xmlstr(&elem));
+        return ERROR_SXS_CANT_GEN_ACTCTX;
+    }
+
+    if (!parse_assembly_elem(xmlbuf, acl, assembly, ai))
+        return ERROR_SXS_CANT_GEN_ACTCTX;
+
+    if (next_xml_elem(xmlbuf, &elem))
+    {
+        WARN("unexpected element %s\n", debugstr_xmlstr(&elem));
+        return ERROR_SXS_CANT_GEN_ACTCTX;
+    }
+
     if (xmlbuf->ptr != xmlbuf->end)
     {
         WARN("parse error\n");





More information about the wine-patches mailing list