add format probes for SGI RGB, ILBM, XPM, PCX, FITS, Photoshop, EPS
authorTony Cook <tony@develop=help.com>
Thu, 30 Mar 2006 04:41:41 +0000 (04:41 +0000)
committerTony Cook <tony@develop=help.com>
Thu, 30 Mar 2006 04:41:41 +0000 (04:41 +0000)
if you have an entry for some other format you want to implement let
me know.

image.c
t/t1000files.t

diff --git a/image.c b/image.c
index 1b5cec3..f1d659d 100644 (file)
--- a/image.c
+++ b/image.c
@@ -2109,7 +2109,39 @@ int i_free_gen_write_data(i_gen_write_data *info, int flush)
   return result;
 }
 
+struct magic_entry {
+  unsigned char *magic;
+  size_t magic_size;
+  char *name;
+  unsigned char *mask;  
+};
+
+static int
+test_magic(unsigned char *buffer, size_t length, struct magic_entry const *magic) {
+  int c;
+
+  if (length < magic->magic_size)
+    return 0;
+  if (magic->mask) {
+    int i;
+    unsigned char *bufp = buffer, 
+      *maskp = magic->mask, 
+      *magicp = magic->magic;
 
+    for (i = 0; i < magic->magic_size; ++i) {
+      int mask = *maskp == 'x' ? 0xFF : *maskp == ' ' ? 0 : *maskp;
+      ++maskp;
+
+      if ((*bufp++ & mask) != (*magicp++ & mask)) 
+       return 0;
+    }
+
+    return 1;
+  }
+  else {
+    return !memcmp(magic->magic, buffer, magic->magic_size);
+  }
+}
 
 /*
 =item i_test_format_probe(io_glue *data, int length)
@@ -2121,16 +2153,12 @@ Check the beginning of the supplied file for a 'magic number'
 
 #define FORMAT_ENTRY(magic, type) \
   { (unsigned char *)(magic ""), sizeof(magic)-1, type }
-
-struct magic_entry {
-    unsigned char *magic;
-    size_t magic_size;
-    char *name;
-};
+#define FORMAT_ENTRY2(magic, type, mask) \
+  { (unsigned char *)(magic ""), sizeof(magic)-1, type, mask }
 
 const char *
 i_test_format_probe(io_glue *data, int length) {
-  static struct magic_entry formats[] = {
+  static const struct magic_entry formats[] = {
     FORMAT_ENTRY("\xFF\xD8", "jpeg"),
     FORMAT_ENTRY("GIF87a", "gif"),
     FORMAT_ENTRY("GIF89a", "gif"),
@@ -2144,8 +2172,40 @@ i_test_format_probe(io_glue *data, int length) {
     FORMAT_ENTRY("P4", "pnm"),
     FORMAT_ENTRY("P5", "pnm"),
     FORMAT_ENTRY("P6", "pnm"),
+    FORMAT_ENTRY("/* XPM", "xpm"),
+    FORMAT_ENTRY("\x8aMNG", "mng"),
+    FORMAT_ENTRY("\x8aJNG", "jng"),
+    /* SGI RGB - with various possible parameters to avoid false positives
+       on similar files 
+       values are: 2 byte magic, rle flags (0 or 1), bytes/sample (1 or 2)
+    */
+    FORMAT_ENTRY("\x01\xDA\x00\x01", "rgb"),
+    FORMAT_ENTRY("\x01\xDA\x00\x02", "rgb"),
+    FORMAT_ENTRY("\x01\xDA\x01\x01", "rgb"),
+    FORMAT_ENTRY("\x01\xDA\x01\x02", "rgb"),
+    
+    FORMAT_ENTRY2("FORM    ILBM", "ilbm", "xxxx    xxxx"),
+
+    /* different versions of PCX format 
+       http://www.fileformat.info/format/pcx/
+    */
+    FORMAT_ENTRY("\x0A\x00\x01", "pcx"),
+    FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
+    FORMAT_ENTRY("\x0A\x03\x01", "pcx"),
+    FORMAT_ENTRY("\x0A\x04\x01", "pcx"),
+    FORMAT_ENTRY("\x0A\x05\x01", "pcx"),
+
+    /* FITS - http://fits.gsfc.nasa.gov/ */
+    FORMAT_ENTRY("SIMPLE  =", "fits"),
+
+    /* PSD - Photoshop */
+    FORMAT_ENTRY("8BPS\x00\x01", "psd"),
+    
+    /* EPS - Encapsulated Postscript */
+    /* only reading 18 chars, so we don't include the F in EPSF */
+    FORMAT_ENTRY("%!PS-Adobe-2.0 EPS", "eps"),
   };
-  static struct magic_entry more_formats[] = {
+  static const struct magic_entry more_formats[] = {
     FORMAT_ENTRY("\x00\x00\x01\x00", "ico"),
     FORMAT_ENTRY("\x00\x00\x02\x00", "ico"), /* cursor */
   };
@@ -2160,13 +2220,10 @@ i_test_format_probe(io_glue *data, int length) {
   data->seekcb(data, -rc, SEEK_CUR);
 
   for(i=0; i<sizeof(formats)/sizeof(formats[0]); i++) { 
-    int c;
-    if (rc < formats[i].magic_size)
-      continue;
-    c = !memcmp(formats[i].magic, head, formats[i].magic_size);
-    if (c) {
-      return formats[i].name;
-    }
+    struct magic_entry const *entry = formats + i;
+
+    if (test_magic(head, rc, entry)) 
+      return entry->name;
   }
 
   if ((rc == 18) &&
@@ -2174,13 +2231,10 @@ i_test_format_probe(io_glue *data, int length) {
     return "tga";
 
   for(i=0; i<sizeof(more_formats)/sizeof(more_formats[0]); i++) { 
-    int c;
-    if (rc < more_formats[i].magic_size)
-      continue;
-    c = !memcmp(more_formats[i].magic, head, more_formats[i].magic_size);
-    if (c) {
-      return more_formats[i].name;
-    }
+    struct magic_entry const *entry = more_formats + i;
+
+    if (test_magic(head, rc, entry)) 
+      return entry->name;
   }
 
   return NULL;
index 341288b..b77969a 100644 (file)
@@ -5,7 +5,7 @@
 
 use strict;
 use lib 't';
-use Test::More tests => 20;
+use Test::More tests => 27;
 use Imager;
 
 Imager::init_log("testout/t1000files.log", 1);
@@ -86,6 +86,48 @@ probe_ok(<<ICO, "ico", "Windows Icon");
 00 00 0E 03 00 00 28 00 00 00 20 00 00 00 40 00
 ICO
 
+probe_ok(<<RGB, "rgb", "SGI RGB");
+01 DA 01 01 00 03 00 96 00 96 00 03 00 00 00 00 
+00 00 00 FF 00 00 00 00 6E 6F 20 6E 61 6D 65 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+RGB
+
+probe_ok(<<ILBM, "ilbm", "ILBM");
+46 4F 52 4D 00 00 60 7A 49 4C 42 4D 42 4D 48 44
+00 00 00 14 00 96 00 96 00 00 00 00 18 00 01 80
+00 00 0A 0A 00 96 00 96 42 4F 44 59 00 00 60 51
+ILBM
+
+probe_ok(<<XPM, "xpm", "XPM");
+2F 2A 20 58 50 4D 20 2A 2F 0A 73 74 61 74 69 63
+20 63 68 61 72 20 2A 6E 6F 6E 61 6D 65 5B 5D 20
+3D 20 7B 0A 2F 2A 20 77 69 64 74 68 20 68 65 69
+XPM
+
+probe_ok(<<PCX, "pcx", 'PCX');
+0A 05 01 08 00 00 00 00 95 00 95 00 96 00 96 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+PCX
+
+probe_ok(<<FITS, "fits", "FITS");
+53 49 4D 50 4C 45 20 20 3D 20 20 20 20 20 20 20 
+20 20 20 20 20 20 20 20 20 20 20 20 20 54 20 20 
+20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 
+FITS
+
+probe_ok(<<PSD, "psd", "Photoshop");
+38 42 50 53 00 01 00 00 00 00 00 00 00 06 00 00
+00 3C 00 00 00 96 00 08 00 03 00 00 00 00 00 00
+0B E6 38 42 49 4D 03 ED 00 00 00 00 00 10 00 90
+PSD
+
+probe_ok(<<EPS, "eps", "Encapsulated Postscript");
+25 21 50 53 2D 41 64 6F 62 65 2D 32 2E 30 20 45
+50 53 46 2D 32 2E 30 0A 25 25 43 72 65 61 74 6F
+72 3A 20 70 6E 6D 74 6F 70 73 0A 25 25 54 69 74
+EPS
+
 sub probe_ok {
   my ($packed, $exp_type, $name) = @_;