X-Git-Url: https://git.saurik.com/cycript.git/blobdiff_plain/b21525c7b2b9f64150f97e79f1f0788edbc7b3bf..11bc0b9e5dc0120f007ed9b2bfc7810e8a2b0162:/sig/parse.cpp diff --git a/sig/parse.cpp b/sig/parse.cpp index a786039..b78015d 100644 --- a/sig/parse.cpp +++ b/sig/parse.cpp @@ -1,34 +1,50 @@ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include "minimal/stdlib.h" - -#include - -#include +/* Cycript - The Truly Universal Scripting Language + * Copyright (C) 2009-2016 Jay Freeman (saurik) +*/ + +/* GNU Affero General Public License, Version 3 {{{ */ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . +**/ +/* }}} */ #include "sig/parse.hpp" +#include "Error.hpp" -namespace sig { +#include +#include +#include +#include -void (*sig_aggregate)(apr_pool_t *pool, enum Primitive primitive, const char *name, struct Signature *signature, const char *types) = NULL; +namespace sig { -void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos); -struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named); +void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback); +struct Type *Parse_(CYPool &pool, const char **name, char eos, bool named, Callback callback); /* XXX: I really screwed up this time */ -void *prealloc_(apr_pool_t *pool, void *odata, size_t osize, size_t nsize) { - void *ndata = apr_palloc(pool, nsize); +void *prealloc_(CYPool &pool, void *odata, size_t osize, size_t nsize) { + void *ndata(pool.malloc(nsize)); memcpy(ndata, odata, osize); return ndata; } -void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, char eos) { +void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback) { _assert(*name != NULL); - bool named = **name == '"'; + // XXX: this is just a stupid check :( + bool named(**name == '"'); signature->elements = NULL; signature->count = 0; @@ -47,12 +63,12 @@ void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, ch if (**name != '"') element->name = NULL; else { - char *quote = strchr(++*name, '"'); - element->name = apr_pstrmemdup(pool, *name, quote - *name); + const char *quote = strchr(++*name, '"'); + element->name = pool.strmemdup(*name, quote - *name); *name = quote + 1; } - element->type = Parse_(pool, name, eos, named); + element->type = Parse_(pool, name, eos, named, callback); if (**name < '0' || **name > '9') element->offset = _not(size_t); @@ -66,197 +82,329 @@ void Parse_(apr_pool_t *pool, struct Signature *signature, const char **name, ch } } -struct Type *Parse_(apr_pool_t *pool, const char **name, char eos, bool named) { - char next = *(*name)++; - if (next == '?') - return NULL; +Type *Parse_(CYPool &pool, const char **encoding, char eos, bool named, Callback callback) { + char next = *(*encoding)++; - struct Type *type = (struct Type *) apr_palloc(pool, sizeof(struct Type)); - _assert(type != NULL); - memset(type, 0, sizeof(struct Type)); + Type *type; + uint8_t flags(0); parse: switch (next) { - case '#': type->primitive = typename_P; break; + case '?': type = new(pool) Unknown(); break; + +#ifdef CY_OBJECTIVEC + case '#': type = new(pool) Meta(); break; +#endif case '(': - type->primitive = union_P; + type = new(pool) Aggregate(true); next = ')'; goto aggregate; - case '*': type->primitive = string_P; break; - case ':': type->primitive = selector_P; break; + case '*': type = new(pool) String(); break; + +#ifdef CY_OBJECTIVEC + case ':': type = new(pool) Selector(); break; - case '@': - if (**name == '"') { - char *quote = strchr(*name + 1, '"'); - if (!named || quote[1] == eos || quote[1] == '"') { - type->name = apr_pstrmemdup(pool, *name + 1, quote - *name - 1); - *name = quote + 1; + case '@': { + char next(**encoding); + + if (next == '?') { + type = new(pool) Block(); + ++*encoding; + } else { + const char *name; + if (next != '"') + name = NULL; + else { + const char *quote = strchr(*encoding + 1, '"'); + if (quote == NULL) { + printf("unterminated specific id type {%s}\n", *encoding - 10); + _assert(false); + } else if (!named || quote[1] == eos || quote[1] == '"') { + name = pool.strmemdup(*encoding + 1, quote - *encoding - 1); + *encoding = quote + 1; + } else { + name = NULL; + } } + + type = new(pool) Object(name); } - type->primitive = object_P; - break; + } break; +#endif - case 'B': type->primitive = boolean_P; break; - case 'C': type->primitive = uchar_P; break; - case 'I': type->primitive = uint_P; break; - case 'L': type->primitive = ulong_P; break; - case 'Q': type->primitive = ulonglong_P; break; - case 'S': type->primitive = ushort_P; break; - - case '[': - type->primitive = array_P; - type->data.data.size = strtoul(*name, (char **) name, 10); - type->data.data.type = Parse_(pool, name, eos, false); - if (**name != ']') { - printf("']' != \"%s\"\n", *name); + case 'B': type = new(pool) Primitive(); break; + case 'C': type = new(pool) Primitive(); break; + case 'I': type = new(pool) Primitive(); break; + case 'L': type = new(pool) Primitive(); break; + case 'Q': type = new(pool) Primitive(); break; + case 'S': type = new(pool) Primitive(); break; + + case '[': { + size_t size(strtoul(*encoding, (char **) encoding, 10)); + type = new(pool) Array(*Parse_(pool, encoding, eos, false, callback), size); + if (**encoding != ']') { + printf("']' != \"%s\"\n", *encoding); _assert(false); } - ++*name; - break; + ++*encoding; + } break; case '^': - type->primitive = pointer_P; - if (**name == 'v') { - type->data.data.type = NULL; - ++*name; - } else if (**name == '"') { - type->data.data.type = NULL; - } else { - type->data.data.type = Parse_(pool, name, eos, named); + if (**encoding == '"') + _assert(false); // XXX: why is this here?!? + else { + type = Parse_(pool, encoding, eos, named, callback); +#ifdef CY_OBJECTIVEC + Aggregate *aggregate(dynamic_cast(type)); + if (aggregate != NULL && strcmp(aggregate->name, "_objc_class") == 0) + type = new(pool) Meta(); + else +#endif + type = new(pool) Pointer(*type); } break; case 'b': - type->primitive = bit_P; - type->data.data.size = strtoul(*name, (char **) name, 10); + type = new(pool) Bits(strtoul(*encoding, (char **) encoding, 10)); break; - case 'c': type->primitive = char_P; break; - case 'd': type->primitive = double_P; break; - case 'f': type->primitive = float_P; break; - case 'i': type->primitive = int_P; break; - case 'l': type->primitive = long_P; break; - case 'q': type->primitive = longlong_P; break; - case 's': type->primitive = short_P; break; - case 'v': type->primitive = void_P; break; + case 'c': type = new(pool) Primitive(); break; + case 'd': type = new(pool) Primitive(); break; + case 'f': type = new(pool) Primitive(); break; + case 'i': type = new(pool) Primitive(); break; + case 'l': type = new(pool) Primitive(); break; + case 'q': type = new(pool) Primitive(); break; + case 's': type = new(pool) Primitive(); break; + case 'v': type = new(pool) Void(); break; case '{': - type->primitive = struct_P; + type = new(pool) Aggregate(false); next = '}'; goto aggregate; aggregate: { + Aggregate *aggregate(static_cast(type)); + char end = next; - const char *begin = *name; - do next = *(*name)++; + const char *begin = *encoding; + do next = *(*encoding)++; while ( next != '=' && next != '}' ); - size_t length = *name - begin - 1; + size_t length = *encoding - begin - 1; if (strncmp(begin, "?", length) != 0) - type->name = (char *) apr_pstrmemdup(pool, begin, length); - else - type->name = NULL; + aggregate->name = (char *) pool.strmemdup(begin, length); - char *types; - if (next != '=') - types = NULL; - else { - const char *temp = *name; - Parse_(pool, &type->data.signature, name, end); - types = (char *) apr_pstrmemdup(pool, temp, *name - temp - 1); - } + if (next == '=') + Parse_(pool, &aggregate->signature, encoding, end, callback); - if (type->name != NULL && sig_aggregate != NULL) { - char *angle = strchr(type->name, '<'); - if (angle == NULL) - (*sig_aggregate)(pool, type->primitive, type->name, &type->data.signature, types); - else { - angle = (char *) apr_pstrmemdup(pool, type->name, angle - type->name); - (*sig_aggregate)(pool, type->primitive, angle, &type->data.signature, types); - } - } + // XXX: this is a hack to support trivial unions + if (aggregate->signature.count <= 1) + aggregate->overlap = false; + + if (callback != NULL) + type = (*callback)(pool, aggregate); } break; - case 'N': type->flags |= JOC_TYPE_INOUT; goto next; - case 'n': type->flags |= JOC_TYPE_IN; goto next; - case 'O': type->flags |= JOC_TYPE_BYCOPY; goto next; - case 'o': type->flags |= JOC_TYPE_OUT; goto next; - case 'R': type->flags |= JOC_TYPE_BYREF; goto next; - case 'r': type->flags |= JOC_TYPE_CONST; goto next; - case 'V': type->flags |= JOC_TYPE_ONEWAY; goto next; + case 'r': flags |= JOC_TYPE_CONST; goto next; + + case 'n': flags |= JOC_TYPE_IN; goto next; + case 'N': flags |= JOC_TYPE_INOUT; goto next; + case 'o': flags |= JOC_TYPE_OUT; goto next; + case 'O': flags |= JOC_TYPE_BYCOPY; goto next; + case 'R': flags |= JOC_TYPE_BYREF; goto next; + case 'V': flags |= JOC_TYPE_ONEWAY; goto next; next: - next = *(*name)++; + next = *(*encoding)++; goto parse; break; default: - printf("invalid type character: '%c' {%s}\n", next, *name - 10); + printf("invalid type character: '%c' {%s}\n", next, *encoding - 10); _assert(false); } + type->flags = flags; + return type; } -void Parse(apr_pool_t *pool, struct Signature *signature, const char *name) { +void Parse(CYPool &pool, struct Signature *signature, const char *name, Callback callback) { const char *temp = name; - Parse_(pool, signature, &temp, '\0'); + Parse_(pool, signature, &temp, '\0', callback); _assert(temp[-1] == '\0'); } -const char *Unparse(apr_pool_t *pool, struct Signature *signature) { +const char *Unparse(CYPool &pool, const struct Signature *signature) { const char *value = ""; size_t offset; for (offset = 0; offset != signature->count; ++offset) { const char *type = Unparse(pool, signature->elements[offset].type); - value = apr_pstrcat(pool, value, type, NULL); + value = pool.strcat(value, type, NULL); } return value; } -const char *Unparse(apr_pool_t *pool, struct Type *type) { - if (type == NULL) - return "?"; - else switch (type->primitive) { - case typename_P: return "#"; - case union_P: return apr_psprintf(pool, "(%s)", Unparse(pool, &type->data.signature)); - case string_P: return "*"; - case selector_P: return ":"; - case object_P: return type->name == NULL ? "@" : apr_psprintf(pool, "@\"%s\"", type->name); - case boolean_P: return "B"; - case uchar_P: return "C"; - case uint_P: return "I"; - case ulong_P: return "L"; - case ulonglong_P: return "Q"; - case ushort_P: return "S"; - - case array_P: { - const char *value = Unparse(pool, type->data.data.type); - return apr_psprintf(pool, "[%lu%s]", type->data.data.size, value); - } break; +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "B"; +} - case pointer_P: return apr_psprintf(pool, "^%s", type->data.data.type == NULL ? "" : Unparse(pool, type->data.data.type)); - case bit_P: return apr_psprintf(pool, "b%zu", type->data.data.size); - case char_P: return "c"; - case double_P: return "d"; - case float_P: return "f"; - case int_P: return "i"; - case long_P: return "l"; - case longlong_P: return "q"; - case short_P: return "s"; - case void_P: return "v"; - case struct_P: return apr_psprintf(pool, "{%s=%s}", type->name == NULL ? "?" : type->name, Unparse(pool, &type->data.signature)); - } +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "c"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "d"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "f"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "c"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "i"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "l"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "q"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "s"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "C"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "I"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "L"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "Q"; +} + +template <> +const char *Primitive::Encode(CYPool &pool) const { + return "S"; +} + +const char *Void::Encode(CYPool &pool) const { + return "v"; +} + +const char *Unknown::Encode(CYPool &pool) const { + return "?"; +} + +const char *String::Encode(CYPool &pool) const { + return "*"; +} + +#ifdef CY_OBJECTIVEC +const char *Meta::Encode(CYPool &pool) const { + return "#"; +} + +const char *Selector::Encode(CYPool &pool) const { + return ":"; +} +#endif + +const char *Bits::Encode(CYPool &pool) const { + return pool.strcat("b", pool.itoa(size), NULL); +} + +const char *Pointer::Encode(CYPool &pool) const { + return pool.strcat("^", type.Encode(pool), NULL); +} + +const char *Array::Encode(CYPool &pool) const { + return pool.strcat("[", pool.itoa(size), type.Encode(pool), "]", NULL); +} + +#ifdef CY_OBJECTIVEC +const char *Object::Encode(CYPool &pool) const { + return name == NULL ? "@" : pool.strcat("@\"", name, "\"", NULL); +} +#endif + +const char *Aggregate::Encode(CYPool &pool) const { + return pool.strcat(overlap ? "(" : "{", name == NULL ? "?" : name, "=", Unparse(pool, &signature), overlap ? ")" : "}", NULL); +} + +const char *Function::Encode(CYPool &pool) const { + return "?"; +} + +#ifdef CY_OBJECTIVEC +const char *Block::Encode(CYPool &pool) const { + return "@?"; +} +#endif - _assert(false); - return NULL; +const char *Unparse(CYPool &pool, const struct Type *type) { + const char *base(type->Encode(pool)); + if (type->flags == 0) + return base; + + #define iovec_(base, size) \ + (struct iovec) {const_cast(base), size} + + size_t size(strlen(base)); + char buffer[7 + size]; + size_t offset(0); + + if ((type->flags & JOC_TYPE_INOUT) != 0) + buffer[offset++] = 'N'; + if ((type->flags & JOC_TYPE_IN) != 0) + buffer[offset++] = 'n'; + if ((type->flags & JOC_TYPE_BYCOPY) != 0) + buffer[offset++] = 'O'; + if ((type->flags & JOC_TYPE_OUT) != 0) + buffer[offset++] = 'o'; + if ((type->flags & JOC_TYPE_BYREF) != 0) + buffer[offset++] = 'R'; + if ((type->flags & JOC_TYPE_CONST) != 0) + buffer[offset++] = 'r'; + if ((type->flags & JOC_TYPE_ONEWAY) != 0) + buffer[offset++] = 'V'; + + memcpy(buffer + offset, base, size); + return pool.strmemdup(buffer, offset + size); } }