pt_png_check, and fclose() pt_image_open_file
authorTero Marttila <terom@fixme.fi>
Mon, 25 Jan 2010 02:40:19 +0200
changeset 69 1d188aa94aee
parent 68 70737d141172
child 70 35515b3a82b7
pt_png_check, and fclose() pt_image_open_file
include/pngtile.h
src/lib/error.c
src/lib/image.c
src/lib/png.c
src/lib/png.h
--- a/include/pngtile.h	Mon Jan 25 02:39:28 2010 +0200
+++ b/include/pngtile.h	Mon Jan 25 02:40:19 2010 +0200
@@ -215,7 +215,8 @@
     PT_ERR_OPEN_MODE,
     
     PT_ERR_IMG_STAT,
-    PT_ERR_IMG_FOPEN,
+    PT_ERR_IMG_OPEN,
+    PT_ERR_IMG_FORMAT,
     
     PT_ERR_PNG_CREATE,
     PT_ERR_PNG,
--- a/src/lib/error.c	Mon Jan 25 02:39:28 2010 +0200
+++ b/src/lib/error.c	Mon Jan 25 02:40:19 2010 +0200
@@ -12,7 +12,8 @@
     [PT_ERR_OPEN_MODE]          = "open_mode",
     
     [PT_ERR_IMG_STAT]           = "stat(.png)",
-    [PT_ERR_IMG_FOPEN]          = "fopen(.png)",
+    [PT_ERR_IMG_OPEN]           = "open(.png)",
+    [PT_ERR_IMG_FORMAT]         = "Unknown image format",
     
     [PT_ERR_PNG_CREATE]         = "png_create()",
     [PT_ERR_PNG]                = "png_*()",
--- a/src/lib/image.c	Mon Jan 25 02:39:28 2010 +0200
+++ b/src/lib/image.c	Mon Jan 25 02:40:19 2010 +0200
@@ -56,7 +56,13 @@
     char cache_path[1024];
     int err;
 
-    // XXX: verify that the path exists and looks like a PNG file
+    // verify that the path exists and looks like a PNG file
+    if ((err = pt_png_check(path)) < 0)
+        return err;
+    
+    if (err)
+        // fail, not a PNG
+        RETURN_ERROR(PT_ERR_IMG_FORMAT);
 
     // alloc
     if ((err = pt_image_new(&image, ctx, path)))
@@ -87,7 +93,7 @@
     
     // open
     if ((fp = fopen(image->path, "rb")) == NULL)
-        RETURN_ERROR(PT_ERR_IMG_FOPEN);
+        RETURN_ERROR(PT_ERR_IMG_OPEN);
 
     // ok
     *file_ptr = fp;
--- a/src/lib/png.c	Mon Jan 25 02:39:28 2010 +0200
+++ b/src/lib/png.c	Mon Jan 25 02:40:19 2010 +0200
@@ -8,13 +8,45 @@
 
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 
+int pt_png_check (const char *path)
+{
+    FILE *fp;
+    uint8_t header[8];
+    int ret;
+
+    // fopen
+    if ((fp = fopen(path, "rb")) == NULL)
+        RETURN_ERROR(PT_ERR_IMG_OPEN);
+
+    // read
+    if (fread(header, 1, sizeof(header), fp) != sizeof(header))
+        JUMP_SET_ERROR(ret, PT_ERR_IMG_FORMAT);
+      
+    // compare signature  
+    if (png_sig_cmp(header, 0, sizeof(header)))
+        // not a PNG file
+        ret = 1;
+
+    else
+        // valid PNG file
+        ret = 0;
+
+error:
+    // cleanup
+    fclose(fp);
+
+    return ret;
+}
+
 int pt_png_open (struct pt_image *image, struct pt_png_img *img)
 {
-    FILE *fp = NULL;
     int err;
+
+    // init
+    memset(img, 0, sizeof(*img));
     
     // open I/O
-    if ((err = pt_image_open_file(image, &fp)))
+    if ((err = pt_image_open_file(image, &img->fh)))
         JUMP_ERROR(err);
 
     // create the struct
@@ -35,27 +67,31 @@
     
 
     // setup I/O to FILE
-    png_init_io(img->png, fp);
+    png_init_io(img->png, img->fh);
 
     // read meta-info
     png_read_info(img->png, img->info);
 
 
-    // XXX: what to do with fp? Should fclose() when done?
+    // img->fh will be closed by pt_png_release_read
     return 0;
 
 error:
     // cleanup
     pt_png_release_read(img);
-
-    if (fp) fclose(fp);
     
     return err;
 }
 
 int pt_png_read_header (struct pt_png_img *img, struct pt_png_header *header, size_t *data_size)
 {
-    // XXX: check image doesn't use any options we don't handle
+    // check image doesn't use any options we don't handle
+    if (png_get_interlace_type(img->png, img->info) != PNG_INTERLACE_NONE) {
+        log_warn("Can't handle interlaced PNG");
+
+        RETURN_ERROR(PT_ERR_IMG_FORMAT);
+    }
+
 
     // initialize
     memset(header, 0, sizeof(*header));
@@ -78,7 +114,7 @@
     header->row_bytes = png_get_rowbytes(img->png, img->info);
 
     // calculate bpp as num_channels * bpc
-    // XXX: this assumes the packed bit depth will be either 8 or 16
+    // this assumes the packed bit depth will be either 8 or 16
     header->col_bytes = png_get_channels(img->png, img->info) * (header->bit_depth == 16 ? 2 : 1);
 
     log_debug("row_bytes=%u, col_bytes=%u", header->row_bytes, header->col_bytes);
@@ -89,7 +125,7 @@
         png_colorp palette;
 
         if (png_get_PLTE(img->png, img->info, &palette, &num_palette) == 0)
-            // XXX: PLTE chunk not read?
+            // PLTE chunk not read?
             RETURN_ERROR(PT_ERR_PNG);
         
         // should only be 256 of them at most
@@ -216,7 +252,7 @@
     
     // write to buffer
     if ((err = pt_tile_mem_write(buf, data, length)))
-        // XXX: log pt_strerror(err)
+        // drop err, because png_error doesn't do formatted output
         png_error(png, "pt_tile_mem_write: ...");
 }
 
@@ -270,19 +306,9 @@
     size_t clip_x, clip_y;
 
 
-    // figure out if the tile clips over the right edge
-    // XXX: use min()
-    if (ti->x + ti->width > header->width)
-        clip_x = header->width;
-    else
-        clip_x = ti->x + ti->width;
-    
-    // figure out if the tile clips over the bottom edge
-    // XXX: use min()
-    if (ti->y + ti->height > header->height)
-        clip_y = header->height;
-    else
-        clip_y = ti->y + ti->height;
+    // fit the left/bottom edge against the image dimensions
+    clip_x = min(ti->x + ti->width, header->width);
+    clip_y = min(ti->y + ti->height, header->height);
 
 
     // allocate buffer for a single row of image data
@@ -415,7 +441,7 @@
     // buffer to hold output rows
     uint8_t *row_buf;
     
-    // XXX: only supports zooming out...
+    // only supports zooming out...
     if (ti->zoom >= 0)
         RETURN_ERROR(PT_ERR_ZOOM);
 
@@ -474,12 +500,15 @@
     struct pt_tile_info *ti = &tile->info;
     int err;
 
+    // init img
+    img->png = NULL;
+    img->info = NULL;
+
     // check within bounds
     if (ti->x >= header->width || ti->y >= header->height)
         // completely outside
         RETURN_ERROR(PT_ERR_TILE_CLIP);
     
-    // XXX: init img
     // open PNG writer
     if ((img->png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL)
         JUMP_SET_ERROR(err, PT_ERR_PNG_CREATE);
@@ -497,6 +526,7 @@
     switch (tile->out_type) {
         case PT_TILE_OUT_FILE:
             // use default FILE* operation
+            // do NOT store in img->fh
             png_init_io(img->png, tile->out.file);
 
             break;
@@ -549,10 +579,23 @@
 void pt_png_release_read (struct pt_png_img *img)
 {
     png_destroy_read_struct(&img->png, &img->info, NULL);
+    
+    // close possible filehandle
+    if (img->fh) {
+        if (fclose(img->fh))
+            log_warn_errno("fclose");
+    }
 }
 
 void pt_png_release_write (struct pt_png_img *img)
 {
     png_destroy_write_struct(&img->png, &img->info);
+
+    // close possible filehandle
+    if (img->fh) {
+        if (fclose(img->fh))
+            log_warn_errno("fclose");
+    }
+
 }
 
--- a/src/lib/png.h	Mon Jan 25 02:39:28 2010 +0200
+++ b/src/lib/png.h	Mon Jan 25 02:40:19 2010 +0200
@@ -21,6 +21,8 @@
     png_struct *png;
     png_info *info;
 
+    /** Possible opened I/O file */
+    FILE *fh;
 };
 
 /**
@@ -50,6 +52,12 @@
 #include "image.h"
 #include "tile.h"
 
+/**
+ * Check if the given path looks like a .png file.
+ *
+ * Returns 0 if ok, 1 if non-png file, -1 on error
+ */
+int pt_png_check (const char *path);
 
 /**
  * Open the given .png image, and read info