diff -r 400ddf1e7aa9 -r a31048ff76a2 src/lib/cache.c --- a/src/lib/cache.c Mon Dec 28 23:15:18 2009 +0200 +++ b/src/lib/cache.c Tue Dec 29 00:18:17 2009 +0200 @@ -12,8 +12,7 @@ #include - -static int pt_cache_new (struct pt_cache **cache_ptr, const char *path, int mode) +int pt_cache_new (struct pt_cache **cache_ptr, const char *path, int mode) { struct pt_cache *cache; @@ -41,20 +40,6 @@ return -1; } -int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode) -{ - struct pt_cache *cache; - - // alloc - if (pt_cache_new(&cache, path, mode)) - return -1; - - // ok - *cache_ptr = cache; - - return 0; -} - int pt_cache_status (struct pt_cache *cache, const char *img_path) { struct stat st_img, st_cache; @@ -151,7 +136,7 @@ /** * Mmap the opened cache file using PT_CACHE_HEADER_SIZE plus the calculated size stored in cache->size */ -static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr) +static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr, bool readonly) { int prot = 0; void *addr; @@ -159,8 +144,11 @@ // determine prot prot |= PROT_READ; - if (cache->mode & PT_IMG_WRITE) + if (!readonly) { + assert(cache->mode & PT_IMG_WRITE); + prot |= PROT_WRITE; + } // perform mmap() from second page on if ((addr = mmap(NULL, PT_CACHE_HEADER_SIZE + cache->size, prot, MAP_SHARED, cache->fd, 0)) == MAP_FAILED) @@ -173,6 +161,35 @@ } /** + * Read in the cache header from the open file + */ +static int pt_cache_read_header (struct pt_cache *cache, struct pt_cache_header *header) +{ + size_t len = sizeof(*header); + char *buf = (char *) header; + + // seek to start + if (lseek(cache->fd, 0, SEEK_SET) != 0) + return -1; + + // write out full header + while (len) { + ssize_t ret; + + // try and write out the header + if ((ret = read(cache->fd, buf, len)) < 0) + return -1; + + // update offset + buf += ret; + len -= ret; + } + + // done + return 0; +} + +/** * Write out the cache header into the opened file */ static int pt_cache_write_header (struct pt_cache *cache, const struct pt_cache_header *header) @@ -226,7 +243,7 @@ goto error; // mmap header and data - if (pt_cache_open_mmap(cache, &base)) + if (pt_cache_open_mmap(cache, &base, false)) goto error; cache->header = base; @@ -266,12 +283,46 @@ return 0; } +int pt_cache_open (struct pt_cache *cache) +{ + struct pt_cache_header header; + void *base; + + // open the .cache + if (pt_cache_open_read_fd(cache, &cache->fd)) + return -1; + + // read in header + if (pt_cache_read_header(cache, &header)) + return -1; + + // calculate data size + cache->size = sizeof(header) + header.height * header.row_bytes; + + // mmap header and data + if (pt_cache_open_mmap(cache, &base, true)) + goto error; + + cache->header = base; + cache->data = base + PT_CACHE_HEADER_SIZE; + + // done + return 0; + +error: + // cleanup + pt_cache_abort(cache); + + return -1; +} + int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info) { struct pt_cache_header header; // XXX: check cache_mode // XXX: check image doesn't use any options we don't handle + // XXX: close any already-opened cache file memset(&header, 0, sizeof(header)); @@ -285,10 +336,18 @@ header.width, header.height, header.bit_depth, header.color_type ); + // only pack 1 pixel per byte + if (header.bit_depth < 8) + png_set_packing(png); + // fill in other info header.row_bytes = png_get_rowbytes(png, info); - log_debug("row_bytes=%u", header.row_bytes); + // calculate bpp as num_channels * bpc + // XXX: this assumes the packed bit depth will be either 8 or 16 + header.col_bytes = png_get_channels(png, info) * (header.bit_depth == 16 ? 2 : 1); + + log_debug("row_bytes=%u, col_bytes=%u", header.row_bytes, header.col_bytes); // palette etc. if (header.color_type == PNG_COLOR_TYPE_PALETTE) { @@ -309,7 +368,6 @@ log_debug("num_palette=%u", num_palette); } - // create .tmp and write out header if (pt_cache_open_create(cache, &header)) return -1; @@ -330,6 +388,44 @@ return 0; } +int pt_cache_tile_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti) +{ + if (!cache->data) { + // not yet open + if (pt_cache_open(cache)) + return -1; + } + + // set basic info + png_set_IHDR(png, info, ti->width, ti->height, cache->header->bit_depth, cache->header->color_type, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT + ); + + // set palette? + if (cache->header->color_type == PNG_COLOR_TYPE_PALETTE) + png_set_PLTE(png, info, cache->header->palette, cache->header->num_palette); + + // write meta-info + png_write_info(png, info); + + // pixel data is packed into 1 pixel per byte + png_set_packing(png); + + // write image data + for (size_t row = ti->y; row < ti->y + ti->height; row++) { + size_t col = ti->x; + + // XXX: fill out-of-range regions in some background color + png_write_row(png, cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes)); + } + + // done, flush remaining output + png_write_flush(png); + + // ok + return 0; +} + void pt_cache_destroy (struct pt_cache *cache) { free(cache->path);