/* * blob.c * * Copyright (c) 2002 Dug Song * * $Id: blob.c 615 2006-01-08 16:06:49Z dugsong $ */ #ifdef _WIN32 #include "dnet_winconfig.h" #else #include "config.h" #endif #include #include #include #include #include #include "dnet.h" static void *(*bl_malloc)(size_t) = malloc; static void *(*bl_realloc)(void *, size_t) = realloc; static void (*bl_free)(void *) = free; static int bl_size = BUFSIZ; static int fmt_D(int, int, blob_t *, va_list *); static int fmt_H(int, int, blob_t *, va_list *); static int fmt_b(int, int, blob_t *, va_list *); static int fmt_c(int, int, blob_t *, va_list *); static int fmt_d(int, int, blob_t *, va_list *); static int fmt_h(int, int, blob_t *, va_list *); static int fmt_s(int, int, blob_t *, va_list *); static void print_hexl(blob_t *); static blob_fmt_cb blob_ascii_fmt[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, fmt_D, NULL, NULL, NULL, fmt_H, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, fmt_b, fmt_c, fmt_d, NULL, NULL, NULL, fmt_h, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, fmt_s, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; struct blob_printer { char *name; void (*print)(blob_t *); } blob_printers[] = { { "hexl", print_hexl }, { NULL, NULL }, }; blob_t * blob_new(void) { blob_t *b; if ((b = bl_malloc(sizeof(*b))) != NULL) { b->off = b->end = 0; b->size = bl_size; if ((b->base = bl_malloc(b->size)) == NULL) { bl_free(b); b = NULL; } } return (b); } static int blob_reserve(blob_t *b, int len) { void *p; int nsize; if (b->size < b->end + len) { if (b->size == 0) return (-1); if ((nsize = b->end + len) > bl_size) nsize = ((nsize / bl_size) + 1) * bl_size; if ((p = bl_realloc(b->base, nsize)) == NULL) return (-1); b->base = p; b->size = nsize; } b->end += len; return (0); } int blob_read(blob_t *b, void *buf, int len) { if (b->end - b->off < len) len = b->end - b->off; memcpy(buf, b->base + b->off, len); b->off += len; return (len); } int blob_write(blob_t *b, const void *buf, int len) { if (b->off + len <= b->end || blob_reserve(b, b->off + len - b->end) == 0) { memcpy(b->base + b->off, (u_char *)buf, len); b->off += len; return (len); } return (-1); } int blob_insert(blob_t *b, const void *buf, int len) { if (blob_reserve(b, len) == 0 && b->size) { if (b->end - b->off > 0) memmove( b->base + b->off + len, b->base + b->off, b->end - b->off); memcpy(b->base + b->off, buf, len); b->off += len; return (len); } return (-1); } int blob_delete(blob_t *b, void *buf, int len) { if (b->off + len <= b->end && b->size) { if (buf != NULL) memcpy(buf, b->base + b->off, len); memmove(b->base + b->off, b->base + b->off + len, b->end - (b->off + len)); b->end -= len; return (len); } return (-1); } static int blob_fmt(blob_t *b, int pack, const char *fmt, va_list *ap) { blob_fmt_cb fmt_cb; char *p; int len; for (p = (char *)fmt; *p != '\0'; p++) { if (*p == '%') { p++; if (isdigit((int) (unsigned char) *p)) { len = strtol(p, &p, 10); } else if (*p == '*') { len = va_arg(*ap, int); p++; } else len = 0; if ((fmt_cb = blob_ascii_fmt[(int)*p]) == NULL) return (-1); if ((*fmt_cb)(pack, len, b, ap) < 0) return (-1); } else { if (pack) { if (b->off + 1 < b->end || blob_reserve(b, b->off + 1 - b->end) == 0) b->base[b->off++] = *p; else return (-1); } else { if (b->base[b->off++] != *p) return (-1); } } } return (0); } int blob_pack(blob_t *b, const char *fmt, ...) { va_list ap; va_start(ap, fmt); return (blob_fmt(b, 1, fmt, &ap)); } int blob_unpack(blob_t *b, const char *fmt, ...) { va_list ap; va_start(ap, fmt); return (blob_fmt(b, 0, fmt, &ap)); } int blob_seek(blob_t *b, int off, int whence) { if (whence == SEEK_CUR) off += b->off; else if (whence == SEEK_END) off += b->end; if (off < 0 || off > b->end) return (-1); return ((b->off = off)); } int blob_index(blob_t *b, const void *buf, int len) { int i; for (i = b->off; i <= b->end - len; i++) { if (memcmp(b->base + i, buf, len) == 0) return (i); } return (-1); } int blob_rindex(blob_t *b, const void *buf, int len) { int i; for (i = b->end - len; i >= 0; i--) { if (memcmp(b->base + i, buf, len) == 0) return (i); } return (-1); } int blob_print(blob_t *b, char *style, int len) { struct blob_printer *bp; for (bp = blob_printers; bp->name != NULL; bp++) { if (strcmp(bp->name, style) == 0) bp->print(b); } return (0); } int blob_sprint(blob_t *b, char *style, int len, char *dst, int size) { return (0); } blob_t * blob_free(blob_t *b) { if (b->size) bl_free(b->base); bl_free(b); return (NULL); } int blob_register_alloc(size_t size, void *(bmalloc)(size_t), void (*bfree)(void *), void *(*brealloc)(void *, size_t)) { bl_size = size; if (bmalloc != NULL) bl_malloc = bmalloc; if (bfree != NULL) bl_free = bfree; if (brealloc != NULL) bl_realloc = brealloc; return (0); } int blob_register_pack(char c, blob_fmt_cb fmt_cb) { if (blob_ascii_fmt[(int)c] == NULL) { blob_ascii_fmt[(int)c] = fmt_cb; return (0); } return (-1); } static int fmt_D(int pack, int len, blob_t *b, va_list *ap) { if (len) return (-1); if (pack) { uint32_t n = va_arg(*ap, uint32_t); n = htonl(n); if (blob_write(b, &n, sizeof(n)) < 0) return (-1); } else { uint32_t *n = va_arg(*ap, uint32_t *); if (blob_read(b, n, sizeof(*n)) != sizeof(*n)) return (-1); *n = ntohl(*n); } return (0); } static int fmt_H(int pack, int len, blob_t *b, va_list *ap) { if (len) return (-1); if (pack) { uint16_t n = va_arg(*ap, int); n = htons(n); if (blob_write(b, &n, sizeof(n)) < 0) return (-1); } else { uint16_t *n = va_arg(*ap, uint16_t *); if (blob_read(b, n, sizeof(*n)) != sizeof(*n)) return (-1); *n = ntohs(*n); } return (0); } static int fmt_b(int pack, int len, blob_t *b, va_list *ap) { void *p = va_arg(*ap, void *); if (len <= 0) return (-1); if (pack) return (blob_write(b, p, len)); else return (blob_read(b, p, len)); } static int fmt_c(int pack, int len, blob_t *b, va_list *ap) { if (len) return (-1); if (pack) { uint8_t n = va_arg(*ap, int); return (blob_write(b, &n, sizeof(n))); } else { uint8_t *n = va_arg(*ap, uint8_t *); return (blob_read(b, n, sizeof(*n))); } } static int fmt_d(int pack, int len, blob_t *b, va_list *ap) { if (len) return (-1); if (pack) { uint32_t n = va_arg(*ap, uint32_t); return (blob_write(b, &n, sizeof(n))); } else { uint32_t *n = va_arg(*ap, uint32_t *); return (blob_read(b, n, sizeof(*n))); } } static int fmt_h(int pack, int len, blob_t *b, va_list *ap) { if (len) return (-1); if (pack) { uint16_t n = va_arg(*ap, int); return (blob_write(b, &n, sizeof(n))); } else { uint16_t *n = va_arg(*ap, uint16_t *); return (blob_read(b, n, sizeof(*n))); } } static int fmt_s(int pack, int len, blob_t *b, va_list *ap) { char *p = va_arg(*ap, char *); char c = '\0'; int i, end; if (pack) { if (len > 0) { if ((c = p[len - 1]) != '\0') p[len - 1] = '\0'; } else len = strlen(p) + 1; if (blob_write(b, p, len) > 0) { if (c != '\0') p[len - 1] = c; return (len); } } else { if (len <= 0) return (-1); if ((end = b->end - b->off) < len) end = len; for (i = 0; i < end; i++) { if ((p[i] = b->base[b->off + i]) == '\0') { b->off += i + 1; return (i); } } } return (-1); } static void print_hexl(blob_t *b) { u_int i, j, jm, len; u_char *p; int c; p = b->base + b->off; len = b->end - b->off; printf("\n"); for (i = 0; i < len; i += 0x10) { printf(" %04x: ", (u_int)(i + b->off)); jm = len - i; jm = jm > 16 ? 16 : jm; for (j = 0; j < jm; j++) { printf((j % 2) ? "%02x " : "%02x", (u_int)p[i + j]); } for (; j < 16; j++) { printf((j % 2) ? " " : " "); } printf(" "); for (j = 0; j < jm; j++) { c = p[i + j]; printf("%c", isprint(c) ? c : '.'); } printf("\n"); } }