]> git.saurik.com Git - cycript.git/blob - sig/parse.cpp
This is getting seriously hot.
[cycript.git] / sig / parse.cpp
1 #ifndef _GNU_SOURCE
2 #define _GNU_SOURCE
3 #endif
4
5 #include "minimal/stdlib.h"
6
7 #include <apr-1/apr_strings.h>
8
9 #include <string.h>
10
11 #include "sig/parse.hpp"
12
13 namespace sig {
14
15 void (*sig_aggregate)(apr_pool_t *pool, enum Primitive primitive, const char *name, struct Signature *signature, const char *types) = NULL;
16
17 /* XXX: I really screwed up this time */
18 void *prealloc_(apr_pool_t *pool, void *odata, size_t osize, size_t nsize) {
19 void *ndata = apr_palloc(pool, nsize);
20 memcpy(ndata, odata, osize);
21 return ndata;
22 }
23
24 void sig_parse_signature(apr_pool_t *pool, struct Signature *signature, const char **name, char eos) {
25 _assert(*name != NULL);
26
27 bool named = **name == '"';
28
29 signature->elements = NULL;
30 signature->count = 0;
31
32 for (;;) {
33 if (**name == eos) {
34 ++*name;
35 return;
36 }
37
38 signature->elements = (struct Element *) prealloc_(pool, signature->elements, signature->count * sizeof(struct Element), (signature->count + 1) * sizeof(struct Element));
39 _assert(signature->elements != NULL);
40
41 struct Element *element = &signature->elements[signature->count++];
42
43 if (**name != '"')
44 element->name = NULL;
45 else {
46 char *quote = strchr(++*name, '"');
47 element->name = apr_pstrmemdup(pool, *name, quote - *name);
48 *name = quote + 1;
49 }
50
51 element->type = sig_parse_type(pool, name, eos, named);
52
53 if (**name < '0' || **name > '9')
54 element->offset = _not(size_t);
55 else {
56 element->offset = 0;
57
58 do
59 element->offset = element->offset * 10 + (*(*name)++ - '0');
60 while (**name >= '0' && **name <= '9');
61 }
62 }
63 }
64
65 struct Type *sig_parse_type(apr_pool_t *pool, const char **name, char eos, bool named) {
66 char next = *(*name)++;
67 if (next == '?')
68 return NULL;
69
70 struct Type *type = (struct Type *) apr_palloc(pool, sizeof(struct Type));
71 _assert(type != NULL);
72 memset(type, 0, sizeof(struct Type));
73
74 parse:
75 switch (next) {
76 case '#': type->primitive = typename_P; break;
77
78 case '(':
79 type->primitive = union_P;
80 next = ')';
81 goto aggregate;
82
83 case '*': type->primitive = string_P; break;
84 case ':': type->primitive = selector_P; break;
85
86 case '@':
87 if (**name == '"') {
88 char *quote = strchr(*name + 1, '"');
89 if (!named || quote[1] == eos || quote[1] == '"') {
90 type->name = apr_pstrmemdup(pool, *name + 1, quote - *name - 1);
91 *name = quote + 1;
92 }
93 }
94
95 type->primitive = object_P;
96 break;
97
98 case 'B': type->primitive = boolean_P; break;
99 case 'C': type->primitive = uchar_P; break;
100 case 'I': type->primitive = uint_P; break;
101 case 'L': type->primitive = ulong_P; break;
102 case 'Q': type->primitive = ulonglong_P; break;
103 case 'S': type->primitive = ushort_P; break;
104
105 case '[':
106 type->primitive = array_P;
107 type->data.data.size = strtoul(*name, (char **) name, 10);
108 type->data.data.type = sig_parse_type(pool, name, eos, false);
109 if (**name != ']') {
110 printf("']' != \"%s\"\n", *name);
111 _assert(false);
112 }
113 ++*name;
114 break;
115
116 case '^':
117 type->primitive = pointer_P;
118 if (**name == 'v') {
119 type->data.data.type = NULL;
120 ++*name;
121 } else if (**name == '"') {
122 type->data.data.type = NULL;
123 } else {
124 type->data.data.type = sig_parse_type(pool, name, eos, named);
125 }
126 break;
127
128 case 'b':
129 type->primitive = bit_P;
130 type->data.data.size = strtoul(*name, (char **) name, 10);
131 break;
132
133 case 'c': type->primitive = char_P; break;
134 case 'd': type->primitive = double_P; break;
135 case 'f': type->primitive = float_P; break;
136 case 'i': type->primitive = int_P; break;
137 case 'l': type->primitive = long_P; break;
138 case 'q': type->primitive = longlong_P; break;
139 case 's': type->primitive = short_P; break;
140 case 'v': type->primitive = void_P; break;
141
142 case '{':
143 type->primitive = struct_P;
144 next = '}';
145 goto aggregate;
146
147 aggregate: {
148 char end = next;
149 const char *begin = *name;
150 do next = *(*name)++;
151 while (
152 next != '=' &&
153 next != '}'
154 );
155 size_t length = *name - begin - 1;
156 if (strncmp(begin, "?", length) != 0)
157 type->name = (char *) apr_pstrmemdup(pool, begin, length);
158 else
159 type->name = NULL;
160
161 char *types;
162 if (next != '=')
163 types = NULL;
164 else {
165 const char *temp = *name;
166 sig_parse_signature(pool, &type->data.signature, name, end);
167 types = (char *) apr_pstrmemdup(pool, temp, *name - temp - 1);
168 }
169
170 if (type->name != NULL && sig_aggregate != NULL) {
171 char *angle = strchr(type->name, '<');
172 if (angle == NULL)
173 (*sig_aggregate)(pool, type->primitive, type->name, &type->data.signature, types);
174 else {
175 angle = (char *) apr_pstrmemdup(pool, type->name, angle - type->name);
176 (*sig_aggregate)(pool, type->primitive, angle, &type->data.signature, types);
177 }
178 }
179 } break;
180
181 case 'N': type->flags |= JOC_TYPE_INOUT; goto next;
182 case 'n': type->flags |= JOC_TYPE_IN; goto next;
183 case 'O': type->flags |= JOC_TYPE_BYCOPY; goto next;
184 case 'o': type->flags |= JOC_TYPE_OUT; goto next;
185 case 'R': type->flags |= JOC_TYPE_BYREF; goto next;
186 case 'r': type->flags |= JOC_TYPE_CONST; goto next;
187 case 'V': type->flags |= JOC_TYPE_ONEWAY; goto next;
188
189 next:
190 next = *(*name)++;
191 goto parse;
192 break;
193
194 default:
195 printf("invalid type character: '%c' {%s}\n", next, *name - 10);
196 _assert(false);
197 }
198
199 return type;
200 }
201
202 void Parse(apr_pool_t *pool, struct Signature *signature, const char *name) {
203 const char *temp = name;
204 sig_parse_signature(pool, signature, &temp, '\0');
205 _assert(temp[-1] == '\0');
206 }
207
208 const char *sig_unparse_signature(apr_pool_t *pool, struct Signature *signature) {
209 const char *value = "";
210 size_t offset;
211
212 for (offset = 0; offset != signature->count; ++offset) {
213 const char *type = sig_unparse_type(pool, signature->elements[offset].type);
214 value = apr_pstrcat(pool, value, type, NULL);
215 }
216
217 return value;
218 }
219
220 const char *sig_unparse_type(apr_pool_t *pool, struct Type *type) {
221 if (type == NULL)
222 return "?";
223 else switch (type->primitive) {
224 case typename_P: return "#";
225 case union_P: return apr_psprintf(pool, "(%s)", sig_unparse_signature(pool, &type->data.signature));
226 case string_P: return "*";
227 case selector_P: return ":";
228 case object_P: return type->name == NULL ? "@" : apr_psprintf(pool, "@\"%s\"", type->name);
229 case boolean_P: return "B";
230 case uchar_P: return "C";
231 case uint_P: return "I";
232 case ulong_P: return "L";
233 case ulonglong_P: return "Q";
234 case ushort_P: return "S";
235
236 case array_P: {
237 const char *value = sig_unparse_type(pool, type->data.data.type);
238 return apr_psprintf(pool, "[%lu%s]", type->data.data.size, value);
239 } break;
240
241 case pointer_P: return apr_psprintf(pool, "^%s", type->data.data.type == NULL ? "" : sig_unparse_type(pool, type->data.data.type));
242 case bit_P: return apr_psprintf(pool, "b%zu", type->data.data.size);
243 case char_P: return "c";
244 case double_P: return "d";
245 case float_P: return "f";
246 case int_P: return "i";
247 case long_P: return "l";
248 case longlong_P: return "q";
249 case short_P: return "s";
250 case void_P: return "v";
251 case struct_P: return apr_psprintf(pool, "{%s=%s}", type->name == NULL ? "?" : type->name, sig_unparse_signature(pool, &type->data.signature));
252 }
253
254 _assert(false);
255 return NULL;
256 }
257
258 }