1 /* 2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "gen_locl.h" 35 #include "lex.h" 36 37 RCSID("$Id$"); 38 39 static void 40 decode_primitive (const char *typename, const char *name, const char *forwstr) 41 { 42 #if 0 43 fprintf (codefile, 44 "e = decode_%s(p, len, %s, &l);\n" 45 "%s;\n", 46 typename, 47 name, 48 forwstr); 49 #else 50 fprintf (codefile, 51 "e = der_get_%s(p, len, %s, &l);\n" 52 "if(e) %s;\np += l; len -= l; ret += l;\n", 53 typename, 54 name, 55 forwstr); 56 #endif 57 } 58 59 static void 60 find_tag (const Type *t, 61 Der_class *cl, Der_type *ty, unsigned *tag) 62 { 63 switch (t->type) { 64 case TBitString: 65 *cl = ASN1_C_UNIV; 66 *ty = PRIM; 67 *tag = UT_BitString; 68 break; 69 case TBoolean: 70 *cl = ASN1_C_UNIV; 71 *ty = PRIM; 72 *tag = UT_Boolean; 73 break; 74 case TChoice: 75 errx(1, "Cannot have recursive CHOICE"); 76 case TEnumerated: 77 *cl = ASN1_C_UNIV; 78 *ty = PRIM; 79 *tag = UT_Enumerated; 80 break; 81 case TGeneralString: 82 *cl = ASN1_C_UNIV; 83 *ty = PRIM; 84 *tag = UT_GeneralString; 85 break; 86 case TTeletexString: 87 *cl = ASN1_C_UNIV; 88 *ty = PRIM; 89 *tag = UT_TeletexString; 90 break; 91 case TGeneralizedTime: 92 *cl = ASN1_C_UNIV; 93 *ty = PRIM; 94 *tag = UT_GeneralizedTime; 95 break; 96 case TIA5String: 97 *cl = ASN1_C_UNIV; 98 *ty = PRIM; 99 *tag = UT_IA5String; 100 break; 101 case TInteger: 102 *cl = ASN1_C_UNIV; 103 *ty = PRIM; 104 *tag = UT_Integer; 105 break; 106 case TNull: 107 *cl = ASN1_C_UNIV; 108 *ty = PRIM; 109 *tag = UT_Null; 110 break; 111 case TOID: 112 *cl = ASN1_C_UNIV; 113 *ty = PRIM; 114 *tag = UT_OID; 115 break; 116 case TOctetString: 117 *cl = ASN1_C_UNIV; 118 *ty = PRIM; 119 *tag = UT_OctetString; 120 break; 121 case TPrintableString: 122 *cl = ASN1_C_UNIV; 123 *ty = PRIM; 124 *tag = UT_PrintableString; 125 break; 126 case TSequence: 127 case TSequenceOf: 128 *cl = ASN1_C_UNIV; 129 *ty = CONS; 130 *tag = UT_Sequence; 131 break; 132 case TSet: 133 case TSetOf: 134 *cl = ASN1_C_UNIV; 135 *ty = CONS; 136 *tag = UT_Set; 137 break; 138 case TTag: 139 *cl = t->tag.tagclass; 140 *ty = is_primitive_type(t->subtype->type) ? PRIM : CONS; 141 *tag = t->tag.tagvalue; 142 break; 143 case TType: 144 if ((t->symbol->stype == Stype && t->symbol->type == NULL) 145 || t->symbol->stype == SUndefined) { 146 lex_error_message("%s is imported or still undefined, " 147 " can't generate tag checking data in CHOICE " 148 "without this information", 149 t->symbol->name); 150 exit(1); 151 } 152 find_tag(t->symbol->type, cl, ty, tag); 153 return; 154 case TUTCTime: 155 *cl = ASN1_C_UNIV; 156 *ty = PRIM; 157 *tag = UT_UTCTime; 158 break; 159 case TUTF8String: 160 *cl = ASN1_C_UNIV; 161 *ty = PRIM; 162 *tag = UT_UTF8String; 163 break; 164 case TBMPString: 165 *cl = ASN1_C_UNIV; 166 *ty = PRIM; 167 *tag = UT_BMPString; 168 break; 169 case TUniversalString: 170 *cl = ASN1_C_UNIV; 171 *ty = PRIM; 172 *tag = UT_UniversalString; 173 break; 174 case TVisibleString: 175 *cl = ASN1_C_UNIV; 176 *ty = PRIM; 177 *tag = UT_VisibleString; 178 break; 179 default: 180 abort(); 181 } 182 } 183 184 static void 185 range_check(const char *name, 186 const char *length, 187 const char *forwstr, 188 struct range *r) 189 { 190 if (r->min == r->max + 2 || r->min < r->max) 191 fprintf (codefile, 192 "if ((%s)->%s > %" PRId64 ") {\n" 193 "e = ASN1_MAX_CONSTRAINT; %s;\n" 194 "}\n", 195 name, length, r->max, forwstr); 196 if (r->min - 1 == r->max || r->min < r->max) 197 fprintf (codefile, 198 "if ((%s)->%s < %" PRId64 ") {\n" 199 "e = ASN1_MIN_CONSTRAINT; %s;\n" 200 "}\n", 201 name, length, r->min, forwstr); 202 if (r->max == r->min) 203 fprintf (codefile, 204 "if ((%s)->%s != %" PRId64 ") {\n" 205 "e = ASN1_EXACT_CONSTRAINT; %s;\n" 206 "}\n", 207 name, length, r->min, forwstr); 208 } 209 210 static int 211 decode_type (const char *name, const Type *t, int optional, 212 const char *forwstr, const char *tmpstr, const char *dertype, 213 unsigned int depth) 214 { 215 switch (t->type) { 216 case TType: { 217 if (optional) 218 fprintf(codefile, 219 "%s = calloc(1, sizeof(*%s));\n" 220 "if (%s == NULL) %s;\n", 221 name, name, name, forwstr); 222 fprintf (codefile, 223 "e = decode_%s(p, len, %s, &l);\n", 224 t->symbol->gen_name, name); 225 if (optional) { 226 fprintf (codefile, 227 "if(e) {\n" 228 "free(%s);\n" 229 "%s = NULL;\n" 230 "} else {\n" 231 "p += l; len -= l; ret += l;\n" 232 "}\n", 233 name, name); 234 } else { 235 fprintf (codefile, 236 "if(e) %s;\n", 237 forwstr); 238 fprintf (codefile, 239 "p += l; len -= l; ret += l;\n"); 240 } 241 break; 242 } 243 case TInteger: 244 if(t->members) { 245 fprintf(codefile, 246 "{\n" 247 "int enumint;\n"); 248 decode_primitive ("integer", "&enumint", forwstr); 249 fprintf(codefile, 250 "*%s = enumint;\n" 251 "}\n", 252 name); 253 } else if (t->range == NULL) { 254 decode_primitive ("heim_integer", name, forwstr); 255 } else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX) { 256 decode_primitive ("integer64", name, forwstr); 257 } else if (t->range->min >= 0 && t->range->max > UINT_MAX) { 258 decode_primitive ("unsigned64", name, forwstr); 259 } else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX) { 260 decode_primitive ("integer", name, forwstr); 261 } else if (t->range->min >= 0 && t->range->max <= UINT_MAX) { 262 decode_primitive ("unsigned", name, forwstr); 263 } else 264 errx(1, "%s: unsupported range %" PRId64 " -> %" PRId64, 265 name, t->range->min, t->range->max); 266 break; 267 case TBoolean: 268 decode_primitive ("boolean", name, forwstr); 269 break; 270 case TEnumerated: 271 decode_primitive ("enumerated", name, forwstr); 272 break; 273 case TOctetString: 274 if (dertype) { 275 fprintf(codefile, 276 "if (%s == CONS) {\n", 277 dertype); 278 decode_primitive("octet_string_ber", name, forwstr); 279 fprintf(codefile, 280 "} else {\n"); 281 } 282 decode_primitive ("octet_string", name, forwstr); 283 if (dertype) 284 fprintf(codefile, "}\n"); 285 if (t->range) 286 range_check(name, "length", forwstr, t->range); 287 break; 288 case TBitString: { 289 Member *m; 290 int pos = 0; 291 292 if (ASN1_TAILQ_EMPTY(t->members)) { 293 decode_primitive ("bit_string", name, forwstr); 294 break; 295 } 296 fprintf(codefile, 297 "if (len < 1) return ASN1_OVERRUN;\n" 298 "p++; len--; ret++;\n"); 299 fprintf(codefile, 300 "do {\n" 301 "if (len < 1) break;\n"); 302 ASN1_TAILQ_FOREACH(m, t->members, members) { 303 while (m->val / 8 > pos / 8) { 304 fprintf (codefile, 305 "p++; len--; ret++;\n" 306 "if (len < 1) break;\n"); 307 pos += 8; 308 } 309 fprintf (codefile, 310 "(%s)->%s = (*p >> %d) & 1;\n", 311 name, m->gen_name, 7 - m->val % 8); 312 } 313 fprintf(codefile, 314 "} while(0);\n"); 315 fprintf (codefile, 316 "p += len; ret += len;\n"); 317 break; 318 } 319 case TSequence: { 320 Member *m; 321 322 if (t->members == NULL) 323 break; 324 325 ASN1_TAILQ_FOREACH(m, t->members, members) { 326 char *s = NULL; 327 328 if (m->ellipsis) 329 continue; 330 331 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", 332 name, m->gen_name) < 0 || s == NULL) 333 errx(1, "malloc"); 334 decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL, 335 depth + 1); 336 free (s); 337 } 338 339 break; 340 } 341 case TSet: { 342 Member *m; 343 unsigned int memno; 344 345 if(t->members == NULL) 346 break; 347 348 fprintf(codefile, "{\n"); 349 fprintf(codefile, "unsigned int members = 0;\n"); 350 fprintf(codefile, "while(len > 0) {\n"); 351 fprintf(codefile, 352 "Der_class class;\n" 353 "Der_type type;\n" 354 "int tag;\n" 355 "e = der_get_tag (p, len, &class, &type, &tag, NULL);\n" 356 "if(e) %s;\n", forwstr); 357 fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n"); 358 memno = 0; 359 ASN1_TAILQ_FOREACH(m, t->members, members) { 360 char *s; 361 362 assert(m->type->type == TTag); 363 364 fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n", 365 classname(m->type->tag.tagclass), 366 is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS", 367 valuename(m->type->tag.tagclass, m->type->tag.tagvalue)); 368 369 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) 370 errx(1, "malloc"); 371 if(m->optional) 372 fprintf(codefile, 373 "%s = calloc(1, sizeof(*%s));\n" 374 "if (%s == NULL) { e = ENOMEM; %s; }\n", 375 s, s, s, forwstr); 376 decode_type (s, m->type, 0, forwstr, m->gen_name, NULL, depth + 1); 377 free (s); 378 379 fprintf(codefile, "members |= (1 << %d);\n", memno); 380 memno++; 381 fprintf(codefile, "break;\n"); 382 } 383 fprintf(codefile, 384 "default:\n" 385 "return ASN1_MISPLACED_FIELD;\n" 386 "break;\n"); 387 fprintf(codefile, "}\n"); 388 fprintf(codefile, "}\n"); 389 memno = 0; 390 ASN1_TAILQ_FOREACH(m, t->members, members) { 391 char *s; 392 393 if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL) 394 errx(1, "malloc"); 395 fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno); 396 if(m->optional) 397 fprintf(codefile, "%s = NULL;\n", s); 398 else if(m->defval) 399 gen_assign_defval(s, m->defval); 400 else 401 fprintf(codefile, "return ASN1_MISSING_FIELD;\n"); 402 free(s); 403 memno++; 404 } 405 fprintf(codefile, "}\n"); 406 break; 407 } 408 case TSetOf: 409 case TSequenceOf: { 410 char *n = NULL; 411 char *sname = NULL; 412 413 fprintf (codefile, 414 "{\n" 415 "size_t %s_origlen = len;\n" 416 "size_t %s_oldret = ret;\n" 417 "size_t %s_olen = 0;\n" 418 "void *%s_tmp;\n" 419 "ret = 0;\n" 420 "(%s)->len = 0;\n" 421 "(%s)->val = NULL;\n", 422 tmpstr, 423 tmpstr, 424 tmpstr, 425 tmpstr, 426 name, 427 name); 428 429 fprintf (codefile, 430 "while(ret < %s_origlen) {\n" 431 "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n" 432 "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n" 433 "%s_olen = %s_nlen;\n" 434 "%s_tmp = realloc((%s)->val, %s_olen);\n" 435 "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n" 436 "(%s)->val = %s_tmp;\n", 437 tmpstr, 438 tmpstr, tmpstr, name, 439 tmpstr, tmpstr, forwstr, 440 tmpstr, tmpstr, 441 tmpstr, name, tmpstr, 442 tmpstr, forwstr, 443 name, tmpstr); 444 445 if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL) 446 errx(1, "malloc"); 447 if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL) 448 errx(1, "malloc"); 449 decode_type (n, t->subtype, 0, forwstr, sname, NULL, depth + 1); 450 fprintf (codefile, 451 "(%s)->len++;\n" 452 "len = %s_origlen - ret;\n" 453 "}\n" 454 "ret += %s_oldret;\n" 455 "}\n", 456 name, 457 tmpstr, tmpstr); 458 if (t->range) 459 range_check(name, "len", forwstr, t->range); 460 free (n); 461 free (sname); 462 break; 463 } 464 case TGeneralizedTime: 465 decode_primitive ("generalized_time", name, forwstr); 466 break; 467 case TGeneralString: 468 decode_primitive ("general_string", name, forwstr); 469 break; 470 case TTeletexString: 471 decode_primitive ("general_string", name, forwstr); 472 break; 473 case TTag:{ 474 char *tname = NULL, *typestring = NULL; 475 char *ide = NULL; 476 477 if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL) 478 errx(1, "malloc"); 479 480 fprintf(codefile, 481 "{\n" 482 "size_t %s_datalen, %s_oldlen;\n" 483 "Der_type %s;\n", 484 tmpstr, tmpstr, typestring); 485 if(support_ber) 486 fprintf(codefile, 487 "int is_indefinite%u;\n", depth); 488 489 fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, " 490 "&%s_datalen, &l);\n", 491 classname(t->tag.tagclass), 492 typestring, 493 valuename(t->tag.tagclass, t->tag.tagvalue), 494 tmpstr); 495 496 /* XXX hardcode for now */ 497 if (support_ber && t->subtype->type == TOctetString) { 498 ide = typestring; 499 } else { 500 fprintf(codefile, 501 "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n", 502 typestring, 503 is_primitive_type(t->subtype->type) ? "PRIM" : "CONS"); 504 } 505 506 if(optional) { 507 fprintf(codefile, 508 "if(e) {\n" 509 "%s = NULL;\n" 510 "} else {\n" 511 "%s = calloc(1, sizeof(*%s));\n" 512 "if (%s == NULL) { e = ENOMEM; %s; }\n", 513 name, name, name, name, forwstr); 514 } else { 515 fprintf(codefile, "if(e) %s;\n", forwstr); 516 } 517 fprintf (codefile, 518 "p += l; len -= l; ret += l;\n" 519 "%s_oldlen = len;\n", 520 tmpstr); 521 if(support_ber) 522 fprintf (codefile, 523 "if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n" 524 "{ e = ASN1_BAD_FORMAT; %s; }\n" 525 "if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }", 526 depth, tmpstr, forwstr, depth, forwstr); 527 else 528 fprintf(codefile, 529 "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n" 530 "len = %s_datalen;\n", tmpstr, forwstr, tmpstr); 531 if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL) 532 errx(1, "malloc"); 533 decode_type (name, t->subtype, 0, forwstr, tname, ide, depth + 1); 534 if(support_ber) 535 fprintf(codefile, 536 "if(is_indefinite%u){\n" 537 "len += 2;\n" 538 "e = der_match_tag_and_length(p, len, " 539 "(Der_class)0, &%s, UT_EndOfContent, " 540 "&%s_datalen, &l);\n" 541 "if(e) %s;\n" 542 "p += l; len -= l; ret += l;\n" 543 "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n" 544 "} else \n", 545 depth, 546 typestring, 547 tmpstr, 548 forwstr, 549 typestring, forwstr); 550 fprintf(codefile, 551 "len = %s_oldlen - %s_datalen;\n", 552 tmpstr, tmpstr); 553 if(optional) 554 fprintf(codefile, 555 "}\n"); 556 fprintf(codefile, 557 "}\n"); 558 free(tname); 559 free(typestring); 560 break; 561 } 562 case TChoice: { 563 Member *m, *have_ellipsis = NULL; 564 const char *els = ""; 565 566 if (t->members == NULL) 567 break; 568 569 ASN1_TAILQ_FOREACH(m, t->members, members) { 570 const Type *tt = m->type; 571 char *s = NULL; 572 Der_class cl; 573 Der_type ty; 574 unsigned tag; 575 576 if (m->ellipsis) { 577 have_ellipsis = m; 578 continue; 579 } 580 581 find_tag(tt, &cl, &ty, &tag); 582 583 fprintf(codefile, 584 "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n", 585 els, 586 classname(cl), 587 ty ? "CONS" : "PRIM", 588 valuename(cl, tag)); 589 fprintf(codefile, 590 "(%s)->element = %s;\n", 591 name, m->label); 592 if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&", 593 name, m->gen_name) < 0 || s == NULL) 594 errx(1, "malloc"); 595 decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL, 596 depth + 1); 597 free(s); 598 fprintf(codefile, 599 "}\n"); 600 els = "else "; 601 } 602 if (have_ellipsis) { 603 fprintf(codefile, 604 "else {\n" 605 "(%s)->element = %s;\n" 606 "(%s)->u.%s.data = calloc(1, len);\n" 607 "if ((%s)->u.%s.data == NULL) {\n" 608 "e = ENOMEM; %s;\n" 609 "}\n" 610 "(%s)->u.%s.length = len;\n" 611 "memcpy((%s)->u.%s.data, p, len);\n" 612 "p += len;\n" 613 "ret += len;\n" 614 "len = 0;\n" 615 "}\n", 616 name, have_ellipsis->label, 617 name, have_ellipsis->gen_name, 618 name, have_ellipsis->gen_name, 619 forwstr, 620 name, have_ellipsis->gen_name, 621 name, have_ellipsis->gen_name); 622 } else { 623 fprintf(codefile, 624 "else {\n" 625 "e = ASN1_PARSE_ERROR;\n" 626 "%s;\n" 627 "}\n", 628 forwstr); 629 } 630 break; 631 } 632 case TUTCTime: 633 decode_primitive ("utctime", name, forwstr); 634 break; 635 case TUTF8String: 636 decode_primitive ("utf8string", name, forwstr); 637 break; 638 case TPrintableString: 639 decode_primitive ("printable_string", name, forwstr); 640 break; 641 case TIA5String: 642 decode_primitive ("ia5_string", name, forwstr); 643 break; 644 case TBMPString: 645 decode_primitive ("bmp_string", name, forwstr); 646 break; 647 case TUniversalString: 648 decode_primitive ("universal_string", name, forwstr); 649 break; 650 case TVisibleString: 651 decode_primitive ("visible_string", name, forwstr); 652 break; 653 case TNull: 654 fprintf (codefile, "/* NULL */\n"); 655 break; 656 case TOID: 657 decode_primitive ("oid", name, forwstr); 658 break; 659 default : 660 abort (); 661 } 662 return 0; 663 } 664 665 void 666 generate_type_decode (const Symbol *s) 667 { 668 int preserve = preserve_type(s->name) ? TRUE : FALSE; 669 670 fprintf (codefile, "int ASN1CALL\n" 671 "decode_%s(const unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE," 672 " size_t len HEIMDAL_UNUSED_ATTRIBUTE, %s *data, size_t *size)\n" 673 "{\n", 674 s->gen_name, s->gen_name); 675 676 switch (s->type->type) { 677 case TInteger: 678 case TBoolean: 679 case TOctetString: 680 case TOID: 681 case TGeneralizedTime: 682 case TGeneralString: 683 case TTeletexString: 684 case TUTF8String: 685 case TPrintableString: 686 case TIA5String: 687 case TBMPString: 688 case TUniversalString: 689 case TVisibleString: 690 case TUTCTime: 691 case TNull: 692 case TEnumerated: 693 case TBitString: 694 case TSequence: 695 case TSequenceOf: 696 case TSet: 697 case TSetOf: 698 case TTag: 699 case TType: 700 case TChoice: 701 fprintf (codefile, 702 "size_t ret = 0;\n" 703 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" 704 "int e HEIMDAL_UNUSED_ATTRIBUTE;\n"); 705 if (preserve) 706 fprintf (codefile, "const unsigned char *begin = p;\n"); 707 708 fprintf (codefile, "\n"); 709 fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */ 710 711 decode_type ("data", s->type, 0, "goto fail", "Top", NULL, 1); 712 if (preserve) 713 fprintf (codefile, 714 "data->_save.data = calloc(1, ret);\n" 715 "if (data->_save.data == NULL) { \n" 716 "e = ENOMEM; goto fail; \n" 717 "}\n" 718 "data->_save.length = ret;\n" 719 "memcpy(data->_save.data, begin, ret);\n"); 720 fprintf (codefile, 721 "if(size) *size = ret;\n" 722 "return 0;\n"); 723 fprintf (codefile, 724 "fail:\n" 725 "free_%s(data);\n" 726 "return e;\n", 727 s->gen_name); 728 break; 729 default: 730 abort (); 731 } 732 fprintf (codefile, "}\n\n"); 733 } 734