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