--- 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 <assert.h>
-
-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);