]> git.saurik.com Git - cycript.git/blame - sig/parse.cpp
Add all supported binding API headers to analysis.
[cycript.git] / sig / parse.cpp
CommitLineData
b3378a02 1/* Cycript - Optimizing JavaScript Compiler/Runtime
c1d3e52e 2 * Copyright (C) 2009-2015 Jay Freeman (saurik)
b4aa79af
JF
3*/
4
f95d2598 5/* GNU Affero General Public License, Version 3 {{{ */
b4aa79af 6/*
f95d2598
JF
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
c15969fd 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
f95d2598
JF
15 * GNU Affero General Public License for more details.
16
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
b3378a02 19**/
b4aa79af
JF
20/* }}} */
21
ea2d184c 22#include "sig/parse.hpp"
37954781
JF
23#include "Error.hpp"
24
25#include <cstdio>
26#include <cstdlib>
27#include <cstring>
9a39f705 28#include <sstream>
ea2d184c
JF
29
30namespace sig {
31
b799113b
JF
32void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback);
33struct Type *Parse_(CYPool &pool, const char **name, char eos, bool named, Callback callback);
b21525c7
JF
34
35
ea2d184c 36/* XXX: I really screwed up this time */
b799113b 37void *prealloc_(CYPool &pool, void *odata, size_t osize, size_t nsize) {
0cbeddf8 38 void *ndata(pool.malloc<void>(nsize));
ea2d184c
JF
39 memcpy(ndata, odata, osize);
40 return ndata;
41}
42
b799113b 43void Parse_(CYPool &pool, struct Signature *signature, const char **name, char eos, Callback callback) {
ea2d184c
JF
44 _assert(*name != NULL);
45
f33b048a
JF
46 // XXX: this is just a stupid check :(
47 bool named(**name == '"');
ea2d184c
JF
48
49 signature->elements = NULL;
50 signature->count = 0;
51
52 for (;;) {
53 if (**name == eos) {
54 ++*name;
55 return;
56 }
57
58 signature->elements = (struct Element *) prealloc_(pool, signature->elements, signature->count * sizeof(struct Element), (signature->count + 1) * sizeof(struct Element));
59 _assert(signature->elements != NULL);
60
61 struct Element *element = &signature->elements[signature->count++];
62
63 if (**name != '"')
64 element->name = NULL;
65 else {
a815a4d6 66 const char *quote = strchr(++*name, '"');
b799113b 67 element->name = pool.strmemdup(*name, quote - *name);
ea2d184c
JF
68 *name = quote + 1;
69 }
70
f33b048a 71 element->type = Parse_(pool, name, eos, named, callback);
ea2d184c
JF
72
73 if (**name < '0' || **name > '9')
74 element->offset = _not(size_t);
75 else {
76 element->offset = 0;
77
78 do
79 element->offset = element->offset * 10 + (*(*name)++ - '0');
80 while (**name >= '0' && **name <= '9');
81 }
82 }
83}
84
0559abf8
JF
85Type *Parse_(CYPool &pool, const char **encoding, char eos, bool named, Callback callback) {
86 char next = *(*encoding)++;
ea2d184c 87
0559abf8
JF
88 Type *type;
89 uint8_t flags(0);
ea2d184c
JF
90
91 parse:
92 switch (next) {
0559abf8
JF
93 case '?': type = new(pool) Unknown(); break;
94 case '#': type = new(pool) Meta(); break;
ea2d184c
JF
95
96 case '(':
0559abf8 97 type = new(pool) Aggregate(true);
ea2d184c
JF
98 next = ')';
99 goto aggregate;
100
0559abf8
JF
101 case '*': type = new(pool) String(); break;
102 case ':': type = new(pool) Selector(); break;
ea2d184c 103
ecf94af8 104 case '@': {
0559abf8 105 char next(**encoding);
ecf94af8
JF
106
107 if (next == '?') {
0559abf8
JF
108 type = new(pool) Block();
109 ++*encoding;
ecf94af8 110 } else {
0559abf8
JF
111 const char *name;
112 if (next != '"')
113 name = NULL;
114 else {
115 const char *quote = strchr(*encoding + 1, '"');
506aad76 116 if (quote == NULL) {
0559abf8 117 printf("unterminated specific id type {%s}\n", *encoding - 10);
506aad76
JF
118 _assert(false);
119 } else if (!named || quote[1] == eos || quote[1] == '"') {
0559abf8
JF
120 name = pool.strmemdup(*encoding + 1, quote - *encoding - 1);
121 *encoding = quote + 1;
122 } else {
123 name = NULL;
ecf94af8 124 }
ea2d184c 125 }
0559abf8
JF
126
127 type = new(pool) Object(name);
ea2d184c
JF
128 }
129
ecf94af8 130 } break;
ea2d184c 131
0559abf8
JF
132 case 'B': type = new(pool) Primitive<bool>(); break;
133 case 'C': type = new(pool) Primitive<unsigned char>(); break;
134 case 'I': type = new(pool) Primitive<unsigned int>(); break;
135 case 'L': type = new(pool) Primitive<unsigned long>(); break;
136 case 'Q': type = new(pool) Primitive<unsigned long long>(); break;
137 case 'S': type = new(pool) Primitive<unsigned short>(); break;
138
139 case '[': {
140 size_t size(strtoul(*encoding, (char **) encoding, 10));
141 type = new(pool) Array(*Parse_(pool, encoding, eos, false, callback), size);
142 if (**encoding != ']') {
143 printf("']' != \"%s\"\n", *encoding);
ea2d184c
JF
144 _assert(false);
145 }
0559abf8
JF
146 ++*encoding;
147 } break;
ea2d184c
JF
148
149 case '^':
0559abf8
JF
150 if (**encoding == '"')
151 _assert(false); // XXX: why is this here?!?
152 else {
153 type = Parse_(pool, encoding, eos, named, callback);
154 Aggregate *aggregate(dynamic_cast<Aggregate *>(type));
155 if (aggregate != NULL && strcmp(aggregate->name, "_objc_class") == 0)
156 type = new(pool) Meta();
157 else
158 type = new(pool) Pointer(*type);
159 }
ea2d184c
JF
160 break;
161
162 case 'b':
0559abf8 163 type = new(pool) Bits(strtoul(*encoding, (char **) encoding, 10));
ea2d184c
JF
164 break;
165
0559abf8
JF
166 case 'c': type = new(pool) Primitive<signed char>(); break;
167 case 'd': type = new(pool) Primitive<double>(); break;
168 case 'f': type = new(pool) Primitive<float>(); break;
169 case 'i': type = new(pool) Primitive<signed int>(); break;
170 case 'l': type = new(pool) Primitive<signed long>(); break;
171 case 'q': type = new(pool) Primitive<signed long long>(); break;
172 case 's': type = new(pool) Primitive<short>(); break;
173 case 'v': type = new(pool) Void(); break;
f61f9da6 174
ea2d184c 175 case '{':
0559abf8 176 type = new(pool) Aggregate(false);
ea2d184c
JF
177 next = '}';
178 goto aggregate;
179
180 aggregate: {
0559abf8
JF
181 Aggregate *aggregate(static_cast<Aggregate *>(type));
182
ea2d184c 183 char end = next;
0559abf8
JF
184 const char *begin = *encoding;
185 do next = *(*encoding)++;
ea2d184c
JF
186 while (
187 next != '=' &&
188 next != '}'
189 );
0559abf8 190 size_t length = *encoding - begin - 1;
ea2d184c 191 if (strncmp(begin, "?", length) != 0)
0559abf8 192 aggregate->name = (char *) pool.strmemdup(begin, length);
f33b048a 193
9814ec39 194 if (next == '=')
0559abf8
JF
195 Parse_(pool, &aggregate->signature, encoding, end, callback);
196
197 // XXX: this is a hack to support trivial unions
198 if (aggregate->signature.count <= 1)
199 aggregate->overlap = false;
200
201 if (callback != NULL)
202 type = (*callback)(pool, aggregate);
ea2d184c
JF
203 } break;
204
140fd60d
JF
205 case 'r': flags |= JOC_TYPE_CONST; goto next;
206
0559abf8 207 case 'n': flags |= JOC_TYPE_IN; goto next;
140fd60d 208 case 'N': flags |= JOC_TYPE_INOUT; goto next;
0559abf8 209 case 'o': flags |= JOC_TYPE_OUT; goto next;
140fd60d 210 case 'O': flags |= JOC_TYPE_BYCOPY; goto next;
0559abf8 211 case 'R': flags |= JOC_TYPE_BYREF; goto next;
0559abf8 212 case 'V': flags |= JOC_TYPE_ONEWAY; goto next;
ea2d184c
JF
213
214 next:
0559abf8 215 next = *(*encoding)++;
ea2d184c
JF
216 goto parse;
217 break;
218
219 default:
0559abf8 220 printf("invalid type character: '%c' {%s}\n", next, *encoding - 10);
ea2d184c
JF
221 _assert(false);
222 }
223
0559abf8 224 type->flags = flags;
9814ec39 225
ea2d184c
JF
226 return type;
227}
228
b799113b 229void Parse(CYPool &pool, struct Signature *signature, const char *name, Callback callback) {
ea2d184c 230 const char *temp = name;
f33b048a 231 Parse_(pool, signature, &temp, '\0', callback);
ea2d184c
JF
232 _assert(temp[-1] == '\0');
233}
234
0559abf8 235const char *Unparse(CYPool &pool, const struct Signature *signature) {
ea2d184c
JF
236 const char *value = "";
237 size_t offset;
238
239 for (offset = 0; offset != signature->count; ++offset) {
b21525c7 240 const char *type = Unparse(pool, signature->elements[offset].type);
0cbeddf8 241 value = pool.strcat(value, type, NULL);
ea2d184c
JF
242 }
243
244 return value;
245}
246
0559abf8
JF
247template <>
248const char *Primitive<bool>::Encode(CYPool &pool) const {
249 return "B";
250}
9a39f705 251
0559abf8
JF
252template <>
253const char *Primitive<char>::Encode(CYPool &pool) const {
254 return "c";
255}
ea2d184c 256
0559abf8
JF
257template <>
258const char *Primitive<double>::Encode(CYPool &pool) const {
259 return "d";
260}
9a39f705 261
0559abf8
JF
262template <>
263const char *Primitive<float>::Encode(CYPool &pool) const {
264 return "f";
265}
266
267template <>
268const char *Primitive<signed char>::Encode(CYPool &pool) const {
269 return "c";
270}
271
272template <>
273const char *Primitive<signed int>::Encode(CYPool &pool) const {
274 return "i";
275}
276
277template <>
278const char *Primitive<signed long int>::Encode(CYPool &pool) const {
279 return "l";
280}
281
282template <>
283const char *Primitive<signed long long int>::Encode(CYPool &pool) const {
284 return "q";
285}
286
287template <>
288const char *Primitive<signed short int>::Encode(CYPool &pool) const {
289 return "s";
290}
291
292template <>
293const char *Primitive<unsigned char>::Encode(CYPool &pool) const {
294 return "C";
295}
296
297template <>
298const char *Primitive<unsigned int>::Encode(CYPool &pool) const {
299 return "I";
300}
301
302template <>
303const char *Primitive<unsigned long int>::Encode(CYPool &pool) const {
304 return "L";
305}
306
307template <>
308const char *Primitive<unsigned long long int>::Encode(CYPool &pool) const {
309 return "Q";
310}
311
312template <>
313const char *Primitive<unsigned short int>::Encode(CYPool &pool) const {
314 return "S";
315}
316
317const char *Void::Encode(CYPool &pool) const {
318 return "v";
319}
320
321const char *Unknown::Encode(CYPool &pool) const {
322 return "?";
323}
324
325const char *String::Encode(CYPool &pool) const {
326 return "*";
327}
ea2d184c 328
0559abf8
JF
329const char *Meta::Encode(CYPool &pool) const {
330 return "#";
ea2d184c
JF
331}
332
0559abf8
JF
333const char *Selector::Encode(CYPool &pool) const {
334 return ":";
335}
336
337const char *Bits::Encode(CYPool &pool) const {
338 return pool.strcat("b", pool.itoa(size), NULL);
339}
340
341const char *Pointer::Encode(CYPool &pool) const {
342 return pool.strcat("^", type.Encode(pool), NULL);
343}
344
345const char *Array::Encode(CYPool &pool) const {
346 return pool.strcat("[", pool.itoa(size), type.Encode(pool), "]", NULL);
347}
348
349const char *Object::Encode(CYPool &pool) const {
350 return name == NULL ? "@" : pool.strcat("@\"", name, "\"", NULL);
351}
352
353const char *Aggregate::Encode(CYPool &pool) const {
354 return pool.strcat(overlap ? "(" : "{", name == NULL ? "?" : name, "=", Unparse(pool, &signature), overlap ? ")" : "}", NULL);
355}
356
357const char *Function::Encode(CYPool &pool) const {
358 return "?";
359}
360
361const char *Block::Encode(CYPool &pool) const {
362 return "@?";
363}
51714815 364
0559abf8
JF
365const char *Unparse(CYPool &pool, const struct Type *type) {
366 const char *base(type->Encode(pool));
51714815
JF
367 if (type->flags == 0)
368 return base;
369
370 #define iovec_(base, size) \
371 (struct iovec) {const_cast<char *>(base), size}
372
0cbeddf8
JF
373 size_t size(strlen(base));
374 char buffer[7 + size];
375 size_t offset(0);
51714815
JF
376
377 if ((type->flags & JOC_TYPE_INOUT) != 0)
0cbeddf8 378 buffer[offset++] = 'N';
51714815 379 if ((type->flags & JOC_TYPE_IN) != 0)
0cbeddf8 380 buffer[offset++] = 'n';
51714815 381 if ((type->flags & JOC_TYPE_BYCOPY) != 0)
0cbeddf8 382 buffer[offset++] = 'O';
51714815 383 if ((type->flags & JOC_TYPE_OUT) != 0)
0cbeddf8 384 buffer[offset++] = 'o';
51714815 385 if ((type->flags & JOC_TYPE_BYREF) != 0)
0cbeddf8 386 buffer[offset++] = 'R';
51714815 387 if ((type->flags & JOC_TYPE_CONST) != 0)
0cbeddf8 388 buffer[offset++] = 'r';
51714815 389 if ((type->flags & JOC_TYPE_ONEWAY) != 0)
0cbeddf8 390 buffer[offset++] = 'V';
51714815 391
0cbeddf8
JF
392 memcpy(buffer + offset, base, size);
393 return pool.strmemdup(buffer, offset + size);
51714815
JF
394}
395
ea2d184c 396}