terom@0: #include "image.h" terom@1: #include "cache.h" terom@0: terom@1: #include terom@1: #include // for _POSIX_PATH_MAX terom@1: terom@1: #include terom@1: terom@1: static int pt_image_new (struct pt_image **img_ptr, struct pt_ctx *ctx, const char *path) terom@0: { terom@0: struct pt_image *img; terom@0: terom@0: // alloc terom@0: if ((img = calloc(1, sizeof(*img))) == NULL) terom@0: return -1; terom@0: terom@1: if ((img->path = strdup(path)) == NULL) terom@0: goto error; terom@0: terom@0: // init terom@0: img->ctx = ctx; terom@0: terom@0: // ok terom@0: *img_ptr = img; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@0: pt_image_destroy(img); terom@0: terom@0: return -1; terom@0: } terom@0: terom@0: /** terom@0: * Open the image's FILE terom@0: */ terom@0: static int pt_image_open_file (struct pt_image *img, FILE **file_ptr) terom@0: { terom@0: FILE *fp; terom@0: terom@0: // open terom@2: if ((fp = fopen(img->path, "rb")) < 0) terom@0: return -1; terom@0: terom@0: // ok terom@0: *file_ptr = fp; terom@0: terom@0: return 0; terom@0: } terom@0: terom@0: /** terom@0: * Open the PNG image, setting up the I/O and returning the png_structp and png_infop terom@0: */ terom@0: static int pt_image_open_png (struct pt_image *img, png_structp *png_ptr, png_infop *info_ptr) terom@0: { terom@0: FILE *fp = NULL; terom@0: png_structp png = NULL; terom@0: png_infop info = NULL; terom@0: terom@0: // open I/O terom@0: if (pt_image_open_file(img, &fp)) terom@0: goto error; terom@0: terom@0: // create the struct terom@0: if ((png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) terom@0: goto error; terom@0: terom@0: // create the info terom@0: if ((info = png_create_info_struct(png)) == NULL) terom@0: goto error; terom@0: terom@0: // setup error trap for the I/O terom@0: if (setjmp(png_jmpbuf(png))) terom@0: goto error; terom@0: terom@0: // setup I/O to FILE terom@0: png_init_io(png, fp); terom@0: terom@0: // ok terom@1: // XXX: what to do with fp? terom@0: *png_ptr = png; terom@0: *info_ptr = info; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@0: // cleanup file terom@0: if (fp) fclose(fp); terom@0: terom@0: // cleanup PNG state terom@0: png_destroy_read_struct(&png, &info, NULL); terom@0: terom@0: return -1; terom@0: } terom@0: terom@0: /** terom@0: * Open the PNG image, and write out to the cache terom@0: */ terom@0: static int pt_image_update_cache (struct pt_image *img) terom@0: { terom@0: png_structp png; terom@0: png_infop info; terom@0: terom@0: // open .png terom@0: if (pt_image_open_png(img, &png, &info)) terom@0: return -1; terom@0: terom@0: // setup error trap terom@0: if (setjmp(png_jmpbuf(png))) terom@0: goto error; terom@0: terom@0: // read meta-info terom@0: png_read_info(png, info); terom@0: terom@0: // pass to cache object terom@0: if (pt_cache_update_png(img->cache, png, info)) terom@0: goto error; terom@0: terom@0: // finish off, ignore trailing data terom@0: png_read_end(png, NULL); terom@0: terom@0: // clean up terom@1: png_destroy_read_struct(&png, &info, NULL); terom@0: terom@0: return 0; terom@0: terom@0: error: terom@0: // clean up terom@1: png_destroy_read_struct(&png, &info, NULL); terom@0: terom@0: return -1; terom@0: } terom@0: terom@1: /** terom@1: * Build a filesystem path representing the appropriate path for this image's cache entry, and store it in the given terom@1: * buffer. terom@1: */ terom@1: static int pt_image_cache_path (struct pt_image *image, char *buf, size_t len) terom@0: { terom@2: char *ext; terom@2: terom@2: // XXX: be more careful about buf len terom@2: terom@2: // copy filename terom@2: strncpy(buf, image->path, len); terom@2: terom@2: // find .ext terom@2: if ((ext = strrchr(buf, '.')) == NULL) terom@2: return -1; terom@2: terom@2: // change to .cache terom@2: strncpy(ext, ".cache", (buf + len) - ext); terom@2: terom@2: // hmmk terom@2: return 0; terom@1: } terom@0: terom@1: int pt_image_open (struct pt_image **image_ptr, struct pt_ctx *ctx, const char *path, int cache_mode) terom@1: { terom@1: struct pt_image *image; terom@1: char cache_path[_POSIX_PATH_MAX]; terom@2: int stale; terom@1: terom@1: // XXX: verify that the path exists and looks like a PNG file terom@0: terom@0: // alloc terom@1: if (pt_image_new(&image, ctx, path)) terom@0: return -1; terom@1: terom@1: // compute cache file path terom@1: if (pt_image_cache_path(image, cache_path, sizeof(cache_path))) terom@1: goto error; terom@0: terom@0: // open the cache object for this image terom@1: if (pt_cache_open(&image->cache, cache_path, cache_mode)) terom@0: goto error; terom@0: terom@0: // update if not fresh terom@1: // XXX: check cache_mode terom@2: if ((stale = pt_cache_stale(image->cache, image->path)) < 0) terom@2: goto error; terom@2: terom@2: if (stale) terom@1: pt_image_update_cache(image); terom@0: terom@0: // ok, ready for access terom@1: *image_ptr = image; terom@0: terom@0: return 0; terom@0: terom@0: error: terom@1: pt_image_destroy(image); terom@1: terom@1: return -1; terom@0: } terom@1: terom@1: void pt_image_destroy (struct pt_image *image) terom@1: { terom@1: free(image->path); terom@1: terom@1: if (image->cache) terom@1: pt_cache_destroy(image->cache); terom@1: terom@1: free(image); terom@1: }