/* * Copyright (c) 2001-2002 Packet Design, LLC. * All rights reserved. * * Subject to the following obligations and disclaimer of warranty, * use and redistribution of this software, in source or object code * forms, with or without modifications are expressly permitted by * Packet Design; provided, however, that: * * (i) Any and all reproductions of the source or object code * must include the copyright notice above and the following * disclaimer of warranties; and * (ii) No rights are granted, in any manner or form, to use * Packet Design trademarks, including the mark "PACKET DESIGN" * on advertising, endorsements, or otherwise except as such * appears in the above copyright notice or in the software. * * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. * * Author: Archie Cobbs */ #include #include #include #include #include #include #include #include "structs/structs.h" #include "structs/type/array.h" #include "util/string_quote.h" #include "util/typed_mem.h" struct string_dequote_info { const char *mtype; char **bufp; }; /* * Internal variables */ static const char *escapes[2] = { "tnrvf\"\\", "\t\n\r\v\f\"\\" }; static const char hexdigit[16] = "0123456789abcdef"; /* * Internal functions */ static void string_dequote_cleanup(void *arg); /* * Parse a doubly-quoted string token. */ char * string_dequote(FILE *fp, const char *mtype) { struct string_dequote_info info; char *buf = NULL; int alloc = 0; int len = 0; void *mem; int ch; /* Cleanup properly if thread is canceled */ info.bufp = &buf; info.mtype = mtype; pthread_cleanup_push(string_dequote_cleanup, &info); /* Parse string */ while ((ch = getc(fp)) != EOF) { /* Increase buffer length if necessary */ if (len + 8 >= alloc) { alloc += 64; if ((mem = REALLOC(mtype, buf, alloc)) == NULL) goto fail; buf = mem; } /* Check special characters */ switch (ch) { case '"': buf[len] = '\0'; goto done; case '\\': switch ((ch = getc(fp))) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { char chsave[3]; int x, k; for (x = k = 0; k < 3; k++) { if (k > 0 && (ch = getc(fp)) == EOF) { k--; /* char not saved */ break; } chsave[k] = ch; if (ch < '0' || ch > '7') break; x = (x << 3) + (ch - '0'); } if (k == 3) /* got a whole byte */ buf[len++] = (char)x; else { /* copy chars as-is */ buf[len++] = '\\'; for (x = 0; x <= k; x++) buf[len++] = chsave[x]; } break; } case 'x': { char chsave[2]; int x, k; for (x = k = 0; k < 2; k++) { if ((ch = getc(fp)) == EOF) { k--; /* char not saved */ break; } chsave[k] = ch; if (!isxdigit(ch)) break; x = (x << 4) + (isdigit(ch) ? (ch - '0') : (tolower(ch) - 'a' + 10)); } if (k == 2) /* got a whole byte */ buf[len++] = (char)x; else { /* copy chars as-is */ buf[len++] = '\\'; buf[len++] = 'x'; for (x = 0; x <= k; x++) buf[len++] = chsave[x]; } break; } case EOF: goto got_eof; default: { char *x; if ((x = strchr(escapes[0], ch)) != NULL) buf[len++] = escapes[1][x - escapes[0]]; else buf[len++] = ch; } } break; default: buf[len++] = (char)ch; break; } } got_eof: /* EOF was read: check for error or actual end of file */ if (!ferror(fp)) errno = EINVAL; fail: /* Error */ FREE(mtype, buf); buf = NULL; done:; /* Done */ pthread_cleanup_pop(0); return (buf); } /* * Cleanup for string_dequote() */ static void string_dequote_cleanup(void *arg) { struct string_dequote_info *const info = arg; FREE(info->mtype, *info->bufp); } /* * Enquote a string. */ char * string_enquote(const char *s, const char *mtype) { char *buf = NULL; int pass2 = 0; int len; char *t; int i; pass2: /* Encode characters */ len = 0; if (pass2) buf[len] = '"'; len++; for (i = 0; s[i] != '\0'; i++) { if ((t = strchr(escapes[1], s[i])) != NULL) { if (pass2) { buf[len] = '\\'; buf[len + 1] = escapes[0][t - escapes[1]]; } len += 2; } else if (isprint(s[i])) { if (pass2) buf[len] = s[i]; len++; } else { if (pass2) { buf[len] = '\\'; buf[len + 1] = 'x'; buf[len + 2] = hexdigit[((s[i]) >> 4) & 0x0f]; buf[len + 3] = hexdigit[(s[i]) & 0x0f]; } len += 4; } } if (pass2) buf[len] = '"'; len++; /* Finish up */ if (pass2) { buf[len] = '\0'; return (buf); } /* Initialize buffer */ if ((buf = MALLOC(mtype, len + 1)) == NULL) return (NULL); pass2 = 1; goto pass2; } #ifdef STRING_QUOTE_TEST #include #include int main(int ac, char **av) { int decode = -1; FILE *fp; char *s; int ch; while ((ch = getopt(ac, av, "de")) != -1) { switch (ch) { case 'd': decode = 1; break; case 'e': decode = 0; break; default: usage: errx(1, "usage: string_quote -d dquotefile\n" "\tstring_quote -e [rawtext]"); } } ac -= optind; av += optind; if (decode == -1) goto usage; if (decode && ac != 1) goto usage; if (!decode && ac != 0 && ac != 1) goto usage; /* Encode or decode */ if (ac == 0) fp = stdin; else if ((fp = fopen(av[0], "r")) == NULL) err(1, "%s", av[0]); if (decode) { if ((ch = getc(fp)) != '"') errx(1, "input does not start with a double quote"); if ((s = string_dequote(fp, TYPED_MEM_TEMP)) == NULL) err(1, "error dequoting %s", av[0]); fputs(s, stdout); FREE(TYPED_MEM_TEMP, s); } else { char buf[1024]; int len; len = fread(buf, 1, sizeof(buf) - 1, fp); if (ferror(fp)) err(1, "reading rawtext input"); if (len == sizeof(buf) - 1) warnx("warning: only %u characters dealt with", len); buf[len] = '\0'; if ((s = string_enquote(buf, TYPED_MEM_TEMP)) == NULL) err(1, "error dequoting %s", av[0]); fputs(s, stdout); putchar('\n'); FREE(TYPED_MEM_TEMP, s); } return (0); } #endif /* STRING_QUOTE_TEST */