X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fbuck2obj.c;h=7d651dfe6b65f6941f375a4c32ef53f88033c06d;hb=a010e5f6e075097c0d6362d40fb49e812e99e185;hp=92f1478b10ac4e926b4a5f16829ba6729a731b18;hpb=1aa9512b50adeef4a04577ecf52d8ecf6b29c2d0;p=libucw.git diff --git a/lib/buck2obj.c b/lib/buck2obj.c index 92f1478b..7d651dfe 100644 --- a/lib/buck2obj.c +++ b/lib/buck2obj.c @@ -1,55 +1,38 @@ /* - * Bucket -> Object converter + * Generating Objects from Buckets * * (c) 2004, Robert Spalek + * (c) 2004, Martin Mares */ #include "lib/lib.h" #include "lib/unaligned.h" #include "lib/pools.h" #include "lib/fastbuf.h" -#include "charset/unicode.h" +#include "lib/unicode.h" #include "lib/object.h" #include "lib/bucket.h" #include "lib/lizard.h" -#include "lib/buck2obj.h" +#include "lib/bbuf.h" #include #include #include -#define MAX_HEADER_SIZE 1024 // extra space for the header not counted in MaxObjSize -#define RET_ERR(num) ({ errno = num; return NULL; }) +#define RET_ERR(num) ({ errno = num; return -1; }) struct buck2obj_buf { - uns max_len, raw_len; - byte *raw; + bb_t bb; struct lizard_buffer *lizard; - struct mempool *mp; }; -static void -buck2obj_alloc_internal(struct buck2obj_buf *buf, uns max_len) -{ - buf->max_len = max_len; - if (!max_len) - { - buf->raw_len = 0; - buf->raw = NULL; - return; - } - buf->raw_len = max_len * LIZARD_MAX_MULTIPLY + LIZARD_MAX_ADD + MAX_HEADER_SIZE; - buf->raw = xmalloc(buf->raw_len); -} - struct buck2obj_buf * -buck2obj_alloc(struct mempool *mp) +buck2obj_alloc(void) { struct buck2obj_buf *buf = xmalloc(sizeof(struct buck2obj_buf)); - buck2obj_alloc_internal(buf, 0); - buf->lizard = lizard_alloc(0); - buf->mp = mp; + bb_init(&buf->bb); + buf->lizard = lizard_alloc(); return buf; } @@ -57,23 +40,10 @@ void buck2obj_free(struct buck2obj_buf *buf) { lizard_free(buf->lizard); - if (buf->raw) - xfree(buf->raw); + bb_done(&buf->bb); xfree(buf); } -static void -buck2obj_realloc(struct buck2obj_buf *buf, uns max_len) -{ - if (max_len <= buf->max_len) - return; - if (max_len < 2*buf->max_len) // to ensure amortized logarithmic complexity - max_len = 2*buf->max_len; - if (buf->raw) - xfree(buf->raw); - buck2obj_alloc_internal(buf, max_len); -} - static inline byte * decode_attributes(byte *ptr, byte *end, struct odes *o, uns can_overwrite) { @@ -89,21 +59,6 @@ decode_attributes(byte *ptr, byte *end, struct odes *o, uns can_overwrite) ptr[len] = 0; obj_add_attr_ref(o, type, ptr); - ptr += len + 1; - } - else if (can_overwrite == 1) - while (ptr < end) - { - uns len; - GET_UTF8(ptr, len); - if (!len--) - break; - byte type = ptr[len]; - - ptr[len] = 0; - obj_add_attr(o, type, ptr); - ptr[len] = type; - ptr += len + 1; } else @@ -125,117 +80,110 @@ decode_attributes(byte *ptr, byte *end, struct odes *o, uns can_overwrite) return ptr; } -struct odes * -obj_read_bucket(struct buck2obj_buf *buf, uns buck_type, uns buck_len, struct fastbuf *body, uns want_body) +int +buck2obj_parse(struct buck2obj_buf *buf, uns buck_type, uns buck_len, struct fastbuf *body, struct odes *o_hdr, uns *body_start, struct odes *o_body) { - struct odes *o = obj_new(buf->mp); - - if (buck_type < BUCKET_TYPE_V33) + if (buck_type == BUCKET_TYPE_PLAIN) { - if (want_body) // ignore empty lines, read until NUL or EOF - { - obj_read_multi(body, o); - bgetc(body); - } - else // end on EOF or the first empty line - obj_read(body, o); + if (body_start) + *body_start = 0; + obj_read_multi(body, o_hdr); // ignore empty lines, read until EOF or NUL } - else + else if (buck_type == BUCKET_TYPE_V30) + { + sh_off_t start = btell(body); + obj_read(body, o_hdr); // end on EOF or the first empty line + if (body_start) + *body_start = btell(body) - start; + else + { + obj_read(body, o_body); + bgetc(body); + } + } + else if (buck_type == BUCKET_TYPE_V33 || buck_type == BUCKET_TYPE_V33_LIZARD) { /* Read all the bucket into 1 buffer, 0-copy if possible. */ - /* FIXME: This could be cached in buck2obj_buf */ - int can_overwrite = bconfig(body, BCONFIG_CAN_OVERWRITE, 0); - if (can_overwrite < 0) - can_overwrite = 0; - uns overwritten; byte *ptr, *end; uns len = bdirect_read_prepare(body, &ptr); + uns copied = 0; if (len < buck_len - || (can_overwrite < 2 && buck_type == BUCKET_TYPE_V33)) + || (body->can_overwrite_buffer < 2 && buck_type == BUCKET_TYPE_V33)) { /* Copy if the original buffer is too small. * If it is write-protected, copy it also if it is uncompressed. */ - if (buck_len > buf->raw_len) - buck2obj_realloc(buf, buck_len); - len = bread(body, buf->raw, buck_len); - ptr = buf->raw; - can_overwrite = 2; - overwritten = 0; + bb_grow(&buf->bb, buck_len); + len = bread(body, buf->bb.ptr, buck_len); + ptr = buf->bb.ptr; + copied = 1; } - else - overwritten = can_overwrite > 1; end = ptr + len; - ptr = decode_attributes(ptr, end, o, can_overwrite);// header - if (!want_body) - return o; - if (buck_type == BUCKET_TYPE_V33) - ; - else if (buck_type == BUCKET_TYPE_V33_LIZARD) // decompression + byte *start = ptr; + ptr = decode_attributes(ptr, end, o_hdr, 0); // header + if (body_start) + { + *body_start = ptr - start; + if (!copied) + bdirect_read_commit(body, ptr); + return 0; + } + if (buck_type == BUCKET_TYPE_V33_LIZARD) // decompression { + if (ptr + 4 > end) + RET_ERR(EINVAL); len = GET_U32(ptr); ptr += 4; - int res; -decompress: - res = lizard_decompress_safe(ptr, buf->lizard, len); - if (res != (int) len) - { - if (res >= 0) - errno = EINVAL; - else if (errno == EFBIG) - { - lizard_realloc(buf->lizard, len); - goto decompress; - } - else - return NULL; - } - ptr = buf->lizard->ptr; + byte *new_ptr = lizard_decompress_safe(ptr, buf->lizard, len); + if (!new_ptr) + return -1; + if (!copied) + bdirect_read_commit(body, end); + ptr = new_ptr; end = ptr + len; - can_overwrite = 2; + copied = 1; } - else // unknown bucket type - RET_ERR(EINVAL); - ASSERT(can_overwrite == 2); // because of the policy and decompression - ptr = decode_attributes(ptr, end, o, 2); // body - + ptr = decode_attributes(ptr, end, o_body, 2); // body if (ptr != end) RET_ERR(EINVAL); - /* If (overwritten), bflush(body) might be needed. */ + if (!copied) + bdirect_read_commit_modified(body, ptr); } - return o; + else + RET_ERR(EINVAL); + return 0; +} + +struct odes * +obj_read_bucket(struct buck2obj_buf *buf, struct mempool *pool, uns buck_type, uns buck_len, struct fastbuf *body, uns *body_start) +{ + struct odes *o = obj_new(pool); + if (buck2obj_parse(buf, buck_type, buck_len, body, o, body_start, o) < 0) + return NULL; + else + return o; } -byte * -obj_attr_to_bucket(byte *buf, uns buck_type, uns attr, byte *val) +int +obj_read(struct fastbuf *f, struct odes *o) { - uns l; + byte buf[MAX_ATTR_SIZE]; - switch (buck_type) + while (bgets(f, buf, sizeof(buf))) { - case BUCKET_TYPE_PLAIN: - case BUCKET_TYPE_V30: - buf += sprintf(buf, "%c%s\n", attr, val); - break; - case BUCKET_TYPE_V33: - case BUCKET_TYPE_V33_LIZARD: - l = strlen(val) + 1; - PUT_UTF8(buf, l); - l--; - memcpy(buf, val, l); - buf += l; - *buf++ = attr; - break; - default: - die("obj_attr_to_bucket called for unknown type %08x", buck_type); + if (!buf[0]) + return 1; + obj_add_attr(o, buf[0], buf+1); } - return buf; + return 0; } -byte * -obj_attr_to_bucket_num(byte *buf, uns buck_type, uns attr, uns val) +void +obj_read_multi(struct fastbuf *f, struct odes *o) { - byte vbuf[16]; - sprintf(vbuf, "%d", val); - return obj_attr_to_bucket(buf, buck_type, attr, vbuf); + /* Read a multi-part object ending with either EOF or a NUL character */ + byte buf[MAX_ATTR_SIZE]; + while (bpeekc(f) > 0 && bgets(f, buf, sizeof(buf))) + if (buf[0]) + obj_add_attr(o, buf[0], buf+1); }