buffers.c (15279B)
1 /* Mixmaster version 3.0 -- (C) 1999 - 2006 Anonymizer Inc. and others. 2 3 Mixmaster may be redistributed and modified under certain conditions. 4 This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF 5 ANY KIND, either express or implied. See the file COPYRIGHT for 6 details. 7 8 Dynamically allocated buffers 9 $Id: buffers.c 934 2006-06-24 13:40:39Z rabbi $ */ 10 11 12 #include "mix3.h" 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <ctype.h> 17 #include <stdarg.h> 18 #ifdef WIN32 19 #include <io.h> 20 #endif /* WIN32 */ 21 #include <assert.h> 22 #ifdef POSIX 23 #include <unistd.h> 24 #endif /* POSIX */ 25 26 static void fail(void) 27 { 28 errlog(ERRORMSG, "Out of memory!\n"); 29 abort(); 30 } 31 32 #define space 128 /* allocate some additional space */ 33 34 static void alloc(BUFFER *b) 35 { 36 b->data = malloc(space); 37 if (b->data == NULL) 38 fail(); 39 b->data[0] = 0; 40 b->size = space; 41 } 42 43 #undef buf_new /* DEBUG */ 44 BUFFER *buf_new(void) 45 { 46 BUFFER *b; 47 48 b = malloc(sizeof(BUFFER)); 49 if (b == NULL) 50 fail(); 51 alloc(b); 52 b->length = 0; 53 b->ptr = 0; 54 b->sensitive = 0; 55 56 return (b); 57 } 58 59 #ifdef DEBUG 60 static void sanity_check(BUFFER *b) 61 { 62 assert(b != NULL); 63 assert(b->size > 0); 64 assert(b->data != NULL); 65 assert(b->length >= 0 && b->length < b->size); 66 assert(b->ptr >= 0 && b->ptr <= b->length); 67 } 68 #else /* not DEBUG */ 69 #define sanity_check(arg) 70 #endif /* else not DEBUG */ 71 72 int buf_reset(BUFFER *buffer) 73 { 74 sanity_check(buffer); 75 76 buffer->length = 0; 77 buffer->ptr = 0; 78 if (buffer->sensitive) 79 memset(buffer->data, 0, buffer->size); 80 free(buffer->data); 81 alloc(buffer); 82 return (0); 83 } 84 85 int buf_free(BUFFER *buffer) 86 { 87 int err = 0; 88 89 if (buffer->sensitive) 90 memset(buffer->data, 0, buffer->size); 91 free(buffer->data); 92 free(buffer); 93 return (err); 94 } 95 96 int buf_clear(BUFFER *buffer) 97 { 98 sanity_check(buffer); 99 buffer->data[0] = '\0'; 100 buffer->length = 0; 101 buffer->ptr = 0; 102 return (0); 103 } 104 105 int buf_append(BUFFER *buffer, byte *msg, int len) 106 { 107 assert(len >= 0); 108 sanity_check(buffer); 109 110 if (buffer->length + len >= buffer->size) { 111 register byte *new; 112 register long newsize; 113 114 newsize = 2 * buffer->length; /* double buffer size */ 115 if (newsize < buffer->length + len + space) 116 newsize = buffer->length + len + space; 117 new = malloc(newsize); 118 if (new == NULL) 119 fail(); 120 memcpy(new, buffer->data, buffer->length); 121 if (buffer->sensitive) 122 memset(buffer->data, 0, buffer->size); 123 free(buffer->data); 124 buffer->data = new; 125 buffer->size = newsize; 126 } 127 if (msg != NULL) 128 memcpy(buffer->data + buffer->length, msg, len); 129 buffer->length += len; 130 131 buffer->data[buffer->length] = 0; 132 return (0); 133 } 134 135 int buf_appendrnd(BUFFER *to, int n) 136 { 137 buf_append(to, NULL, n); 138 rnd_bytes(to->data + to->length - n, n); 139 return (0); 140 } 141 142 int buf_appendzero(BUFFER *to, int n) 143 { 144 buf_append(to, NULL, n); 145 memset(to->data + to->length - n, 0, n); 146 return (0); 147 } 148 149 int buf_setrnd(BUFFER *b, int n) 150 { 151 buf_prepare(b, n); 152 rnd_bytes(b->data, n); 153 return (0); 154 } 155 156 int buf_cat(BUFFER *to, BUFFER *from) 157 { 158 return (buf_append(to, from->data, from->length)); 159 } 160 161 int buf_set(BUFFER *to, BUFFER *from) 162 { 163 buf_reset(to); 164 return (buf_cat(to, from)); 165 } 166 167 int buf_appendc(BUFFER *to, byte b) 168 { 169 return (buf_append(to, &b, 1)); 170 } 171 172 int buf_rest(BUFFER *to, BUFFER *from) 173 { 174 assert(from != to); 175 return (buf_append(to, from->data + from->ptr, from->length - from->ptr)); 176 } 177 178 int buf_appends(BUFFER *buffer, char *s) 179 { 180 return (buf_append(buffer, s, strlen(s))); 181 } 182 183 int buf_sets(BUFFER *buffer, char *s) 184 { 185 buf_clear(buffer); 186 return (buf_appends(buffer, s)); 187 } 188 189 int buf_setc(BUFFER *buffer, byte c) 190 { 191 buf_clear(buffer); 192 return (buf_appendc(buffer, c)); 193 } 194 195 int buf_nl(BUFFER *b) 196 { 197 return (buf_append(b, "\n", 1)); 198 } 199 200 int buf_vappendf(BUFFER *b, char *fmt, va_list args) 201 { 202 for (; *fmt != '\0'; fmt++) 203 if (*fmt == '%') { 204 int lzero = 0; 205 int longvar = 0; 206 int len = 0; 207 208 for (;;) { 209 if (*++fmt == '\0') 210 return (-1); 211 if (*fmt == '%') { 212 buf_appendc(b, '%'); 213 break; 214 } else if (*fmt == 'b') { /* extension of printf */ 215 buf_cat(b, va_arg(args, BUFFER *)); 216 217 break; 218 } else if (*fmt == 'c') { 219 buf_appendc(b, va_arg(args, int)); 220 221 break; 222 } else if (*fmt == 's') { 223 buf_appends(b, va_arg(args, char *)); 224 225 break; 226 } else if (*fmt == 'd' || *fmt == 'X') { 227 int base, val, sign = 0; 228 BUFFER *out; 229 230 out = buf_new(); 231 base = *fmt == 'd' ? 10 : 16; 232 if (longvar) 233 val = va_arg(args, long); 234 235 else 236 val = va_arg(args, int); 237 238 if (val < 0) 239 sign = 1, val = -val; 240 do { 241 if (val % base > 9) 242 buf_appendc(out, val % base - 10 + 'A'); 243 else 244 buf_appendc(out, val % base + '0'); 245 val /= base; 246 } while (val > 0); 247 if (sign) 248 len--; 249 while (len-- > out->length) 250 buf_appendc(b, lzero ? '0' : ' '); 251 if (sign) 252 buf_appendc(b, '-'); 253 for (len = out->length - 1; len >= 0; len--) 254 buf_appendc(b, out->data[len]); 255 buf_free(out); 256 break; 257 } else if (*fmt == 'l') 258 longvar = 1; 259 else if (*fmt == '0' && len == 0) 260 lzero = 1; 261 else if (isdigit(*fmt)) 262 len = len * 10 + *fmt - '0'; 263 else 264 assert(0); 265 } 266 } else 267 buf_appendc(b, *fmt); 268 return (0); 269 } 270 271 int buf_setf(BUFFER *b, char *fmt, ...) 272 { 273 va_list args; 274 int ret; 275 276 va_start(args, fmt); 277 buf_clear(b); 278 ret = buf_vappendf(b, fmt, args); 279 va_end(args); 280 return (ret); 281 } 282 283 int buf_appendf(BUFFER *b, char *fmt, ...) 284 { 285 va_list args; 286 int ret; 287 288 va_start(args, fmt); 289 ret = buf_vappendf(b, fmt, args); 290 va_end(args); 291 return (ret); 292 } 293 294 int buf_pad(BUFFER *buffer, int size) 295 { 296 assert(size - buffer->length >= 0); 297 buf_appendrnd(buffer, size - buffer->length); 298 return (0); 299 } 300 301 int buf_prepare(BUFFER *buffer, int size) 302 { 303 buf_clear(buffer); 304 buf_append(buffer, NULL, size); 305 return (0); 306 } 307 308 int buf_read(BUFFER *outmsg, FILE *infile) 309 { 310 char buf[BUFSIZE]; 311 int n; 312 int err = -1; 313 314 assert(infile != NULL); 315 sanity_check(outmsg); 316 317 for (;;) { 318 n = fread(buf, 1, BUFSIZE, infile); 319 if (n > 0) 320 err = 0; 321 buf_append(outmsg, buf, n); 322 if (n < BUFSIZE) 323 break; 324 #ifdef BUFFER_MAX 325 if (outmsg->length > BUFFER_MAX) { 326 errlog(ERRORMSG, "Message file too large. Giving up.\n"); 327 return (1); 328 } 329 #endif /* BUFFER_MAX */ 330 } 331 332 #ifdef WIN32 333 if (isatty(fileno(infile)) && isatty(fileno(stdout))) 334 printf("\n"); 335 #endif /* WIN32 */ 336 337 return (err); 338 } 339 340 int buf_write(BUFFER *buffer, FILE *out) 341 { 342 assert(out != NULL); 343 sanity_check(buffer); 344 345 return (fwrite(buffer->data, 1, buffer->length, out) == buffer->length 346 ? 0 : -1); 347 } 348 349 int buf_write_sync(BUFFER *buffer, FILE *out) 350 { 351 int ret = 0; 352 353 if (buf_write(buffer, out) == -1) { 354 fclose(out); 355 return -1; 356 } 357 358 if (fflush(out) != 0) 359 ret = -1; 360 361 #ifdef POSIX 362 /* dir entry not synced */ 363 if (fsync(fileno(out)) != 0) 364 ret = -1; 365 #endif /* POSIX */ 366 367 if (fclose(out) != 0) 368 ret = -1; 369 370 return ret; 371 } 372 373 int buf_rewind(BUFFER *buffer) 374 { 375 sanity_check(buffer); 376 377 buffer->ptr = 0; 378 return (0); 379 } 380 381 int buf_get(BUFFER *buffer, BUFFER *to, int n) 382 { 383 sanity_check(buffer); 384 sanity_check(to); 385 assert(n > 0); 386 assert(buffer != to); 387 388 buf_clear(to); 389 if (buffer->length - buffer->ptr < n) 390 return (-1); 391 buf_append(to, buffer->data + buffer->ptr, n); 392 buffer->ptr += n; 393 return (0); 394 } 395 396 int buf_getc(BUFFER *buffer) 397 { 398 sanity_check(buffer); 399 if (buffer->ptr == buffer->length) 400 return (-1); 401 else 402 return (buffer->data[buffer->ptr++]); 403 } 404 405 void buf_ungetc(BUFFER *buffer) 406 { 407 sanity_check(buffer); 408 if (buffer->ptr > 0) 409 buffer->ptr--; 410 } 411 412 int buf_getline(BUFFER *buffer, BUFFER *line) 413 { 414 register int i; 415 int ret = 0; 416 int nl = 0; 417 418 sanity_check(buffer); 419 420 if (line != NULL) 421 buf_clear(line); 422 if (buffer->ptr == buffer->length) 423 return (-1); 424 425 for (i = buffer->ptr; i < buffer->length; i++) { 426 if (buffer->data[i] > '\r') 427 continue; 428 if (buffer->data[i] == '\0' || buffer->data[i] == '\n') { 429 nl = 1; 430 break; 431 } 432 if (buffer->data[i] == '\r' && 433 i + 1 <= buffer->length && buffer->data[i + 1] == '\n') { 434 nl = 2; 435 break; 436 } 437 } 438 439 if (line != NULL) 440 buf_append(line, buffer->data + buffer->ptr, i - buffer->ptr); 441 if (i == buffer->ptr) 442 ret = 1; 443 buffer->ptr = i + nl; 444 445 return (ret); 446 } 447 448 int buf_chop(BUFFER *b) 449 { 450 int i; 451 452 sanity_check(b); 453 454 for (i = 0; i < b->length; i++) 455 if (b->data[i] == '\0' || b->data[i] == '\n' || 456 (b->data[i] == '\r' && i + 1 < b->length && 457 b->data[i + 1] == '\n')) 458 b->length = i; 459 b->data[b->length] = 0; 460 return (0); 461 } 462 463 int buf_isheader(BUFFER *buffer) 464 { 465 BUFFER *line; 466 long p; 467 int i; 468 int err; 469 int ret; 470 471 line = buf_new(); 472 p = buffer->ptr; 473 ret = 0; 474 err = buf_getline(buffer, line); 475 if (err != 0) 476 goto end; 477 478 for (i = 0; i < line->length; i++) { 479 if (line->data[i] == ' ' || line->data[i] == '\t') 480 break; 481 if (line->data[i] == ':') { 482 ret = 1; 483 break; 484 } 485 } 486 487 end: 488 buffer->ptr = p; 489 buf_free(line); 490 return(ret); 491 } 492 493 int buf_getheader(BUFFER *buffer, BUFFER *field, BUFFER *content) 494 { 495 BUFFER *line; 496 long p; 497 int i; 498 int err; 499 500 line = buf_new(); 501 buf_reset(field); 502 buf_reset(content); 503 504 err = buf_getline(buffer, line); 505 if (err != 0) 506 goto end; 507 508 err = -1; 509 for (i = 0; i < line->length; i++) { 510 if (line->data[i] == ' ' || line->data[i] == '\t') 511 break; 512 if (line->data[i] == ':') { 513 err = 0; 514 break; 515 } 516 } 517 if (err == -1 && bufileft(line, "From ")) { 518 buf_set(field, line); 519 err = 0; 520 } 521 if (err == -1) { 522 /* badly formatted message -- try to process anyway */ 523 buf_sets(field, "X-Invalid"); 524 buf_set(content, line); 525 err = 0; 526 goto end; 527 } 528 buf_append(field, line->data, i); 529 if (i < line->length) 530 i++; 531 else 532 err = 1; 533 while (i < line->length && 534 (line->data[i] == ' ' || line->data[i] == '\t')) 535 i++; 536 buf_append(content, line->data + i, line->length - i); 537 538 for (;;) { 539 p = buffer->ptr; 540 if (buf_getline(buffer, line) != 0) 541 break; 542 if (line->data[0] != ' ' && line->data[0] != '\t') 543 break; 544 #if 1 545 buf_nl(content); 546 buf_cat(content, line); 547 #else /* end of 1 */ 548 buf_appendc(content, ' '); 549 buf_appends(content, line->data + 1); 550 #endif /* else if not 1 */ 551 } 552 buffer->ptr = p; 553 end: 554 buf_free(line); 555 return (err); 556 } 557 558 int buf_appendheader(BUFFER *buffer, BUFFER *field, BUFFER *content) 559 { 560 return buf_appendf(buffer, "%b: %b\n", field, content); 561 } 562 563 int buf_lookahead(BUFFER *buffer, BUFFER *line) 564 { 565 long p; 566 int e; 567 568 p = buffer->ptr; 569 e = buf_getline(buffer, line); 570 buffer->ptr = p; 571 return (e); 572 } 573 574 int buf_eq(BUFFER *b1, BUFFER *b2) 575 { 576 sanity_check(b1); 577 sanity_check(b2); 578 579 if (b1->length != b2->length) 580 return (0); 581 if (b1->length > 0 && memcmp(b1->data, b2->data, b1->length) != 0) 582 return (0); 583 return (1); 584 } 585 586 int buf_ieq(BUFFER *b1, BUFFER *b2) 587 { 588 int i; 589 sanity_check(b1); 590 sanity_check(b2); 591 592 if (b1->length != b2->length) 593 return (0); 594 for (i = 0; i < b1->length; i++) 595 if (tolower(b1->data[i]) != tolower(b2->data[i])) 596 return (0); 597 return (1); 598 } 599 600 void buf_move(BUFFER *dest, BUFFER *src) 601 /* equivalent to buf_set(dest, src); buf_reset(src); */ 602 { 603 BUFFER temp; 604 sanity_check(src); 605 buf_reset(dest); 606 temp.data = dest->data, temp.size = dest->size; 607 dest->data = src->data, dest->size = src->size, dest->length = src->length; 608 src->data = temp.data, src->size = temp.size, src->length = 0; 609 dest->ptr = 0, src->ptr = 0; 610 } 611 612 int buf_appendl(BUFFER *b, long l) 613 { 614 buf_appendc(b, (l >> 24) & 255); 615 buf_appendc(b, (l >> 16) & 255); 616 buf_appendc(b, (l >> 8) & 255); 617 buf_appendc(b, l & 255); 618 return (0); 619 } 620 621 int buf_appendl_lo(BUFFER *b, long l) 622 { 623 buf_appendc(b, l & 255); 624 buf_appendc(b, (l >> 8) & 255); 625 buf_appendc(b, (l >> 16) & 255); 626 buf_appendc(b, (l >> 24) & 255); 627 return (0); 628 } 629 630 long buf_getl(BUFFER *b) 631 { 632 long l; 633 634 if (b->ptr + 4 > b->length) 635 return (-1); 636 l = buf_getc(b) << 24; 637 l += buf_getc(b) << 16; 638 l += buf_getc(b) << 8; 639 l += buf_getc(b); 640 return (l); 641 } 642 643 long buf_getl_lo(BUFFER *b) 644 { 645 long l; 646 647 if (b->ptr + 4 > b->length) 648 return (-1); 649 l = buf_getc(b); 650 l += buf_getc(b) << 8; 651 l += buf_getc(b) << 16; 652 l += buf_getc(b) << 24; 653 654 return (l); 655 } 656 657 int buf_appendi(BUFFER *b, int i) 658 { 659 buf_appendc(b, (i >> 8) & 255); 660 buf_appendc(b, i & 255); 661 return (0); 662 } 663 664 int buf_appendi_lo(BUFFER *b, int i) 665 { 666 buf_appendc(b, i & 255); 667 buf_appendc(b, (i >> 8) & 255); 668 return (0); 669 } 670 671 int buf_geti(BUFFER *b) 672 { 673 int i; 674 675 if (b->ptr + 2 > b->length) 676 return (-1); 677 i = buf_getc(b) << 8; 678 i += buf_getc(b); 679 return (i); 680 } 681 682 int buf_geti_lo(BUFFER *b) 683 { 684 int i; 685 686 if (b->ptr + 2 > b->length) 687 return (-1); 688 i = buf_getc(b); 689 i += buf_getc(b) << 8; 690 return (i); 691 } 692 693 int buf_getb(BUFFER *b, BUFFER *p) 694 { 695 long l; 696 697 l = buf_getl(b); 698 return (buf_get(b, p, l)); 699 } 700 701 int buf_appendb(BUFFER *b, BUFFER *p) 702 { 703 long l; 704 705 l = p->length; 706 buf_appendl(b, l); 707 return (buf_cat(b, p)); 708 } 709 710 int bufleft(BUFFER *b, char *k) { 711 return(strleft(b->data, k)); 712 } 713 714 int bufileft(BUFFER *b, char *k) { 715 return(strileft(b->data, k)); 716 } 717 718 int buffind(BUFFER *b, char *k) { 719 return(strfind(b->data, k)); 720 } 721 722 int bufifind(BUFFER *b, char *k) { 723 return(strifind(b->data, k)); 724 } 725 726 int bufiright(BUFFER *b, char *k) { 727 int l = strlen(k); 728 if (l <= b->length) 729 return (strieq(b->data + b->length - l, k)); 730 return(0); 731 } 732 733 int bufeq(BUFFER *b, char *k) { 734 return(streq(b->data, k)); 735 } 736 737 int bufieq(BUFFER *b, char *k) { 738 return(strieq(b->data, k)); 739 } 740 741 /* void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest, 742 * int from, int len); 743 * 744 * Cut a chunk out of the buffer. 745 * 746 * Starting with from, len bytes are cut out of buffer. The chunk 747 * of text that has been cut out is returned in cut_out, the 748 * remainings of buffer are returned in rest. 749 * 750 * This function was added by Gerd Beuster. (gb@uni-koblenz.de) 751 */ 752 753 void buf_cut_out(BUFFER *buffer, BUFFER *cut_out, BUFFER *rest, 754 int from, int len){ 755 756 assert((len >= 0) && (from >= 0)); 757 assert(from+len <= buffer->length); 758 assert(cut_out != rest); 759 760 buffer->ptr = 0; 761 if(from > 0) 762 buf_get(buffer, rest, from); 763 buf_get(buffer, cut_out, len); 764 buf_rest(rest, buffer); 765 } 766 767 768 #ifdef DEBUG 769 /* check for memory leaks */ 770 #undef malloc 771 #undef free 772 void *malloc(size_t size); 773 void free(void *ptr); 774 #define max 100000 775 static int n=0; 776 static void *m[max]; 777 static char *mm[max]; 778 779 void mix3_leaks(void) { 780 int i, ok=1; 781 for (i = 0; i < n; i++) 782 if (m[i]) { 783 fprintf(stderr, "Leak [%d] %s\n", i, mm[i]); 784 ok = 0; 785 } 786 if (ok) 787 fprintf(stderr, "No memory leaks.\n"); 788 } 789 790 void *mix3_malloc(size_t size) { 791 void *ptr; 792 if (n == 0) 793 atexit(mix3_leaks); 794 ptr = malloc(size); 795 if (n >= max) abort(); 796 m[n++] = ptr; 797 mm[n] = "?"; 798 return(ptr); 799 } 800 801 void mix3_free(void *ptr) { 802 int i; 803 for (i = 0; i < n; i++) 804 if (m[i] == ptr) { 805 m[i] = 0; 806 break; 807 } 808 free(ptr); 809 } 810 811 BUFFER *mix3_bufnew(char *file, int line, char *func) { 812 mm[n] = malloc(strlen(file) + strlen(func) + 15); 813 sprintf(mm[n], "in %s %s:%d", func, file, line); 814 return(buf_new()); 815 } 816 #endif /* DEBUG */