00001
00002 #include <ctype.h>
00003 #include <errno.h>
00004 #include <iconv.h>
00005 #include <limits.h>
00006 #include <signal.h>
00007 #include <stdarg.h>
00008 #include <stdio.h>
00009 #include <stdlib.h>
00010 #include <string.h>
00011
00012 #include "define.h"
00013 #include "vbuf.h"
00014
00015 #ifdef WITH_DMALLOC
00016 #include <dmalloc.h>
00017 #endif
00018
00019 #define STUPID_CR "\r\n"
00020 #define ASSERT(x,...) { if( !(x) ) DIE(( __VA_ARGS__)); }
00021
00022
00023 int skip_nl(char *s)
00024 {
00025 if (s[0] == '\n')
00026 return 1;
00027 if (s[0] == '\r' && s[1] == '\n')
00028 return 2;
00029 if (s[0] == '\0')
00030 return 0;
00031 return -1;
00032 }
00033
00034
00035 int find_nl(vstr * vs)
00036 {
00037 char *nextr, *nextn;
00038
00039 nextr = memchr(vs->b, '\r', vs->dlen);
00040 nextn = memchr(vs->b, '\n', vs->dlen);
00041
00042
00043 if (nextn && (nextr == NULL || nextr > nextn)) {
00044 return nextn - vs->b;
00045 }
00046
00047 if (NULL != nextr && NULL != nextn && 1 == (char *) nextn - (char *) nextr) {
00048 return nextr - vs->b;
00049 }
00050
00051
00052 return -1;
00053 }
00054
00055
00056
00057
00058
00059 char *wwbuf = NULL;
00060 size_t nwwbuf = 0;
00061 static int unicode_up = 0;
00062 iconv_t i16to8, i8to16, i8859_1to8, i8toi8859_1;
00063
00064
00065 void unicode_init()
00066 {
00067 char *wipe = "";
00068 char dump[4];
00069
00070 if (unicode_up)
00071 unicode_close();
00072
00073 if ((iconv_t) - 1 == (i16to8 = iconv_open("UTF-8", "UTF-16LE"))) {
00074 fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-16LE to UTF-8.\n");
00075 exit(1);
00076 }
00077
00078 if ((iconv_t) - 1 == (i8to16 = iconv_open("UTF-16LE", "UTF-8"))) {
00079 fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-8 to UTF-16LE.\n");
00080 exit(2);
00081 }
00082
00083 memset(dump, 'x', 4);
00084 ASSERT(0 == utf8to16(wipe, 1, dump, 4), "unicode_init(): attempt to dump FF FE failed.");
00085
00086 if ((iconv_t) - 1 == (i8859_1to8 = iconv_open("UTF-8", "ISO_8859-1"))) {
00087 fprintf(stderr, "doexport(): Couldn't open iconv descriptor for ASCII to UTF-8.\n");
00088 exit(1);
00089 }
00090
00091 if ((iconv_t) - 1 == (i8toi8859_1 = iconv_open("ISO_8859-1", "UTF-8"))) {
00092 fprintf(stderr, "doexport(): Couldn't open iconv descriptor for UTF-8 to ASCII.\n");
00093 exit(1);
00094 }
00095
00096 unicode_up = 1;
00097 }
00098
00099
00100 void unicode_close()
00101 {
00102 unicode_up = 0;
00103 iconv_close(i8to16);
00104 iconv_close(i16to8);
00105 iconv_close(i8859_1to8);
00106 iconv_close(i8toi8859_1);
00107 }
00108
00109
00110 int utf16_is_terminated(char *str, int length)
00111 {
00112 VSTR_STATIC(errbuf, 100);
00113 int len = -1;
00114 int i;
00115 for (i = 0; i < length; i += 2) {
00116 if (str[i] == 0 && str[i + 1] == 0) {
00117 len = i;
00118 }
00119 }
00120
00121 if (-1 == len) {
00122 vshexdump(errbuf, str, 0, length, 1);
00123 WARN(("String is not zero terminated (probably broken data from registry) %s.", errbuf->b));
00124 }
00125
00126 return (-1 == len) ? 0 : 1;
00127 }
00128
00129
00130 int vb_utf16to8(vbuf * dest, char *buf, int len)
00131 {
00132 size_t inbytesleft = len;
00133 char *inbuf = buf;
00134 size_t icresult = (size_t)-1;
00135 VBUF_STATIC(dumpster, 100);
00136
00137 size_t outbytesleft = 0;
00138 char *outbuf = NULL;
00139
00140 ASSERT(unicode_up, "vb_utf16to8() called before unicode started.");
00141
00142 if (2 > dest->blen)
00143 vbresize(dest, 2);
00144 dest->dlen = 0;
00145
00146
00147 if (!utf16_is_terminated(buf, len))
00148 return -1;
00149
00150 do {
00151 outbytesleft = dest->blen - dest->dlen;
00152 outbuf = dest->b + dest->dlen;
00153 icresult = iconv(i16to8, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
00154 dest->dlen = outbuf - dest->b;
00155 vbgrow(dest, inbytesleft);
00156 } while ((size_t)-1 == icresult && E2BIG == errno);
00157
00158 if (0 != vb_utf8to16T(dumpster, dest->b, dest->dlen))
00159 DIE(("Reverse conversion failed."));
00160
00161 if (icresult == (size_t)-1) {
00162
00163
00164 unicode_init();
00165 return -1;
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 }
00181
00182 if (icresult) {
00183
00184 return -1;
00185 }
00186 return icresult;
00187 }
00188
00189
00190 int utf8to16(char *inbuf_o, int iblen, char *outbuf_o, int oblen)
00191 {
00192
00193
00194 size_t inbytesleft = 0;
00195 size_t outbytesleft = oblen;
00196 char *inbuf = inbuf_o;
00197 char *outbuf = outbuf_o;
00198 size_t icresult = (size_t)-1;
00199 char *stend;
00200
00201 stend = memchr(inbuf_o, '\0', iblen);
00202 ASSERT(NULL != stend, "utf8to16(): in string not zero terminated.");
00203 inbytesleft = (stend - inbuf_o + 1 < iblen) ? stend - inbuf_o + 1 : iblen;
00204 icresult = iconv(i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
00205
00206 if (icresult == (size_t)-1) {
00207 DIE(("iconv failure(%d): %s\n", errno, strerror(errno)));
00208 }
00209 if (icresult > (size_t)INT_MAX) {
00210 return (-1);
00211 }
00212 return (int) icresult;
00213 }
00214
00215
00216 int vb_utf8to16T(vbuf * bout, char *cin, int inlen)
00217 {
00218
00219 size_t inbytesleft = inlen;
00220 char *inbuf = cin;
00221
00222 size_t icresult = (size_t)-1;
00223 size_t outbytesleft = 0;
00224 char *outbuf = NULL;
00225
00226 if (2 > bout->blen)
00227 vbresize(bout, 2);
00228 bout->dlen = 0;
00229
00230 do {
00231 outbytesleft = bout->blen - bout->dlen;
00232 outbuf = bout->b + bout->dlen;
00233 icresult = iconv(i8to16, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
00234 bout->dlen = outbuf - bout->b;
00235 vbgrow(bout, 20);
00236 } while ((size_t)-1 == icresult && E2BIG == errno);
00237
00238 if (icresult == (size_t)-1) {
00239 WARN(("iconv failure: %s", strerror(errno)));
00240 unicode_init();
00241 return -1;
00242 }
00243 if (icresult > (size_t) INT_MAX) {
00244 return (-1);
00245 }
00246 return icresult;
00247 }
00248
00249
00250
00251 void cheap_uni2ascii(char *src, char *dest, int l)
00252 {
00253
00254 for (; l > 0; l -= 2) {
00255 *dest = *src;
00256 dest++;
00257 src += 2;
00258 }
00259 *dest = 0;
00260 }
00261
00262
00263
00264 void cheap_ascii2uni(char *src, char *dest, int l)
00265 {
00266 for (; l > 0; l--) {
00267 *dest++ = *src++;
00268 *dest++ = 0;
00269
00270 }
00271 }
00272
00273
00274 vbuf *vballoc(size_t len)
00275 {
00276 struct varbuf *result = malloc(sizeof(struct varbuf));
00277 if (result) {
00278 result->dlen = 0;
00279 result->blen = 0;
00280 result->buf = NULL;
00281 vbresize(result, len);
00282 }
00283 else DIE(("malloc() failure"));
00284 return result;
00285 }
00286
00287
00288 void vbcheck(vbuf * vb)
00289 {
00290 ASSERT(vb->b >= vb->buf, "vbcheck(): data not inside buffer");
00291 ASSERT((size_t)(vb->b - vb->buf) <= vb->blen, "vbcheck(): vb->b outside of buffer range.");
00292 ASSERT(vb->dlen <= vb->blen, "vbcheck(): data length > buffer length.");
00293 ASSERT(vb->blen < 1024 * 1024, "vbcheck(): blen is a bit large...hmmm.");
00294 }
00295
00296
00297 void vbfree(vbuf * vb)
00298 {
00299 free(vb->buf);
00300 free(vb);
00301 }
00302
00303
00304 void vbclear(struct varbuf *vb)
00305 {
00306 vbresize(vb, 0);
00307 }
00308
00309
00310 void vbresize(struct varbuf *vb, size_t len)
00311 {
00312 vb->dlen = 0;
00313
00314 if (vb->blen >= len) {
00315 vb->b = vb->buf;
00316 return;
00317 }
00318
00319 vb->buf = realloc(vb->buf, len);
00320 vb->b = vb->buf;
00321 vb->blen = len;
00322 }
00323
00324
00325 size_t vbavail(vbuf * vb)
00326 {
00327 return vb->blen - vb->dlen - (size_t)(vb->b - vb->buf);
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345 void vbgrow(struct varbuf *vb, size_t len)
00346 {
00347 if (0 == len)
00348 return;
00349
00350 if (0 == vb->blen) {
00351 vbresize(vb, len);
00352 return;
00353 }
00354
00355 if (vb->dlen + len > vb->blen) {
00356 if (vb->dlen + len < vb->blen * 1.5)
00357 len = vb->blen * 1.5;
00358 char *nb = malloc(vb->blen + len);
00359 if (!nb) DIE(("malloc() failure"));
00360 vb->blen = vb->blen + len;
00361 memcpy(nb, vb->b, vb->dlen);
00362
00363 free(vb->buf);
00364 vb->buf = nb;
00365 vb->b = vb->buf;
00366 } else {
00367 if (vb->b != vb->buf)
00368 memcpy(vb->buf, vb->b, vb->dlen);
00369 }
00370
00371 vb->b = vb->buf;
00372
00373 ASSERT(vbavail(vb) >= len, "vbgrow(): I have failed in my mission.");
00374 }
00375
00376
00377 void vbset(vbuf * vb, void *b, size_t len)
00378 {
00379 vbresize(vb, len);
00380
00381 memcpy(vb->b, b, len);
00382 vb->dlen = len;
00383 }
00384
00385
00386 void vsskipws(vstr * vs)
00387 {
00388 char *p = vs->b;
00389 while ((size_t)(p - vs->b) < vs->dlen && isspace(p[0]))
00390 p++;
00391
00392 vbskip((vbuf *) vs, p - vs->b);
00393 }
00394
00395
00396
00397 void vbappend(struct varbuf *vb, void *b, size_t len)
00398 {
00399 if (0 == vb->dlen) {
00400 vbset(vb, b, len);
00401 return;
00402 }
00403 vbgrow(vb, len);
00404 memcpy(vb->b + vb->dlen, b, len);
00405 vb->dlen += len;
00406 }
00407
00408
00409
00410 void vbskip(struct varbuf *vb, size_t skip)
00411 {
00412 ASSERT(skip <= vb->dlen, "vbskip(): Attempt to seek past end of buffer.");
00413 vb->b += skip;
00414 vb->dlen -= skip;
00415 }
00416
00417
00418
00419 void vboverwrite(struct varbuf *vbdest, struct varbuf *vbsrc)
00420 {
00421 vbresize(vbdest, vbsrc->blen);
00422 memcpy(vbdest->b, vbsrc->b, vbsrc->dlen);
00423 vbdest->blen = vbsrc->blen;
00424 vbdest->dlen = vbsrc->dlen;
00425 }
00426
00427
00428 vstr *vsalloc(size_t len)
00429 {
00430 vstr *result = (vstr *) vballoc(len + 1);
00431 vsset(result, "");
00432 return result;
00433 }
00434
00435
00436 char *vsstr(vstr * vs)
00437 {
00438 return vs->b;
00439 }
00440
00441
00442 size_t vslen(vstr * vs)
00443 {
00444 return strlen(vsstr(vs));
00445 }
00446
00447
00448 void vsfree(vstr * vs)
00449 {
00450 vbfree((vbuf *) vs);
00451 }
00452
00453
00454 void vscharcat(vstr * vb, int ch)
00455 {
00456 vbgrow((vbuf *) vb, 1);
00457 vb->b[vb->dlen - 1] = ch;
00458 vb->b[vb->dlen] = '\0';
00459 vb->dlen++;
00460 }
00461
00462
00463
00464 void vsnprepend(vstr * vb, char *str, size_t len)
00465 {
00466 ASSERT(vb->b[vb->dlen - 1] == '\0', "vsncat(): attempt to append string to non-string.");
00467 size_t sl = strlen(str);
00468 size_t n = (sl < len) ? sl : len;
00469 vbgrow((vbuf *) vb, n + 1);
00470 memmove(vb->b + n, vb->b, vb->dlen - 1);
00471 memcpy(vb->b, str, n);
00472 vb->dlen += n;
00473 vb->b[vb->dlen - 1] = '\0';
00474 }
00475
00476
00477
00478 void vsskip(vstr * vs, size_t len)
00479 {
00480 ASSERT(len < vs->dlen - 1, "Attempt to skip past end of string");
00481 vbskip((vbuf *) vs, len);
00482 }
00483
00484
00485
00486 int vsskipline(vstr * vs)
00487 {
00488 int nloff = find_nl(vs);
00489 int nll = skip_nl(vs->b + nloff);
00490
00491 if (nloff < 0) {
00492
00493 printf("vb_skipline(): there seems to be no newline here.\n");
00494 return -1;
00495 }
00496 if (nll < 0) {
00497
00498 printf("vb_skipline(): there seems to be no newline here...except there should be. :P\n");
00499 return -1;
00500 }
00501
00502 memmove(vs->b, vs->b + nloff + nll, vs->dlen - nloff - nll);
00503
00504 vs->dlen -= nloff + nll;
00505
00506 return 0;
00507 }
00508
00509
00510 int vscatprintf(vstr * vs, char *fmt, ...)
00511 {
00512 int size;
00513 va_list ap;
00514
00515
00516
00517 if (!vs->b || vs->dlen == 0) {
00518 vsset(vs, "");
00519 }
00520
00521 while (1) {
00522
00523 va_start(ap, fmt);
00524 size = vsnprintf(vs->b + vs->dlen - 1, vs->blen - vs->dlen, fmt, ap);
00525 va_end(ap);
00526
00527
00528 if ((size > -1) && ((size_t)size < vs->blen - vs->dlen)) {
00529 vs->dlen += size;
00530 return size;
00531 }
00532
00533 if (size >= 0)
00534 vbgrow((vbuf *) vs, size + 1);
00535 else
00536 vbgrow((vbuf *) vs, vs->blen);
00537 }
00538 }
00539
00540
00541
00542 int vslast(vstr * vs)
00543 {
00544 if (vs->dlen < 1)
00545 return -1;
00546 if (vs->b[vs->dlen - 1] != '\0')
00547 return -1;
00548 if (vs->dlen == 1)
00549 return '\0';
00550 return vs->b[vs->dlen - 2];
00551 }
00552
00553
00554
00555 void vs_printf(vstr * vs, char *fmt, ...)
00556 {
00557 int size;
00558 va_list ap;
00559
00560
00561 vbresize((vbuf *) vs, 100);
00562
00563 while (1) {
00564
00565 va_start(ap, fmt);
00566 size = vsnprintf(vs->b, vs->blen, fmt, ap);
00567 va_end(ap);
00568
00569
00570 if ((size > -1) && ((size_t)size < vs->blen)) {
00571 vs->dlen = size + 1;
00572 return;
00573 }
00574
00575 if (size >= 0)
00576 vbresize((vbuf *) vs, size + 1);
00577 else
00578 vbresize((vbuf *) vs, vs->blen * 2);
00579 }
00580 }
00581
00582
00583
00584 void vs_printfa(vstr * vs, char *fmt, ...)
00585 {
00586 int size;
00587 va_list ap;
00588
00589 if (vs->blen - vs->dlen < 50)
00590 vbgrow((vbuf *) vs, 100);
00591
00592 while (1) {
00593
00594 va_start(ap, fmt);
00595 size = vsnprintf(vs->b + vs->dlen - 1, vs->blen - vs->dlen + 1, fmt, ap);
00596 va_end(ap);
00597
00598
00599 if ((size > -1) && ((size_t)size < vs->blen)) {
00600 vs->dlen += size;
00601 return;
00602 }
00603
00604 if (size >= 0)
00605 vbgrow((vbuf *) vs, size + 1 - vs->dlen);
00606 else
00607 vbgrow((vbuf *) vs, size);
00608 }
00609 }
00610
00611
00612 void vshexdump(vstr * vs, char *b, size_t start, size_t stop, int ascii)
00613 {
00614 char c;
00615 int diff, i;
00616
00617 while (start < stop) {
00618 diff = stop - start;
00619 if (diff > 16)
00620 diff = 16;
00621
00622 vs_printfa(vs, ":%08X ", start);
00623
00624 for (i = 0; i < diff; i++) {
00625 if (8 == i)
00626 vs_printfa(vs, " ");
00627 vs_printfa(vs, "%02X ", (unsigned char) *(b + start + i));
00628 }
00629 if (ascii) {
00630 for (i = diff; i < 16; i++)
00631 vs_printfa(vs, " ");
00632 for (i = 0; i < diff; i++) {
00633 c = *(b + start + i);
00634 vs_printfa(vs, "%c", isprint(c) ? c : '.');
00635 }
00636 }
00637 vs_printfa(vs, "\n");
00638 start += 16;
00639 }
00640 }
00641
00642
00643 void vsset(vstr * vs, char *s)
00644 {
00645 vsnset(vs, s, strlen(s));
00646 }
00647
00648
00649 void vsnset(vstr * vs, char *s, size_t n)
00650 {
00651 vbresize((vbuf *) vs, n + 1);
00652 memcpy(vs->b, s, n);
00653 vs->b[n] = '\0';
00654 vs->dlen = n + 1;
00655 }
00656
00657
00658 void vsgrow(vstr * vs, size_t len)
00659 {
00660 vbgrow((vbuf *) vs, len);
00661 }
00662
00663
00664 size_t vsavail(vstr * vs)
00665 {
00666 return vbavail((vbuf *) vs);
00667 }
00668
00669
00670 void vsnset16(vstr * vs, char *s, size_t len)
00671 {
00672 vbresize((vbuf *) vs, len + 1);
00673 memcpy(vs->b, s, len);
00674
00675 vs->b[len] = '\0';
00676 vs->dlen = len + 1;
00677 vs->b[len] = '\0';
00678 }
00679
00680
00681 void vscat(vstr * vs, char *str)
00682 {
00683 vsncat(vs, str, strlen(str));
00684 }
00685
00686
00687 int vscmp(vstr * vs, char *str)
00688 {
00689 return strcmp(vs->b, str);
00690 }
00691
00692
00693 void vsncat(vstr * vs, char *str, size_t len)
00694 {
00695 ASSERT(vs->b[vs->dlen - 1] == '\0', "vsncat(): attempt to append string to non-string.");
00696 size_t sl = strlen(str);
00697 size_t n = (sl < len) ? sl : len;
00698
00699 vbgrow((vbuf *) vs, n + 1);
00700 memcpy(vs->b + vs->dlen - 1, str, n);
00701 vs->dlen += n;
00702 vs->b[vs->dlen - 1] = '\0';
00703 }
00704
00705
00706 void vstrunc(vstr * v, size_t off)
00707 {
00708 if (off >= v->dlen - 1)
00709 return;
00710 v->b[off] = '\0';
00711 v->dlen = off + 1;
00712 }
00713
00714