1 : /*
2 : * Copyright (c) 2011 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : // This module contains parsing code to be used with sel_universal.
8 : // Since sel_universal is a testing tool and parsing in C++ is no fun,
9 : // this code merely aims at being maitainable.
10 : // Efficiency and proper dealing with bad input are non-goals.
11 :
12 : #include <stdio.h>
13 : #include <stdlib.h>
14 : #include <string.h>
15 :
16 : #if NACL_WINDOWS
17 : #include <float.h>
18 : #define NACL_ISNAN(d) _isnan(d)
19 : #else
20 : /* Windows doesn't have the following header files. */
21 : # include <math.h>
22 : #define NACL_ISNAN(d) isnan(d)
23 : #endif /* NACL_WINDOWS */
24 :
25 : #include <iomanip>
26 : #include <string>
27 : #include <vector>
28 : #include <sstream>
29 :
30 : #include "native_client/src/include/portability_string.h"
31 :
32 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
33 : #include "native_client/src/trusted/sel_universal/parsing.h"
34 : #include "native_client/src/shared/platform/nacl_log.h"
35 :
36 : using std::stringstream;
37 :
38 :
39 18 : static uint32_t StringToUint32(string s, size_t pos = 0) {
40 18 : return strtoul(s.c_str() + pos, 0, 0);
41 : }
42 :
43 :
44 76 : static int32_t StringToInt32(string s, size_t pos = 0) {
45 76 : return strtol(s.c_str() + pos, 0, 0);
46 : }
47 :
48 :
49 10 : static int64_t StringToInt64(string s, size_t pos = 0) {
50 10 : return STRTOLL(s.c_str() + pos, 0, 0);
51 : }
52 :
53 :
54 48 : static double StringToDouble(string s, size_t pos = 0) {
55 48 : return strtod(s.c_str() + pos, 0);
56 : }
57 :
58 : // remove typing markup, e.g. i(1234) -> 1234
59 2 : string GetPayload(string token) {
60 2 : return token.substr(2, token.size() - 3);
61 : }
62 :
63 : // convert strings 5 or i(5) to int32
64 0 : int32_t ExtractInt32(string token) {
65 0 : if (token[0] == 'i' && token[1] == '(') {
66 0 : return StringToInt32(token, 2);
67 : }
68 0 : return StringToInt32(token);
69 : }
70 :
71 : // convert strings 5 or l(5) to int64
72 0 : int64_t ExtractInt64(string token) {
73 0 : if (token[0] == 'l' && token[1] == '(') {
74 0 : return StringToInt64(token, 2);
75 : }
76 0 : return StringToInt64(token);
77 : }
78 :
79 :
80 0 : NaClDesc* ExtractDesc(string token, NaClCommandLoop* ncl) {
81 0 : if (token[0] == 'h' && token[1] == '(') {
82 0 : token = GetPayload(token);
83 : }
84 0 : return ncl->FindDescByName(token);
85 : }
86 :
87 :
88 10 : static int HandleEscapedOctal(const string s, size_t* pos) {
89 10 : if (*pos + 2 >= s.size()) {
90 0 : NaClLog(LOG_ERROR, "malformed octal escape");
91 0 : return -1;
92 : }
93 :
94 10 : int ival = s[*pos] - '0';
95 10 : ++*pos;
96 10 : ival = ival * 8 + s[*pos] - '0';
97 10 : ++*pos;
98 10 : ival = ival * 8 + s[*pos] - '0';
99 10 : ++*pos;
100 10 : return ival;
101 : }
102 :
103 :
104 28 : static int HexDigit(char c) {
105 28 : if (isdigit(c)) return c - '0';
106 8 : else return toupper(c) - 'A' + 10;
107 : }
108 :
109 :
110 14 : static int HandleEscapedHex(const string s, size_t* pos) {
111 14 : if (*pos + 1 >= s.size()) {
112 0 : NaClLog(LOG_ERROR, "malformed hex escape");
113 0 : return -1;
114 : }
115 14 : int ival = HexDigit(s[*pos]);
116 14 : ++*pos;
117 14 : ival = ival * 16 + HexDigit(s[*pos]);
118 14 : ++*pos;
119 14 : return ival;
120 : }
121 :
122 :
123 : // This should be kept in sync with the SRPC logging escaping done in
124 : // src/shared/srpc/rpc_log.c to allow easy capture of logs for testing.
125 39 : static int HandleEscapedChar(const string s, size_t* pos) {
126 39 : if (*pos >= s.size()) return -1;
127 39 : switch (s[*pos]) {
128 : case '\\':
129 2 : ++*pos;
130 2 : return '\\';
131 : case '\"':
132 5 : ++*pos;
133 5 : return '\"';
134 : case '\'':
135 0 : ++*pos;
136 0 : return '\'';
137 : case 'a':
138 0 : ++*pos;
139 0 : return '\a';
140 : case 'b':
141 2 : ++*pos;
142 2 : return '\b';
143 : case 'f':
144 2 : ++*pos;
145 2 : return '\f';
146 : case 'n':
147 2 : ++*pos;
148 2 : return '\n';
149 : case 'r':
150 0 : ++*pos;
151 0 : return '\r';
152 : case 't':
153 2 : ++*pos;
154 2 : return '\t';
155 : case 'v':
156 0 : ++*pos;
157 0 : return '\v';
158 :
159 : case '0':
160 : case '1':
161 : case '2':
162 : case '3':
163 : case '4':
164 : case '5':
165 : case '6':
166 : case '7':
167 10 : return HandleEscapedOctal(s, pos);
168 :
169 : case 'x':
170 : case 'X':
171 14 : ++*pos;
172 14 : return HandleEscapedHex(s, pos);
173 :
174 : default:
175 0 : NaClLog(LOG_ERROR, "bad escape\n");
176 0 : return -1;
177 : }
178 : }
179 :
180 :
181 : // Reads one char from *p and advances *p to the next read point in the input.
182 : // This handles some meta characters ('\\', '\"', '\b', '\f', '\n', '\t',
183 : // and '\v'), \ddd, where ddd is interpreted as an octal character value, and
184 : // \[xX]dd, where dd is interpreted as a hexadecimal character value.
185 71 : static int ReadOneChar(const string s, size_t* pos) {
186 71 : if (*pos >= s.size()) {
187 0 : return -1;
188 : }
189 :
190 71 : if (s[*pos] == '\\') {
191 39 : ++*pos;
192 39 : return HandleEscapedChar(s, pos);
193 : }
194 :
195 32 : int ival = s[*pos];
196 32 : ++*pos;
197 32 : return ival;
198 : }
199 :
200 : // expects "from" to point to leading \" and returns offset to trailing \"
201 : // a zero return value indicates an error
202 8 : static size_t ScanEscapeString(const string s, size_t from) {
203 : // skip initial quotes
204 8 : size_t pos = from + 1;
205 8 : int ival = ReadOneChar(s, &pos);
206 8 : while (-1 != ival) {
207 13 : if ('\"' == ival) {
208 8 : return pos;
209 : }
210 5 : ival = ReadOneChar(s, &pos);
211 : }
212 0 : NaClLog(LOG_ERROR, "unterminated string\n");
213 0 : return 0;
214 : }
215 :
216 : // input looks like:
217 : // rpc fib i(1) i(1) * I(10)
218 : // rpc rubyEval s("3.times{ puts 'lala' }") * s("")
219 : // rpc double_array D(5,3.1,1.4,4.1,1.5,5.9) * D(5)
220 : // rpc invalid_handle h(-1) *
221 : // rpc char_array C(9,A\b\f\n\t\"\"\\\x7F) * C(9)
222 53 : void Tokenize(string line, vector<string>* tokens) {
223 53 : size_t pos_start = 0;
224 :
225 399 : while (pos_start < line.size()) {
226 : // skip over leading white space
227 586 : while (pos_start < line.size()) {
228 293 : const char c = line[pos_start];
229 293 : if (isspace((unsigned char)c)) {
230 0 : pos_start++;
231 : } else {
232 293 : break;
233 : }
234 : }
235 :
236 293 : if (pos_start >= line.size()) break; // <<< LOOP EXIT
237 :
238 293 : size_t pos_end = pos_start;
239 1978 : while (pos_end < line.size()) {
240 1656 : const char c = line[pos_end];
241 :
242 1656 : if (isspace((unsigned char)c)) {
243 264 : break;
244 1392 : } else if (c == '\"') {
245 : // NOTE: quotes are only really relevant in s("...").
246 8 : size_t end = ScanEscapeString(line, pos_end);
247 8 : if (end == 0) {
248 0 : NaClLog(LOG_ERROR, "unterminated string constant\n");
249 0 : return;
250 : }
251 :
252 8 : pos_end = end;
253 : } else {
254 1384 : pos_end++;
255 : }
256 : }
257 :
258 293 : tokens->push_back(line.substr(pos_start, pos_end - pos_start));
259 :
260 293 : pos_start = pos_end + 1;
261 : }
262 : }
263 :
264 :
265 7 : static size_t FindComma(string s, size_t start) {
266 : size_t i;
267 15 : for (i = start; i < s.size(); ++i) {
268 15 : if (s[i] == ',') {
269 7 : break;
270 : }
271 : }
272 7 : return i;
273 : }
274 :
275 : // input looks like:
276 : // I(5,1,2,3,4,5)
277 : // L(5,1,2,3,4,5)
278 : static uint32_t SplitArray(string s,
279 : vector<string>* tokens,
280 : bool input,
281 11 : bool check_size = true) {
282 11 : tokens->clear();
283 11 : uint32_t dim = StringToUint32(s, 2);
284 :
285 18 : if (!input) return dim;
286 :
287 4 : size_t i = 1 + FindComma(s, 2);
288 4 : size_t start = i;
289 :
290 73 : for (; i < s.size(); ++i) {
291 69 : if (s[i] == ',' || s[i] == ')') {
292 18 : tokens->push_back(s.substr(start, i - start));
293 18 : start = i + 1;
294 : }
295 : }
296 :
297 4 : if (check_size && dim != tokens->size()) {
298 : NaClLog(LOG_ERROR, "array token number mismatch %d vs %d\n",
299 0 : static_cast<int>(dim), static_cast<int>(tokens->size()));
300 0 : return 0;
301 : }
302 :
303 4 : return dim;
304 : }
305 :
306 : // input looks like:
307 : // C(12,\110\145\154\154\157,\x77\x6f\x72\x6C\x64\X2E)
308 : // C(9,A\b\f\n\t\"\"\\\x7F)
309 7 : static uint32_t SplitArrayChar(string s, vector<string>* tokens, bool input) {
310 7 : tokens->clear();
311 7 : uint32_t dim = StringToUint32(s, 2);
312 :
313 11 : if (!input) return dim;
314 :
315 3 : size_t i = 1 + FindComma(s, 2);
316 3 : size_t start = i;
317 :
318 32 : while (i < s.size() && s[i] != ')') {
319 26 : ReadOneChar(s, &i);
320 52 : tokens->push_back(s.substr(start, i - start));
321 26 : start = i;
322 : }
323 :
324 3 : if (dim != tokens->size()) {
325 : NaClLog(LOG_ERROR, "array token number mismatch %d vs %d\n",
326 0 : static_cast<int>(dim), static_cast<int>(tokens->size()));
327 0 : return 0;
328 : }
329 :
330 3 : return dim;
331 : }
332 :
333 :
334 : // substitute ${var_name} strings in s
335 293 : string SubstituteVars(string s, NaClCommandLoop* ncl) {
336 293 : string result("");
337 586 : string var("");
338 293 : bool scanning_var_name = false;
339 1699 : for (size_t i = 0; i < s.size(); ++i) {
340 1406 : if (scanning_var_name) {
341 21 : if (s[i] == '{') {
342 2 : continue;
343 19 : } else if (s[i] == '}') {
344 2 : result.append(ncl->GetVariable(var));
345 2 : scanning_var_name = false;
346 : } else {
347 17 : var.push_back(s[i]);
348 : }
349 : } else {
350 1385 : if (s[i] == '$') {
351 2 : scanning_var_name = true;
352 2 : var = "";
353 : } else {
354 1383 : result.push_back(s[i]);
355 : }
356 : }
357 : }
358 :
359 293 : return result;
360 : }
361 :
362 :
363 8 : static string UnescapeString(string s) {
364 8 : string result("");
365 8 : size_t i = 3;
366 22 : while (i < s.size() && s[i] != '"') {
367 6 : int val = ReadOneChar(s, &i);
368 6 : result.push_back(val);
369 : }
370 :
371 0 : return result;
372 : }
373 :
374 : // initialize a single srpc arg using the information found in token.
375 : // input indicates whether this is an input our an output arg.
376 : // Output args are handled slightly different especially in the array case
377 : // where the merely allocate space but do not initialize it.
378 : bool ParseArg(NaClSrpcArg* arg,
379 : string token,
380 : bool input,
381 146 : NaClCommandLoop* ncl) {
382 146 : if (token.size() <= 2) {
383 0 : NaClLog(LOG_ERROR, "parameter too short: %s\n", token.c_str());
384 0 : return false;
385 : }
386 :
387 146 : const char type = token[0];
388 146 : vector<string> array_tokens;
389 :
390 : // Initialize the argument slot. This enables freeing on failures.
391 146 : memset(arg, 0, sizeof(*arg));
392 :
393 292 : NaClLog(3, "TOKEN %s\n", token.c_str());
394 146 : if (token[1] != '(' || token[token.size() - 1] != ')') {
395 0 : NaClLog(LOG_ERROR, "malformed token '%s'\n", token.c_str());
396 146 : return false;
397 : }
398 :
399 : int dim;
400 146 : switch (type) {
401 : case NACL_SRPC_ARG_TYPE_INVALID:
402 0 : arg->tag = NACL_SRPC_ARG_TYPE_INVALID;
403 0 : break;
404 : case NACL_SRPC_ARG_TYPE_BOOL:
405 4 : arg->tag = NACL_SRPC_ARG_TYPE_BOOL;
406 4 : arg->u.bval = StringToInt32(token, 2);
407 4 : break;
408 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
409 7 : arg->tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
410 7 : dim = SplitArrayChar(token, &array_tokens, input);
411 7 : arg->arrays.carr = static_cast<char*>(calloc(dim, sizeof(char)));
412 7 : if (NULL == arg->arrays.carr) {
413 0 : NaClLog(LOG_ERROR, "alloc problem\n");
414 0 : return false;
415 : }
416 7 : arg->u.count = dim;
417 7 : if (input) {
418 29 : for (int i = 0; i < dim; ++i) {
419 26 : size_t dummy = 0;
420 26 : arg->arrays.carr[i] = ReadOneChar(array_tokens[i], &dummy);
421 : }
422 : }
423 7 : break;
424 : // This is alternative representation for CHAR_ARRAY:
425 : // R stands for "record".
426 : // example: R(8,1:0x44,2:1999,4:0,"a")
427 : // NOTE: commas inside of strings must currently be escaped
428 : case 'R':
429 1 : arg->tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
430 1 : dim = SplitArray(token, &array_tokens, input, false);
431 1 : arg->arrays.carr = static_cast<char*>(calloc(dim, sizeof(char)));
432 1 : if (NULL == arg->arrays.carr) {
433 0 : NaClLog(LOG_ERROR, "alloc problem\n");
434 0 : return false;
435 : }
436 1 : arg->u.count = dim;
437 1 : if (input) {
438 1 : int curr = 0;
439 1 : for (size_t i = 0; i < array_tokens.size(); ++i) {
440 3 : string s = array_tokens[i];
441 3 : if (s[0] == '"') {
442 : // the format of the token is: "string"
443 0 : size_t p = 1;
444 0 : while (p < s.size() && s[p] != '"') {
445 0 : if (curr >= dim) {
446 0 : NaClLog(LOG_ERROR, "size overflow in 'R' string parameter\n");
447 0 : return false;
448 : }
449 0 : int val = ReadOneChar(s, &p);
450 0 : arg->arrays.carr[curr] = (char) val;
451 0 : ++curr;
452 : }
453 : } else {
454 : // the format of the token is: <num_bytes_single_digit>:<value>
455 3 : int num_bytes = s[0] - '0';
456 3 : if (s.size() < 3 || num_bytes < 1 || 8 < num_bytes || s[1] != ':') {
457 0 : NaClLog(LOG_ERROR, "poorly formatted 'R' parameter\n");
458 0 : return false;
459 : }
460 3 : int64_t val = StringToInt64(s, 2);
461 13 : while (num_bytes) {
462 7 : --num_bytes;
463 7 : if (curr >= dim) {
464 0 : NaClLog(LOG_ERROR, "size overflow in 'R' int parameter\n");
465 0 : return false;
466 : }
467 7 : arg->arrays.carr[curr] = val & 0xff;
468 7 : ++curr;
469 7 : val >>= 8;
470 : }
471 : }
472 : }
473 :
474 1 : if (curr != dim) {
475 0 : NaClLog(LOG_ERROR, "size mismatch in 'R' parameter\n");
476 0 : return false;
477 : }
478 : }
479 1 : break;
480 : case NACL_SRPC_ARG_TYPE_DOUBLE:
481 43 : arg->tag = NACL_SRPC_ARG_TYPE_DOUBLE;
482 43 : arg->u.dval = StringToDouble(token, 2);
483 43 : break;
484 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
485 2 : arg->tag = NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY;
486 2 : dim = SplitArray(token, &array_tokens, input);
487 2 : arg->arrays.darr = static_cast<double*>(calloc(dim, sizeof(double)));
488 2 : if (NULL == arg->arrays.darr) {
489 0 : NaClLog(LOG_ERROR, "alloc problem\n");
490 0 : return false;
491 : }
492 2 : arg->u.count = dim;
493 2 : if (input) {
494 6 : for (int i = 0; i < dim; ++i) {
495 5 : arg->arrays.darr[i] = StringToDouble(array_tokens[i]);
496 : }
497 : }
498 2 : break;
499 : case NACL_SRPC_ARG_TYPE_HANDLE:
500 4 : arg->tag = NACL_SRPC_ARG_TYPE_HANDLE;
501 4 : if (input) {
502 2 : arg->u.hval = ncl->FindDescByName(GetPayload(token));
503 : }
504 4 : break;
505 : case NACL_SRPC_ARG_TYPE_INT:
506 67 : arg->tag = NACL_SRPC_ARG_TYPE_INT;
507 67 : arg->u.ival = StringToInt32(token, 2);
508 67 : break;
509 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
510 6 : arg->tag = NACL_SRPC_ARG_TYPE_INT_ARRAY;
511 6 : dim = SplitArray(token, &array_tokens, input);
512 6 : arg->arrays.iarr = static_cast<int32_t*>(calloc(dim, sizeof(int32_t)));
513 6 : if (NULL == arg->arrays.iarr) {
514 0 : return false;
515 : }
516 6 : arg->u.count = dim;
517 6 : if (input) {
518 6 : for (int i = 0; i < dim; ++i) {
519 5 : arg->arrays.iarr[i] = StringToInt32(array_tokens[i]);
520 : }
521 : }
522 6 : break;
523 : case NACL_SRPC_ARG_TYPE_LONG:
524 2 : arg->tag = NACL_SRPC_ARG_TYPE_LONG;
525 2 : arg->u.lval = StringToInt64(token, 2);
526 2 : break;
527 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
528 2 : arg->tag = NACL_SRPC_ARG_TYPE_LONG_ARRAY;
529 2 : dim = SplitArray(token, &array_tokens, input);
530 2 : arg->arrays.larr = static_cast<int64_t*>(calloc(dim, sizeof(int64_t)));
531 2 : if (NULL == arg->arrays.larr) {
532 0 : NaClLog(LOG_ERROR, "alloc problem\n");
533 0 : return false;
534 : }
535 2 : arg->u.count = dim;
536 2 : if (input) {
537 6 : for (int i = 0; i < dim; ++i) {
538 5 : arg->arrays.larr[i] = StringToInt64(array_tokens[i]);
539 : }
540 : }
541 2 : break;
542 : case NACL_SRPC_ARG_TYPE_STRING:
543 8 : arg->tag = NACL_SRPC_ARG_TYPE_STRING;
544 : arg->arrays.str =
545 8 : strdup(UnescapeString(token).c_str());
546 8 : if (NULL == arg->arrays.str) {
547 0 : NaClLog(LOG_ERROR, "alloc problem\n");
548 0 : return false;
549 : }
550 8 : break;
551 : /*
552 : * The two cases below are added to avoid warnings, they are only used
553 : * in the plugin code
554 : */
555 : case NACL_SRPC_ARG_TYPE_OBJECT:
556 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
557 : default:
558 0 : NaClLog(LOG_ERROR, "unsupported srpc arg type\n");
559 0 : return false;
560 : }
561 :
562 146 : return true;
563 : }
564 :
565 :
566 0 : bool OneArgEqual(NaClSrpcArg* arg1, NaClSrpcArg* arg2) {
567 0 : if (arg1->tag != arg2->tag) return false;
568 :
569 0 : switch (arg1->tag) {
570 : case NACL_SRPC_ARG_TYPE_INVALID:
571 0 : return true;
572 : case NACL_SRPC_ARG_TYPE_BOOL:
573 0 : return arg1->u.bval == arg2->u.bval;
574 : case NACL_SRPC_ARG_TYPE_DOUBLE:
575 : // TOOD(robertm): tolerate small deltas
576 0 : return arg1->u.dval == arg2->u.dval;
577 : case NACL_SRPC_ARG_TYPE_HANDLE:
578 0 : return arg1->u.hval == arg2->u.hval;
579 : case NACL_SRPC_ARG_TYPE_INT:
580 0 : return arg1->u.ival == arg2->u.ival;
581 : case NACL_SRPC_ARG_TYPE_LONG:
582 0 : return arg1->u.lval == arg2->u.lval;
583 : case NACL_SRPC_ARG_TYPE_STRING:
584 0 : return string(arg1->arrays.str) == string(arg2->arrays.str);
585 :
586 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
587 0 : if (arg1->u.count != arg2->u.count) return false;
588 0 : for (size_t i = 0; i < arg1->u.count; ++i) {
589 0 : if ( arg1->arrays.carr[i] != arg2->arrays.carr[i]) return false;
590 : }
591 0 : return true;
592 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
593 0 : if (arg1->u.count != arg2->u.count) return false;
594 0 : for (size_t i = 0; i < arg1->u.count; ++i) {
595 0 : if ( arg1->arrays.iarr[i] != arg2->arrays.iarr[i]) return false;
596 : }
597 0 : return true;
598 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
599 0 : if (arg1->u.count != arg2->u.count) return false;
600 0 : for (size_t i = 0; i < arg1->u.count; ++i) {
601 0 : if ( arg1->arrays.larr[i] != arg2->arrays.larr[i]) return false;
602 : }
603 0 : return true;
604 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
605 0 : if (arg1->u.count != arg2->u.count) return false;
606 0 : for (size_t i = 0; i < arg1->u.count; ++i) {
607 : // TOOD(robertm): tolerate small deltas
608 0 : if ( arg1->arrays.darr[i] != arg2->arrays.darr[i]) return false;
609 : }
610 0 : return true;
611 : case NACL_SRPC_ARG_TYPE_OBJECT:
612 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
613 : default:
614 0 : NaClLog(LOG_FATAL, "unsupported srpc arg type\n");
615 0 : return false;
616 : }
617 : }
618 :
619 :
620 0 : bool AllArgsEqual(NaClSrpcArg** arg1, NaClSrpcArg** arg2) {
621 0 : if (NULL != *arg1 && NULL != *arg2) {
622 0 : if (!OneArgEqual(*arg1, *arg2)) return false;
623 0 : return AllArgsEqual(++arg1, ++arg2);
624 0 : } else if (0 == *arg1 && 0 == *arg2) {
625 0 : return true;
626 : } else {
627 0 : return false;
628 : }
629 : }
630 :
631 :
632 : bool ParseArgs(NaClSrpcArg** args,
633 : const vector<string>& tokens,
634 : size_t start,
635 : bool input,
636 94 : NaClCommandLoop* ncl) {
637 240 : for (size_t i = 0; args[i] != NULL; ++i) {
638 146 : if (!ParseArg(args[i], tokens[start + i], input, ncl)) {
639 0 : return false;
640 : }
641 : }
642 94 : return true;
643 : }
644 :
645 :
646 1448 : static string StringifyOneChar(unsigned char c) {
647 1448 : switch (c) {
648 : case '\"':
649 6 : return "\\\"";
650 : case '\b':
651 3 : return "\\b";
652 : case '\f':
653 3 : return "\\f";
654 : case '\n':
655 29 : return "\\n";
656 : case '\t':
657 3 : return "\\t";
658 : case '\v':
659 0 : return "\\v";
660 : case '\\':
661 3 : return "\\\\";
662 : default:
663 : // play it safe and escape closing parens which could
664 : // cause problems when this string is read back
665 1401 : if (c < ' ' || 126 < c || c == ')') {
666 24 : stringstream result;
667 : result << "\\x" << std::hex << std::setw(2) <<
668 24 : std::setfill('0') << int(c);
669 24 : return result.str();
670 : } else {
671 1377 : stringstream result;
672 1377 : result << c;
673 1377 : return result.str();
674 : }
675 : }
676 : }
677 :
678 :
679 60 : static string DumpDouble(const double* dval) {
680 60 : if (NACL_ISNAN(*dval)) {
681 2 : return "NaN";
682 : } else {
683 58 : stringstream result;
684 58 : result << *dval;
685 58 : return result.str();
686 : }
687 : }
688 :
689 :
690 210 : string DumpArg(const NaClSrpcArg* arg, NaClCommandLoop* ncl) {
691 210 : stringstream result;
692 : uint32_t count;
693 : uint32_t i;
694 : char* p;
695 210 : switch (arg->tag) {
696 : case NACL_SRPC_ARG_TYPE_INVALID:
697 0 : return "X()";
698 : case NACL_SRPC_ARG_TYPE_BOOL:
699 6 : result << "b(" << arg->u.bval << ")";
700 6 : return result.str();
701 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
702 12 : count = arg->u.count;
703 12 : result << "C(" << count << ",";
704 111 : for (i = 0; i < arg->u.count; ++i)
705 99 : result << StringifyOneChar(arg->arrays.carr[i]);
706 12 : result << ")";
707 12 : return result.str();
708 : case NACL_SRPC_ARG_TYPE_DOUBLE:
709 45 : result << "d(" << DumpDouble(&arg->u.dval) << ")";
710 45 : return result.str();
711 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
712 3 : count = arg->u.count;
713 3 : result << "D(" << count;
714 18 : for (i = 0; i < count; ++i) {
715 15 : result << "," << DumpDouble(&(arg->arrays.darr[i]));
716 : }
717 3 : result << ")";
718 3 : return result.str();
719 : case NACL_SRPC_ARG_TYPE_HANDLE:
720 6 : result << "h(" << ncl->AddDescUniquify(arg->u.hval, "imported") << ")";
721 6 : return result.str();
722 : case NACL_SRPC_ARG_TYPE_INT:
723 106 : result << "i(" << arg->u.ival << ")";
724 106 : return result.str();
725 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
726 11 : count = arg->u.count;
727 11 : result << "I(" << count;
728 126 : for (i = 0; i < count; ++i) {
729 115 : result << "," << arg->arrays.iarr[i];
730 : }
731 11 : result << ")";
732 11 : return result.str();
733 : case NACL_SRPC_ARG_TYPE_LONG:
734 3 : result << "l(" << arg->u.lval << ")";
735 3 : return result.str();
736 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
737 3 : count = arg->u.count;
738 3 : result << "L(" << count;
739 18 : for (i = 0; i < count; ++i) {
740 15 : result << "," << arg->arrays.larr[i];
741 : }
742 3 : result << ")";
743 3 : return result.str();
744 : case NACL_SRPC_ARG_TYPE_STRING:
745 15 : result << "s(\"";
746 1364 : for (p = arg->arrays.str; '\0' != *p; ++p)
747 1349 : result << StringifyOneChar(*p);
748 15 : result << "\")";
749 15 : return result.str();
750 : case NACL_SRPC_ARG_TYPE_OBJECT:
751 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
752 : default:
753 0 : NaClLog(LOG_ERROR, "unknown or unsupported type '%c'\n", arg->tag);
754 0 : return "";
755 0 : }
756 : }
757 :
758 :
759 94 : void BuildArgVec(NaClSrpcArg* argv[], NaClSrpcArg arg[], size_t count) {
760 240 : for (size_t i = 0; i < count; ++i) {
761 146 : NaClSrpcArgCtor(&arg[i]);
762 146 : argv[i] = &arg[i];
763 : }
764 94 : argv[count] = NULL;
765 94 : }
766 :
767 :
768 146 : void FreeArrayArg(NaClSrpcArg* arg) {
769 146 : switch (arg->tag) {
770 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
771 8 : free(arg->arrays.carr);
772 8 : break;
773 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
774 2 : free(arg->arrays.darr);
775 2 : break;
776 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
777 6 : free(arg->arrays.iarr);
778 6 : break;
779 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
780 2 : free(arg->arrays.larr);
781 2 : break;
782 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
783 : case NACL_SRPC_ARG_TYPE_OBJECT:
784 0 : NaClLog(LOG_ERROR, "unsupported srpc arg type\n");
785 0 : break;
786 : case NACL_SRPC_ARG_TYPE_STRING:
787 8 : free(arg->arrays.str);
788 : break;
789 : case NACL_SRPC_ARG_TYPE_INVALID:
790 : case NACL_SRPC_ARG_TYPE_BOOL:
791 : case NACL_SRPC_ARG_TYPE_DOUBLE:
792 : case NACL_SRPC_ARG_TYPE_HANDLE:
793 : case NACL_SRPC_ARG_TYPE_INT:
794 : case NACL_SRPC_ARG_TYPE_LONG:
795 : default:
796 : break;
797 : }
798 146 : }
799 :
800 :
801 94 : void FreeArrayArgs(NaClSrpcArg** args) {
802 240 : for (size_t i = 0; args[i] != NULL; ++i) {
803 146 : FreeArrayArg(args[i]);
804 : }
805 94 : }
|