]> git.saurik.com Git - cycript.git/blob - Library.cpp
apr_pstrdup used to return NULL when passed NULL.
[cycript.git] / Library.cpp
1 /* Cycript - Optimizing JavaScript Compiler/Runtime
2 * Copyright (C) 2009-2013 Jay Freeman (saurik)
3 */
4
5 /* GNU General Public License, Version 3 {{{ */
6 /*
7 * Cycript is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation, either version 3 of the License,
10 * or (at your option) any later version.
11 *
12 * Cycript is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Cycript. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <dlfcn.h>
23 #include <iconv.h>
24
25 #include "cycript.hpp"
26
27 #include "Pooling.hpp"
28
29 #include <sys/mman.h>
30
31 #include <iostream>
32 #include <ext/stdio_filebuf.h>
33 #include <set>
34 #include <map>
35 #include <iomanip>
36 #include <sstream>
37 #include <cmath>
38
39 #include "Parser.hpp"
40 #include "Cycript.tab.hh"
41
42 #include "Error.hpp"
43 #include "String.hpp"
44 #include "Execute.hpp"
45 #include "JavaScript.hpp"
46
47 /* C Strings {{{ */
48 template <typename Type_>
49 _finline size_t iconv_(size_t (*iconv)(iconv_t, Type_, size_t *, char **, size_t *), iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) {
50 return iconv(cd, const_cast<Type_>(inbuf), inbytesleft, outbuf, outbytesleft);
51 }
52
53 #ifdef __GLIBC__
54 #define UCS_2_INTERNAL "UCS-2"
55 #else
56 #define UCS_2_INTERNAL "UCS-2-INTERNAL"
57 #endif
58
59 CYUTF8String CYPoolUTF8String(CYPool &pool, CYUTF16String utf16) {
60 const char *in(reinterpret_cast<const char *>(utf16.data));
61
62 iconv_t conversion(_syscall(iconv_open("UTF-8", UCS_2_INTERNAL)));
63
64 // XXX: this is wrong
65 size_t size(utf16.size * 5);
66 char *out(new(pool) char[size]);
67 CYUTF8String utf8(out, size);
68
69 size = utf16.size * 2;
70 _syscall(iconv_(&iconv, conversion, const_cast<char **>(&in), &size, &out, &utf8.size));
71
72 *out = '\0';
73 utf8.size = out - utf8.data;
74
75 _syscall(iconv_close(conversion));
76
77 return utf8;
78 }
79
80 CYUTF16String CYPoolUTF16String(CYPool &pool, CYUTF8String utf8) {
81 const char *in(utf8.data);
82
83 iconv_t conversion(_syscall(iconv_open(UCS_2_INTERNAL, "UTF-8")));
84
85 // XXX: this is wrong
86 size_t size(utf8.size * 5);
87 uint16_t *temp(new (pool) uint16_t[size]);
88 CYUTF16String utf16(temp, size * 2);
89 char *out(reinterpret_cast<char *>(temp));
90
91 size = utf8.size;
92 _syscall(iconv_(&iconv, conversion, const_cast<char **>(&in), &size, &out, &utf16.size));
93
94 utf16.size = reinterpret_cast<uint16_t *>(out) - utf16.data;
95 temp[utf16.size] = 0;
96
97 _syscall(iconv_close(conversion));
98
99 return utf16;
100 }
101 /* }}} */
102 /* Index Offsets {{{ */
103 size_t CYGetIndex(const CYUTF8String &value) {
104 if (value.data[0] != '0') {
105 size_t index(0);
106 for (size_t i(0); i != value.size; ++i) {
107 if (!DigitRange_[value.data[i]])
108 return _not(size_t);
109 index *= 10;
110 index += value.data[i] - '0';
111 }
112 return index;
113 } else if (value.size == 1)
114 return 0;
115 else
116 return _not(size_t);
117 }
118
119 // XXX: this isn't actually right
120 bool CYGetOffset(const char *value, ssize_t &index) {
121 if (value[0] != '0') {
122 char *end;
123 index = strtol(value, &end, 10);
124 if (value + strlen(value) == end)
125 return true;
126 } else if (value[1] == '\0') {
127 index = 0;
128 return true;
129 }
130
131 return false;
132 }
133 /* }}} */
134 /* JavaScript *ify {{{ */
135 void CYStringify(std::ostringstream &str, const char *data, size_t size) {
136 unsigned quot(0), apos(0);
137 for (const char *value(data), *end(data + size); value != end; ++value)
138 if (*value == '"')
139 ++quot;
140 else if (*value == '\'')
141 ++apos;
142
143 bool single(quot > apos);
144
145 str << (single ? '\'' : '"');
146
147 for (const char *value(data), *end(data + size); value != end; ++value)
148 switch (*value) {
149 case '\\': str << "\\\\"; break;
150 case '\b': str << "\\b"; break;
151 case '\f': str << "\\f"; break;
152 case '\n': str << "\\n"; break;
153 case '\r': str << "\\r"; break;
154 case '\t': str << "\\t"; break;
155 case '\v': str << "\\v"; break;
156
157 case '"':
158 if (!single)
159 str << "\\\"";
160 else goto simple;
161 break;
162
163 case '\'':
164 if (single)
165 str << "\\'";
166 else goto simple;
167 break;
168
169 default:
170 // this test is designed to be "awesome", generating neither warnings nor incorrect results
171 if (*value < 0x20 || *value >= 0x7f)
172 str << "\\x" << std::setbase(16) << std::setw(2) << std::setfill('0') << unsigned(uint8_t(*value));
173 else simple:
174 str << *value;
175 }
176
177 str << (single ? '\'' : '"');
178 }
179
180 void CYNumerify(std::ostringstream &str, double value) {
181 char string[32];
182 // XXX: I want this to print 1e3 rather than 1000
183 sprintf(string, "%.17g", value);
184 str << string;
185 }
186
187 bool CYIsKey(CYUTF8String value) {
188 const char *data(value.data);
189 size_t size(value.size);
190
191 if (size == 0)
192 return false;
193
194 if (DigitRange_[data[0]]) {
195 size_t index(CYGetIndex(value));
196 if (index == _not(size_t))
197 return false;
198 } else {
199 if (!WordStartRange_[data[0]])
200 return false;
201 for (size_t i(1); i != size; ++i)
202 if (!WordEndRange_[data[i]])
203 return false;
204 }
205
206 return true;
207 }
208 /* }}} */
209
210 double CYCastDouble(const char *value, size_t size) {
211 char *end;
212 double number(strtod(value, &end));
213 if (end != value + size)
214 return NAN;
215 return number;
216 }
217
218 double CYCastDouble(const char *value) {
219 return CYCastDouble(value, strlen(value));
220 }
221
222 size_t CYArrayLength(JSContextRef context, JSObjectRef array) {
223 return CYCastDouble(context, CYGetProperty(context, array, length_s));
224 }
225
226 JSValueRef CYArrayGet(JSContextRef context, JSObjectRef array, size_t index) {
227 JSValueRef exception(NULL);
228 JSValueRef value(JSObjectGetPropertyAtIndex(context, array, index, &exception));
229 CYThrow(context, exception);
230 return value;
231 }
232
233 void CYArrayPush(JSContextRef context, JSObjectRef array, JSValueRef value) {
234 JSValueRef exception(NULL);
235 JSValueRef arguments[1];
236 arguments[0] = value;
237 JSObjectRef Array(CYGetCachedObject(context, CYJSString("Array_prototype")));
238 JSObjectCallAsFunction(context, CYCastJSObject(context, CYGetProperty(context, Array, push_s)), array, 1, arguments, &exception);
239 CYThrow(context, exception);
240 }
241
242 extern "C" void CydgetMemoryParse(const uint16_t **data, size_t *size) {
243 CYLocalPool local;
244
245 CYUTF8String utf8(CYPoolUTF8String(local, CYUTF16String(*data, *size)));
246 CYStream stream(utf8.data, utf8.data + utf8.size);
247 CYDriver driver(stream);
248
249 cy::parser parser(driver);
250 if (parser.parse() != 0 || !driver.errors_.empty())
251 return;
252
253 CYOptions options;
254 CYContext context(options);
255 driver.program_->Replace(context);
256 std::ostringstream str;
257 CYOutput out(str, options);
258 out << *driver.program_;
259 std::string code(str.str());
260
261 CYPool pool;
262 CYUTF16String utf16(CYPoolUTF16String(pool, CYUTF8String(code.c_str(), code.size())));
263
264 size_t bytes(utf16.size * sizeof(uint16_t));
265 uint16_t *copy(reinterpret_cast<uint16_t *>(malloc(bytes)));
266 memcpy(copy, utf16.data, bytes);
267
268 *data = copy;
269 *size = utf16.size;
270 }
271
272 CYPool &CYGetGlobalPool() {
273 static CYPool pool;
274 return pool;
275 }
276
277 void CYThrow(const char *format, ...) {
278 va_list args;
279 va_start(args, format);
280 throw CYPoolError(format, args);
281 // XXX: does this matter? :(
282 va_end(args);
283 }
284
285 const char *CYPoolError::PoolCString(CYPool &pool) const {
286 return pool.strdup(message_);
287 }
288
289 CYPoolError::CYPoolError(const CYPoolError &rhs) :
290 message_(pool_.strdup(rhs.message_))
291 {
292 }
293
294 CYPoolError::CYPoolError(const char *format, ...) {
295 va_list args;
296 va_start(args, format);
297 // XXX: there might be a beter way to think about this
298 message_ = pool_.vsprintf(64, format, args);
299 va_end(args);
300 }
301
302 CYPoolError::CYPoolError(const char *format, va_list args) {
303 // XXX: there might be a beter way to think about this
304 message_ = pool_.vsprintf(64, format, args);
305 }