[PATCH 08/27] [Kernel32]: ActCtx: first shot at manifest parsing
Eric Pouech
eric.pouech at wanadoo.fr
Mon May 7 14:50:30 CDT 2007
From: Jacek Caban <jacek at codeweavers.com>
---
dlls/kernel32/actctx.c | 321 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 320 insertions(+), 1 deletions(-)
diff --git a/dlls/kernel32/actctx.c b/dlls/kernel32/actctx.c
index 4fbe5a4..57ef39e 100644
--- a/dlls/kernel32/actctx.c
+++ b/dlls/kernel32/actctx.c
@@ -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
{
LPCWSTR name;
struct version version;
+ enum assembly_id_type type;
+ enum assembly_id_arch arch;
};
enum assembly_type
@@ -124,11 +138,36 @@ static WCHAR* xstrdupW(const WCHAR* str)
return strcpyW(ptr, str);
}
-static BOOL xmlstr_cmp(xmlstr_t* xmlstr, const char* str)
+static WCHAR* xstrdupXW(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;
@@ -246,6 +285,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;
@@ -269,6 +386,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(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 = xstrdupXW(&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 */
@@ -300,6 +604,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