src/lib/cache.c
changeset 9 a31048ff76a2
parent 8 400ddf1e7aa9
child 10 6806a90d934f
equal deleted inserted replaced
8:400ddf1e7aa9 9:a31048ff76a2
    10 #include <sys/mman.h>
    10 #include <sys/mman.h>
    11 #include <errno.h>
    11 #include <errno.h>
    12 #include <assert.h>
    12 #include <assert.h>
    13 
    13 
    14 
    14 
    15 
    15 int pt_cache_new (struct pt_cache **cache_ptr, const char *path, int mode)
    16 static int pt_cache_new (struct pt_cache **cache_ptr, const char *path, int mode)
       
    17 {
    16 {
    18     struct pt_cache *cache;
    17     struct pt_cache *cache;
    19 
    18 
    20     // alloc
    19     // alloc
    21     if ((cache = calloc(1, sizeof(*cache))) == NULL)
    20     if ((cache = calloc(1, sizeof(*cache))) == NULL)
    37     // cleanup
    36     // cleanup
    38     if (cache)
    37     if (cache)
    39         pt_cache_destroy(cache);
    38         pt_cache_destroy(cache);
    40 
    39 
    41     return -1;
    40     return -1;
    42 }
       
    43 
       
    44 int pt_cache_open (struct pt_cache **cache_ptr, const char *path, int mode)
       
    45 {
       
    46     struct pt_cache *cache;
       
    47     
       
    48     // alloc
       
    49     if (pt_cache_new(&cache, path, mode))
       
    50         return -1;
       
    51     
       
    52     // ok
       
    53     *cache_ptr = cache;
       
    54 
       
    55     return 0;
       
    56 }
    41 }
    57 
    42 
    58 int pt_cache_status (struct pt_cache *cache, const char *img_path)
    43 int pt_cache_status (struct pt_cache *cache, const char *img_path)
    59 {
    44 {
    60     struct stat st_img, st_cache;
    45     struct stat st_img, st_cache;
   149 
   134 
   150 
   135 
   151 /**
   136 /**
   152  * Mmap the opened cache file using PT_CACHE_HEADER_SIZE plus the calculated size stored in cache->size
   137  * Mmap the opened cache file using PT_CACHE_HEADER_SIZE plus the calculated size stored in cache->size
   153  */
   138  */
   154 static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr)
   139 static int pt_cache_open_mmap (struct pt_cache *cache, void **addr_ptr, bool readonly)
   155 {
   140 {
   156     int prot = 0;
   141     int prot = 0;
   157     void *addr;
   142     void *addr;
   158 
   143 
   159     // determine prot
   144     // determine prot
   160     prot |= PROT_READ;
   145     prot |= PROT_READ;
   161 
   146 
   162     if (cache->mode & PT_IMG_WRITE)
   147     if (!readonly) {
       
   148         assert(cache->mode & PT_IMG_WRITE);
       
   149 
   163         prot |= PROT_WRITE;
   150         prot |= PROT_WRITE;
       
   151     }
   164 
   152 
   165     // perform mmap() from second page on
   153     // perform mmap() from second page on
   166     if ((addr = mmap(NULL, PT_CACHE_HEADER_SIZE + cache->size, prot, MAP_SHARED, cache->fd, 0)) == MAP_FAILED)
   154     if ((addr = mmap(NULL, PT_CACHE_HEADER_SIZE + cache->size, prot, MAP_SHARED, cache->fd, 0)) == MAP_FAILED)
   167         return -1;
   155         return -1;
   168 
   156 
   169     // ok
   157     // ok
   170     *addr_ptr = addr;
   158     *addr_ptr = addr;
   171 
   159 
       
   160     return 0;
       
   161 }
       
   162 
       
   163 /**
       
   164  * Read in the cache header from the open file
       
   165  */
       
   166 static int pt_cache_read_header (struct pt_cache *cache, struct pt_cache_header *header)
       
   167 {
       
   168     size_t len = sizeof(*header);
       
   169     char *buf = (char *) header;
       
   170 
       
   171     // seek to start
       
   172     if (lseek(cache->fd, 0, SEEK_SET) != 0)
       
   173         return -1;
       
   174 
       
   175     // write out full header
       
   176     while (len) {
       
   177         ssize_t ret;
       
   178         
       
   179         // try and write out the header
       
   180         if ((ret = read(cache->fd, buf, len)) < 0)
       
   181             return -1;
       
   182 
       
   183         // update offset
       
   184         buf += ret;
       
   185         len -= ret;
       
   186     }
       
   187 
       
   188     // done
   172     return 0;
   189     return 0;
   173 }
   190 }
   174 
   191 
   175 /**
   192 /**
   176  * Write out the cache header into the opened file
   193  * Write out the cache header into the opened file
   224     // grow file
   241     // grow file
   225     if (ftruncate(cache->fd, PT_CACHE_HEADER_SIZE + cache->size) < 0)
   242     if (ftruncate(cache->fd, PT_CACHE_HEADER_SIZE + cache->size) < 0)
   226         goto error;
   243         goto error;
   227 
   244 
   228     // mmap header and data
   245     // mmap header and data
   229     if (pt_cache_open_mmap(cache, &base))
   246     if (pt_cache_open_mmap(cache, &base, false))
   230         goto error;
   247         goto error;
   231 
   248 
   232     cache->header = base;
   249     cache->header = base;
   233     cache->data = base + PT_CACHE_HEADER_SIZE;
   250     cache->data = base + PT_CACHE_HEADER_SIZE;
   234 
   251 
   264 
   281 
   265     // ok
   282     // ok
   266     return 0;
   283     return 0;
   267 }
   284 }
   268 
   285 
       
   286 int pt_cache_open (struct pt_cache *cache)
       
   287 {
       
   288     struct pt_cache_header header;
       
   289     void *base;
       
   290 
       
   291     // open the .cache
       
   292     if (pt_cache_open_read_fd(cache, &cache->fd))
       
   293         return -1;
       
   294 
       
   295     // read in header
       
   296     if (pt_cache_read_header(cache, &header))
       
   297         return -1;
       
   298 
       
   299     // calculate data size
       
   300     cache->size = sizeof(header) + header.height * header.row_bytes;
       
   301 
       
   302     // mmap header and data
       
   303     if (pt_cache_open_mmap(cache, &base, true))
       
   304         goto error;
       
   305 
       
   306     cache->header = base;
       
   307     cache->data = base + PT_CACHE_HEADER_SIZE;
       
   308 
       
   309     // done
       
   310     return 0;
       
   311 
       
   312 error:
       
   313     // cleanup
       
   314     pt_cache_abort(cache);
       
   315 
       
   316     return -1;
       
   317 }
       
   318 
   269 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info)
   319 int pt_cache_update_png (struct pt_cache *cache, png_structp png, png_infop info)
   270 {
   320 {
   271     struct pt_cache_header header;
   321     struct pt_cache_header header;
   272     
   322     
   273     // XXX: check cache_mode
   323     // XXX: check cache_mode
   274     // XXX: check image doesn't use any options we don't handle
   324     // XXX: check image doesn't use any options we don't handle
       
   325     // XXX: close any already-opened cache file
   275 
   326 
   276     memset(&header, 0, sizeof(header));
   327     memset(&header, 0, sizeof(header));
   277 
   328 
   278     // fill in basic info
   329     // fill in basic info
   279     header.width = png_get_image_width(png, info);
   330     header.width = png_get_image_width(png, info);
   283 
   334 
   284     log_debug("width=%u, height=%u, bit_depth=%u, color_type=%u", 
   335     log_debug("width=%u, height=%u, bit_depth=%u, color_type=%u", 
   285             header.width, header.height, header.bit_depth, header.color_type
   336             header.width, header.height, header.bit_depth, header.color_type
   286     );
   337     );
   287 
   338 
       
   339     // only pack 1 pixel per byte
       
   340     if (header.bit_depth < 8)
       
   341         png_set_packing(png);
       
   342 
   288     // fill in other info
   343     // fill in other info
   289     header.row_bytes = png_get_rowbytes(png, info);
   344     header.row_bytes = png_get_rowbytes(png, info);
   290 
   345 
   291     log_debug("row_bytes=%u", header.row_bytes);
   346     // calculate bpp as num_channels * bpc
       
   347     // XXX: this assumes the packed bit depth will be either 8 or 16
       
   348     header.col_bytes = png_get_channels(png, info) * (header.bit_depth == 16 ? 2 : 1);
       
   349 
       
   350     log_debug("row_bytes=%u, col_bytes=%u", header.row_bytes, header.col_bytes);
   292     
   351     
   293     // palette etc.
   352     // palette etc.
   294     if (header.color_type == PNG_COLOR_TYPE_PALETTE) {
   353     if (header.color_type == PNG_COLOR_TYPE_PALETTE) {
   295         int num_palette;
   354         int num_palette;
   296         png_colorp palette;
   355         png_colorp palette;
   307         memcpy(&header.palette, palette, num_palette * sizeof(*palette));
   366         memcpy(&header.palette, palette, num_palette * sizeof(*palette));
   308         
   367         
   309         log_debug("num_palette=%u", num_palette);
   368         log_debug("num_palette=%u", num_palette);
   310     }
   369     }
   311 
   370 
   312 
       
   313     // create .tmp and write out header
   371     // create .tmp and write out header
   314     if (pt_cache_open_create(cache, &header))
   372     if (pt_cache_open_create(cache, &header))
   315         return -1;
   373         return -1;
   316 
   374 
   317 
   375 
   328 
   386 
   329     // done!
   387     // done!
   330     return 0;
   388     return 0;
   331 }
   389 }
   332 
   390 
       
   391 int pt_cache_tile_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti)
       
   392 {
       
   393     if (!cache->data) {
       
   394         // not yet open
       
   395         if (pt_cache_open(cache))
       
   396             return -1;
       
   397     }
       
   398 
       
   399     // set basic info
       
   400     png_set_IHDR(png, info, ti->width, ti->height, cache->header->bit_depth, cache->header->color_type,
       
   401             PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT
       
   402     );
       
   403 
       
   404     // set palette?
       
   405     if (cache->header->color_type == PNG_COLOR_TYPE_PALETTE)
       
   406         png_set_PLTE(png, info, cache->header->palette, cache->header->num_palette);
       
   407 
       
   408     // write meta-info
       
   409     png_write_info(png, info);
       
   410 
       
   411     // pixel data is packed into 1 pixel per byte
       
   412     png_set_packing(png);
       
   413     
       
   414     // write image data
       
   415     for (size_t row = ti->y; row < ti->y + ti->height; row++) {
       
   416         size_t col = ti->x;
       
   417         
       
   418         // XXX: fill out-of-range regions in some background color
       
   419         png_write_row(png, cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes));
       
   420     }
       
   421 
       
   422     // done, flush remaining output
       
   423     png_write_flush(png);
       
   424 
       
   425     // ok
       
   426     return 0;
       
   427 }
       
   428 
   333 void pt_cache_destroy (struct pt_cache *cache)
   429 void pt_cache_destroy (struct pt_cache *cache)
   334 {
   430 {
   335     free(cache->path);
   431     free(cache->path);
   336 
   432 
   337     pt_cache_abort(cache);
   433     pt_cache_abort(cache);