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 37RCSID("$Id$"); 38 39static void 40decode_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 59static void 60find_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 } 180} 181 182static void 183range_check(const char *name, 184 const char *length, 185 const char *forwstr, 186 struct range *r) 187{ 188 if (r->min == r->max + 2 || r->min < r->max) 189 fprintf (codefile, 190 "if ((%s)->%s > %d) {\n" 191 "e = ASN1_MAX_CONSTRAINT; %s;\n" 192 "}\n", 193 name, length, r->max, forwstr); 194 if (r->min - 1 == r->max || r->min < r->max) 195 fprintf (codefile, 196 "if ((%s)->%s < %d) {\n" 197 "e = ASN1_MIN_CONSTRAINT; %s;\n" 198 "}\n", 199 name, length, r->min, forwstr); 200 if (r->max == r->min) 201 fprintf (codefile, 202 "if ((%s)->%s != %d) {\n" 203 "e = ASN1_EXACT_CONSTRAINT; %s;\n" 204 "}\n", 205 name, length, r->min, forwstr); 206} 207 208static int 209decode_type (const char *name, const Type *t, int optional, 210 const char *forwstr, const char *tmpstr, const char *dertype, 211 unsigned int depth) 212{ 213 switch (t->type) { 214 case TType: { 215 if (optional) 216 fprintf(codefile, 217 "%s = calloc(1, sizeof(*%s));\n" 218 "if (%s == NULL) %s;\n", 219 name, name, name, forwstr); 220 fprintf (codefile, 221 "e = decode_%s(p, len, %s, &l);\n", 222 t->symbol->gen_name, name); 223 if (optional) { 224 fprintf (codefile, 225 "if(e) {\n" 226 "free(%s);\n" 227 "%s = NULL;\n" 228 "} else {\n" 229 "p += l; len -= l; ret += l;\n" 230 "}\n", 231 name, name); 232 } else { 233 fprintf (codefile, 234 "if(e) %s;\n", 235 forwstr); 236 fprintf (codefile, 237 "p += l; len -= l; ret += l;\n"); 238 } 239 break; 240 } 241 case TInteger: 242 if(t->members) { 243 /* 244 * This will produce a worning, how its hard to fix since: 245 * if its enum to an NameType, we can add appriate 246 * type-cast. If its not though, we have to figure out if 247 * there is negative enum enum and use appropriate 248 * signness and size on the intertype we cast the result 249 * too. 250 */ 251 fprintf(codefile, 252 "{\n" 253 "int enumint;\n"); 254 decode_primitive ("integer", "&enumint", forwstr); 255 fprintf(codefile, 256 "*%s = enumint;\n" 257 "}\n", 258 name); 259 } else if (t->range == NULL) { 260 decode_primitive ("heim_integer", name, forwstr); 261 } else if (t->range->min == INT_MIN && t->range->max == INT_MAX) { 262 decode_primitive ("integer", name, forwstr); 263 } else if (t->range->min == 0 && (unsigned int)t->range->max == UINT_MAX) { 264 decode_primitive ("unsigned", name, forwstr); 265 } else if (t->range->min == 0 && t->range->max == INT_MAX) { 266 decode_primitive ("unsigned", name, forwstr); 267 } else 268 errx(1, "%s: unsupported range %d -> %d", 269 name, t->range->min, t->range->max); 270 break; 271 case TBoolean: 272 decode_primitive ("boolean", name, forwstr); 273 break; 274 case TEnumerated: 275 decode_primitive ("enumerated", name, forwstr); 276 break; 277 case TOctetString: 278 if (dertype) { 279 fprintf(codefile, 280 "if (%s == CONS) {\n", 281 dertype); 282 decode_primitive("octet_string_ber", name, forwstr); 283 fprintf(codefile, 284 "} else {\n"); 285 } 286 decode_primitive ("octet_string", name, forwstr); 287 if (dertype) 288 fprintf(codefile, "}\n"); 289 if (t->range) 290 range_check(name, "length", forwstr, t->range); 291 break; 292 case TBitString: { 293 Member *m; 294 int pos = 0; 295 296 if (ASN1_TAILQ_EMPTY(t->members)) { 297 decode_primitive ("bit_string", name, forwstr); 298 break; 299 } 300 fprintf(codefile, 301 "if (len < 1) return ASN1_OVERRUN;\n" 302 "p++; len--; ret++;\n"); 303 fprintf(codefile, 304 "do {\n" 305 "if (len < 1) break;\n"); 306 ASN1_TAILQ_FOREACH(m, t->members, members) { 307 while (m->val / 8 > pos / 8) { 308 fprintf (codefile, 309 "p++; len--; ret++;\n" 310 "if (len < 1) break;\n"); 311 pos += 8; 312 } 313 fprintf (codefile, 314 "(%s)->%s = (*p >> %d) & 1;\n", 315 name, m->gen_name, 7 - m->val % 8); 316 } 317 fprintf(codefile, 318 "} while(0);\n"); 319 fprintf (codefile, 320 "p += len; ret += len;\n"); 321 break; 322 } 323 case TSequence: { 324 Member *m; 325 326 if (t->members == NULL) 327 break; 328 329 ASN1_TAILQ_FOREACH(m, t->members, members) { 330 char *s = NULL; 331 332 if (m->ellipsis) 333 continue; 334 335 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", 336 name, m->gen_name) < 0 || s == NULL) 337 errx(1, "malloc"); 338 decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL, 339 depth + 1); 340 free (s); 341 } 342 343 break; 344 } 345 case TSet: { 346 Member *m; 347 unsigned int memno; 348 349 if(t->members == NULL) 350 break; 351 352 fprintf(codefile, "{\n"); 353 fprintf(codefile, "unsigned int members = 0;\n"); 354 fprintf(codefile, "while(len > 0) {\n"); 355 fprintf(codefile, 356 "Der_class class;\n" 357 "Der_type type;\n" 358 "int tag;\n" 359 "e = der_get_tag (p, len, &class, &type, &tag, NULL);\n" 360 "if(e) %s;\n", forwstr); 361 fprintf(codefile, "switch (MAKE_TAG(class, type, tag)) {\n"); 362 memno = 0; 363 ASN1_TAILQ_FOREACH(m, t->members, members) { 364 char *s; 365 366 assert(m->type->type == TTag); 367 368 fprintf(codefile, "case MAKE_TAG(%s, %s, %s):\n", 369 classname(m->type->tag.tagclass), 370 is_primitive_type(m->type->subtype->type) ? "PRIM" : "CONS", 371 valuename(m->type->tag.tagclass, m->type->tag.tagvalue)); 372 373 if (asprintf (&s, "%s(%s)->%s", m->optional ? "" : "&", name, m->gen_name) < 0 || s == NULL) 374 errx(1, "malloc"); 375 if(m->optional) 376 fprintf(codefile, 377 "%s = calloc(1, sizeof(*%s));\n" 378 "if (%s == NULL) { e = ENOMEM; %s; }\n", 379 s, s, s, forwstr); 380 decode_type (s, m->type, 0, forwstr, m->gen_name, NULL, depth + 1); 381 free (s); 382 383 fprintf(codefile, "members |= (1 << %d);\n", memno); 384 memno++; 385 fprintf(codefile, "break;\n"); 386 } 387 fprintf(codefile, 388 "default:\n" 389 "return ASN1_MISPLACED_FIELD;\n" 390 "break;\n"); 391 fprintf(codefile, "}\n"); 392 fprintf(codefile, "}\n"); 393 memno = 0; 394 ASN1_TAILQ_FOREACH(m, t->members, members) { 395 char *s; 396 397 if (asprintf (&s, "%s->%s", name, m->gen_name) < 0 || s == NULL) 398 errx(1, "malloc"); 399 fprintf(codefile, "if((members & (1 << %d)) == 0)\n", memno); 400 if(m->optional) 401 fprintf(codefile, "%s = NULL;\n", s); 402 else if(m->defval) 403 gen_assign_defval(s, m->defval); 404 else 405 fprintf(codefile, "return ASN1_MISSING_FIELD;\n"); 406 free(s); 407 memno++; 408 } 409 fprintf(codefile, "}\n"); 410 break; 411 } 412 case TSetOf: 413 case TSequenceOf: { 414 char *n = NULL; 415 char *sname = NULL; 416 417 fprintf (codefile, 418 "{\n" 419 "size_t %s_origlen = len;\n" 420 "size_t %s_oldret = ret;\n" 421 "size_t %s_olen = 0;\n" 422 "void *%s_tmp;\n" 423 "ret = 0;\n" 424 "(%s)->len = 0;\n" 425 "(%s)->val = NULL;\n", 426 tmpstr, 427 tmpstr, 428 tmpstr, 429 tmpstr, 430 name, 431 name); 432 433 fprintf (codefile, 434 "while(ret < %s_origlen) {\n" 435 "size_t %s_nlen = %s_olen + sizeof(*((%s)->val));\n" 436 "if (%s_olen > %s_nlen) { e = ASN1_OVERFLOW; %s; }\n" 437 "%s_olen = %s_nlen;\n" 438 "%s_tmp = realloc((%s)->val, %s_olen);\n" 439 "if (%s_tmp == NULL) { e = ENOMEM; %s; }\n" 440 "(%s)->val = %s_tmp;\n", 441 tmpstr, 442 tmpstr, tmpstr, name, 443 tmpstr, tmpstr, forwstr, 444 tmpstr, tmpstr, 445 tmpstr, name, tmpstr, 446 tmpstr, forwstr, 447 name, tmpstr); 448 449 if (asprintf (&n, "&(%s)->val[(%s)->len]", name, name) < 0 || n == NULL) 450 errx(1, "malloc"); 451 if (asprintf (&sname, "%s_s_of", tmpstr) < 0 || sname == NULL) 452 errx(1, "malloc"); 453 decode_type (n, t->subtype, 0, forwstr, sname, NULL, depth + 1); 454 fprintf (codefile, 455 "(%s)->len++;\n" 456 "len = %s_origlen - ret;\n" 457 "}\n" 458 "ret += %s_oldret;\n" 459 "}\n", 460 name, 461 tmpstr, tmpstr); 462 if (t->range) 463 range_check(name, "len", forwstr, t->range); 464 free (n); 465 free (sname); 466 break; 467 } 468 case TGeneralizedTime: 469 decode_primitive ("generalized_time", name, forwstr); 470 break; 471 case TGeneralString: 472 decode_primitive ("general_string", name, forwstr); 473 break; 474 case TTeletexString: 475 decode_primitive ("general_string", name, forwstr); 476 break; 477 case TTag:{ 478 char *tname = NULL, *typestring = NULL; 479 char *ide = NULL; 480 481 if (asprintf(&typestring, "%s_type", tmpstr) < 0 || typestring == NULL) 482 errx(1, "malloc"); 483 484 fprintf(codefile, 485 "{\n" 486 "size_t %s_datalen, %s_oldlen;\n" 487 "Der_type %s;\n", 488 tmpstr, tmpstr, typestring); 489 if(support_ber) 490 fprintf(codefile, 491 "int is_indefinite%u;\n", depth); 492 493 fprintf(codefile, "e = der_match_tag_and_length(p, len, %s, &%s, %s, " 494 "&%s_datalen, &l);\n", 495 classname(t->tag.tagclass), 496 typestring, 497 valuename(t->tag.tagclass, t->tag.tagvalue), 498 tmpstr); 499 500 /* XXX hardcode for now */ 501 if (support_ber && t->subtype->type == TOctetString) { 502 ide = typestring; 503 } else { 504 fprintf(codefile, 505 "if (e == 0 && %s != %s) { e = ASN1_BAD_ID; }\n", 506 typestring, 507 is_primitive_type(t->subtype->type) ? "PRIM" : "CONS"); 508 } 509 510 if(optional) { 511 fprintf(codefile, 512 "if(e) {\n" 513 "%s = NULL;\n" 514 "} else {\n" 515 "%s = calloc(1, sizeof(*%s));\n" 516 "if (%s == NULL) { e = ENOMEM; %s; }\n", 517 name, name, name, name, forwstr); 518 } else { 519 fprintf(codefile, "if(e) %s;\n", forwstr); 520 } 521 fprintf (codefile, 522 "p += l; len -= l; ret += l;\n" 523 "%s_oldlen = len;\n", 524 tmpstr); 525 if(support_ber) 526 fprintf (codefile, 527 "if((is_indefinite%u = _heim_fix_dce(%s_datalen, &len)) < 0)\n" 528 "{ e = ASN1_BAD_FORMAT; %s; }\n" 529 "if (is_indefinite%u) { if (len < 2) { e = ASN1_OVERRUN; %s; } len -= 2; }", 530 depth, tmpstr, forwstr, depth, forwstr); 531 else 532 fprintf(codefile, 533 "if (%s_datalen > len) { e = ASN1_OVERRUN; %s; }\n" 534 "len = %s_datalen;\n", tmpstr, forwstr, tmpstr); 535 if (asprintf (&tname, "%s_Tag", tmpstr) < 0 || tname == NULL) 536 errx(1, "malloc"); 537 decode_type (name, t->subtype, 0, forwstr, tname, ide, depth + 1); 538 if(support_ber) 539 fprintf(codefile, 540 "if(is_indefinite%u){\n" 541 "len += 2;\n" 542 "e = der_match_tag_and_length(p, len, " 543 "(Der_class)0, &%s, UT_EndOfContent, " 544 "&%s_datalen, &l);\n" 545 "if(e) %s;\n" 546 "p += l; len -= l; ret += l;\n" 547 "if (%s != (Der_type)0) { e = ASN1_BAD_ID; %s; }\n" 548 "} else \n", 549 depth, 550 typestring, 551 tmpstr, 552 forwstr, 553 typestring, forwstr); 554 fprintf(codefile, 555 "len = %s_oldlen - %s_datalen;\n", 556 tmpstr, tmpstr); 557 if(optional) 558 fprintf(codefile, 559 "}\n"); 560 fprintf(codefile, 561 "}\n"); 562 free(tname); 563 free(typestring); 564 break; 565 } 566 case TChoice: { 567 Member *m, *have_ellipsis = NULL; 568 const char *els = ""; 569 570 if (t->members == NULL) 571 break; 572 573 ASN1_TAILQ_FOREACH(m, t->members, members) { 574 const Type *tt = m->type; 575 char *s = NULL; 576 Der_class cl; 577 Der_type ty; 578 unsigned tag; 579 580 if (m->ellipsis) { 581 have_ellipsis = m; 582 continue; 583 } 584 585 find_tag(tt, &cl, &ty, &tag); 586 587 fprintf(codefile, 588 "%sif (der_match_tag(p, len, %s, %s, %s, NULL) == 0) {\n", 589 els, 590 classname(cl), 591 ty ? "CONS" : "PRIM", 592 valuename(cl, tag)); 593 if (asprintf (&s, "%s(%s)->u.%s", m->optional ? "" : "&", 594 name, m->gen_name) < 0 || s == NULL) 595 errx(1, "malloc"); 596 decode_type (s, m->type, m->optional, forwstr, m->gen_name, NULL, 597 depth + 1); 598 fprintf(codefile, 599 "(%s)->element = %s;\n", 600 name, m->label); 601 free(s); 602 fprintf(codefile, 603 "}\n"); 604 els = "else "; 605 } 606 if (have_ellipsis) { 607 fprintf(codefile, 608 "else {\n" 609 "(%s)->u.%s.data = calloc(1, len);\n" 610 "if ((%s)->u.%s.data == NULL) {\n" 611 "e = ENOMEM; %s;\n" 612 "}\n" 613 "(%s)->u.%s.length = len;\n" 614 "memcpy((%s)->u.%s.data, p, len);\n" 615 "(%s)->element = %s;\n" 616 "p += len;\n" 617 "ret += len;\n" 618 "len = 0;\n" 619 "}\n", 620 name, have_ellipsis->gen_name, 621 name, have_ellipsis->gen_name, 622 forwstr, 623 name, have_ellipsis->gen_name, 624 name, have_ellipsis->gen_name, 625 name, have_ellipsis->label); 626 } else { 627 fprintf(codefile, 628 "else {\n" 629 "(%s)->element = ASN1_CHOICE_INVALID;\n" 630 "e = ASN1_PARSE_ERROR;\n" 631 "%s;\n" 632 "}\n", 633 name, forwstr); 634 } 635 break; 636 } 637 case TUTCTime: 638 decode_primitive ("utctime", name, forwstr); 639 break; 640 case TUTF8String: 641 decode_primitive ("utf8string", name, forwstr); 642 break; 643 case TPrintableString: 644 decode_primitive ("printable_string", name, forwstr); 645 break; 646 case TIA5String: 647 decode_primitive ("ia5_string", name, forwstr); 648 break; 649 case TBMPString: 650 decode_primitive ("bmp_string", name, forwstr); 651 break; 652 case TUniversalString: 653 decode_primitive ("universal_string", name, forwstr); 654 break; 655 case TVisibleString: 656 decode_primitive ("visible_string", name, forwstr); 657 break; 658 case TNull: 659 fprintf (codefile, "/* NULL */\n"); 660 break; 661 case TOID: 662 decode_primitive ("oid", name, forwstr); 663 break; 664 } 665 return 0; 666} 667 668void 669generate_type_decode (const Symbol *s) 670{ 671 int preserve = preserve_type(s->name) ? TRUE : FALSE; 672 673 fprintf (codefile, "int ASN1CALL\n" 674 "decode_%s(const unsigned char *p HEIMDAL_UNUSED_ATTRIBUTE," 675 " size_t len HEIMDAL_UNUSED_ATTRIBUTE, %s *data, size_t *size)\n" 676 "{\n", 677 s->gen_name, s->gen_name); 678 679 switch (s->type->type) { 680 case TInteger: 681 case TBoolean: 682 case TOctetString: 683 case TOID: 684 case TGeneralizedTime: 685 case TGeneralString: 686 case TTeletexString: 687 case TUTF8String: 688 case TPrintableString: 689 case TIA5String: 690 case TBMPString: 691 case TUniversalString: 692 case TVisibleString: 693 case TUTCTime: 694 case TNull: 695 case TEnumerated: 696 case TBitString: 697 case TSequence: 698 case TSequenceOf: 699 case TSet: 700 case TSetOf: 701 case TTag: 702 case TType: 703 case TChoice: 704 fprintf (codefile, 705 "size_t ret = 0;\n" 706 "size_t l HEIMDAL_UNUSED_ATTRIBUTE;\n" 707 "int e HEIMDAL_UNUSED_ATTRIBUTE;\n"); 708 if (preserve) 709 fprintf (codefile, "const unsigned char *begin = p;\n"); 710 711 fprintf (codefile, "\n"); 712 fprintf (codefile, "memset(data, 0, sizeof(*data));\n"); /* hack to avoid `unused variable' */ 713 714 decode_type ("data", s->type, 0, "goto fail", "Top", NULL, 1); 715 if (preserve) 716 fprintf (codefile, 717 "data->_save.data = calloc(1, ret);\n" 718 "if (data->_save.data == NULL) { \n" 719 "e = ENOMEM; goto fail; \n" 720 "}\n" 721 "data->_save.length = ret;\n" 722 "memcpy(data->_save.data, begin, ret);\n"); 723 fprintf (codefile, 724 "if(size) *size = ret;\n" 725 "return 0;\n"); 726 fprintf (codefile, 727 "fail:\n" 728 "free_%s(data);\n" 729 "return e;\n", 730 s->gen_name); 731 break; 732 } 733 fprintf (codefile, "}\n\n"); 734} 735