From 3f0284935c8189959dd312686416e178556aa52b Mon Sep 17 00:00:00 2001
From: Marcus Comstedt <marcus@mc.pp.se>
Date: Tue, 6 Apr 1999 19:24:32 +0200
Subject: [PATCH] ILBM decoder added.

Rev: src/modules/Image/encodings/Makefile.in:1.22
Rev: src/modules/Image/encodings/any.c:1.5
Rev: src/modules/Image/encodings/iff.c:1.1
Rev: src/modules/Image/encodings/ilbm.c:1.1
Rev: src/modules/Image/image.c:1.121
---
 .gitattributes                          |   2 +
 src/modules/Image/encodings/Makefile.in |   4 +-
 src/modules/Image/encodings/any.c       |  12 +-
 src/modules/Image/encodings/iff.c       |  62 ++++
 src/modules/Image/encodings/ilbm.c      | 462 ++++++++++++++++++++++++
 src/modules/Image/image.c               |  10 +-
 6 files changed, 544 insertions(+), 8 deletions(-)
 create mode 100644 src/modules/Image/encodings/iff.c
 create mode 100644 src/modules/Image/encodings/ilbm.c

diff --git a/.gitattributes b/.gitattributes
index a0d3457305..d6ea693fce 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -183,6 +183,8 @@ testfont binary
 /src/modules/Image/encodings/gif.c foreign_ident
 /src/modules/Image/encodings/gif_lzw.c foreign_ident
 /src/modules/Image/encodings/gif_lzw.h foreign_ident
+/src/modules/Image/encodings/iff.c foreign_ident
+/src/modules/Image/encodings/ilbm.c foreign_ident
 /src/modules/Image/encodings/pcx.c foreign_ident
 /src/modules/Image/encodings/png.c foreign_ident
 /src/modules/Image/encodings/pnm.c foreign_ident
diff --git a/src/modules/Image/encodings/Makefile.in b/src/modules/Image/encodings/Makefile.in
index 127352fb0e..3a5f5d2dc1 100644
--- a/src/modules/Image/encodings/Makefile.in
+++ b/src/modules/Image/encodings/Makefile.in
@@ -1,7 +1,7 @@
-# $Id: Makefile.in,v 1.21 1999/04/06 11:37:16 per Exp $
+# $Id: Makefile.in,v 1.22 1999/04/06 17:24:29 marcus Exp $
 SRCDIR=@srcdir@
 VPATH=@srcdir@:@srcdir@/../../..:../../..
-OBJS = gif.o gif_lzw.o pnm.o x.o xwd.o png.o any.o bmp.o tga.o pcx.o xbm.o _xpm.o
+OBJS = gif.o gif_lzw.o pnm.o x.o xwd.o png.o any.o bmp.o tga.o pcx.o xbm.o _xpm.o ilbm.o iff.o
 
 @SET_MAKE@
 
diff --git a/src/modules/Image/encodings/any.c b/src/modules/Image/encodings/any.c
index d5293e563f..61b0a4ede6 100644
--- a/src/modules/Image/encodings/any.c
+++ b/src/modules/Image/encodings/any.c
@@ -1,9 +1,9 @@
-/* $Id: any.c,v 1.4 1999/03/11 08:29:32 mirar Exp $ */
+/* $Id: any.c,v 1.5 1999/04/06 17:24:30 marcus Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: any.c,v 1.4 1999/03/11 08:29:32 mirar Exp $
+**!	$Id: any.c,v 1.5 1999/04/06 17:24:30 marcus Exp $
 **! submodule ANY
 **!
 **!	This method calls the other decoding methods
@@ -23,7 +23,7 @@
 #include <ctype.h>
 
 #include "stralloc.h"
-RCSID("$Id: any.c,v 1.4 1999/03/11 08:29:32 mirar Exp $");
+RCSID("$Id: any.c,v 1.5 1999/04/06 17:24:30 marcus Exp $");
 #include "pike_macros.h"
 #include "operators.h"
 #include "builtin_functions.h"
@@ -97,6 +97,12 @@ void image_any__decode(INT32 args)
 	 error("can't handle gif's yet\n");
 	 return;
 
+      case CHAR2('F','O'):
+	 /* ILBM (probably) */
+	 img_ilbm_decode(1);
+	 push_text("image/x-ilbm");
+	 goto simple_image;
+
       case CHAR2(0,0):
 	 switch (CHAR2(sp[-args].u.string->str[2],sp[-args].u.string->str[3]))
 	 {
diff --git a/src/modules/Image/encodings/iff.c b/src/modules/Image/encodings/iff.c
new file mode 100644
index 0000000000..b294b05a5b
--- /dev/null
+++ b/src/modules/Image/encodings/iff.c
@@ -0,0 +1,62 @@
+/* $Id: iff.c,v 1.1 1999/04/06 17:24:32 marcus Exp $ */
+
+#include "global.h"
+
+#include "stralloc.h"
+RCSID("$Id: iff.c,v 1.1 1999/04/06 17:24:32 marcus Exp $");
+#include "pike_macros.h"
+#include "object.h"
+#include "constants.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "mapping.h"
+#include "error.h"
+
+
+static INT32 low_parse_iff(unsigned char *data, INT32 len, unsigned char *hdr,
+			   struct mapping *m, unsigned char *stopchunk)
+{
+  INT32 clen;
+  clen = (EXTRACT_CHAR(hdr+4)<<24)|(hdr[5]<<16)|(hdr[6]<<8)|hdr[7];
+
+  if(clen==-1)
+    clen = len;
+  else {
+    if(!memcmp(hdr, "FORM", 4))
+      clen -= 4;
+    if(clen > len)
+      error("truncated file\n");
+    else if(clen < 0)
+      error("invalid chunk length\n");
+  }
+
+  if((!memcmp(hdr, "FORM", 4)) || (!memcmp(hdr, "LIST", 4))) {
+    INT32 pos=0;
+    while(pos+8 <= clen) {
+      INT32 l = low_parse_iff(data+pos+8, clen-pos-8, data+pos, m, stopchunk);
+      if(!l)
+	return 0;
+      pos += l+8;
+    }
+  } else {
+    push_string(make_shared_binary_string(hdr, 4));
+    push_string(make_shared_binary_string(data, clen));
+    mapping_insert(m, sp-2, sp-1);
+    pop_n_elems(2);
+    if(!memcmp(hdr, stopchunk, 4))
+      return 0;
+  }
+  return clen + (clen & 1);
+}
+
+void parse_iff(char *id, unsigned char *data, INT32 len,
+	       struct mapping *m, char *stopchunk)
+{
+  if(len<12 || memcmp("FORM", data, 4))
+    error("invalid IFF FORM\n");
+
+  if(memcmp(id, data+8, 4))
+    error("FORM is not %s\n", id);
+
+  low_parse_iff(data+12, len-12, data, m, stopchunk);
+}
diff --git a/src/modules/Image/encodings/ilbm.c b/src/modules/Image/encodings/ilbm.c
new file mode 100644
index 0000000000..10cb1cde49
--- /dev/null
+++ b/src/modules/Image/encodings/ilbm.c
@@ -0,0 +1,462 @@
+/* $Id: ilbm.c,v 1.1 1999/04/06 17:24:32 marcus Exp $ */
+
+/*
+**! module Image
+**! note
+**!	$Id: ilbm.c,v 1.1 1999/04/06 17:24:32 marcus Exp $
+**! submodule ILBM
+**!
+**!	This submodule keep the ILBM encode/decode capabilities
+**!	of the <ref>Image</ref> module.
+**!
+**! see also: Image, Image.image, Image.colortable
+*/
+#include "global.h"
+
+#include "stralloc.h"
+RCSID("$Id: ilbm.c,v 1.1 1999/04/06 17:24:32 marcus Exp $");
+#include "pike_macros.h"
+#include "object.h"
+#include "constants.h"
+#include "interpret.h"
+#include "svalue.h"
+#include "array.h"
+#include "mapping.h"
+#include "error.h"
+#include "threads.h"
+#include "builtin_functions.h"
+#include "module_support.h"
+
+#include "image.h"
+#include "colortable.h"
+
+
+extern struct program *image_colortable_program;
+extern struct program *image_program;
+
+#define string_BMHD 0
+#define string_CMAP 1
+#define string_CAMG 2
+#define string_BODY 3
+
+static struct svalue string_[4];
+
+struct BMHD {
+    unsigned int w, h;
+    int x, y;
+    unsigned char nPlanes, masking, compression, pad1;
+    unsigned int transparentColor;
+    unsigned char xAspect, yAspect;
+    int pageWidth, pageHeight;
+};
+
+#define mskNone                 0
+#define mskHasMask              1
+#define mskHasTransparentColor  2
+#define mskLasso                3
+
+#define cmpNone                 0
+#define cmpByteRun1             1
+
+
+
+/** decoding *****************************************/
+
+/*
+**! method array __decode();
+**!     Decodes an ILBM image structure down to chunks and
+**!     returns an array containing the ILBM structure;
+**!	
+**!     <pre>
+**!	({int xsize,int ysize,      // 0: size of image drawing area
+**!	  string bitmapheader,      // 2: BMHD chunk
+**!	  void|string colortable,   // 3: opt. colortable chunk (CMAP)
+**!	  void|string colortable,   // 4: opt. colormode chunk (CAMG)
+**!	  string body,		    // 5: BODY chunk
+**!	  mapping more_chunks})	    // 6: mapping with other chunks
+**!	</pre>
+**!
+**! returns the above array
+**!
+**! note
+**!	May throw errors if the ILBM header is incomplete or illegal.
+*/
+
+static void image_ilbm___decode(INT32 args)
+{
+   unsigned char *s;
+   INT32 len;
+   struct pike_string *str;
+   struct mapping *m;
+   int n;
+   extern void parse_iff(char *, unsigned char *, INT32,
+			 struct mapping *, char *);
+
+   get_all_args("__decode", args, "%S", &str);
+
+   s=(unsigned char *)str->str;
+   len=str->len;
+   pop_n_elems(args-1);
+
+   for(n=0; n<5; n++)
+     push_int(0);
+   push_mapping(m = allocate_mapping(4));
+
+   parse_iff("ILBM", s, len, m, "BODY");
+
+   mapping_index_no_free(sp-5, m, &string_[string_BMHD]);
+   mapping_index_no_free(sp-4, m, &string_[string_CMAP]);
+   mapping_index_no_free(sp-3, m, &string_[string_CAMG]);
+   mapping_index_no_free(sp-2, m, &string_[string_BODY]);
+
+   map_delete(m, &string_[string_BMHD]);
+   map_delete(m, &string_[string_CMAP]);
+   map_delete(m, &string_[string_CAMG]);
+   map_delete(m, &string_[string_BODY]);
+
+   if(sp[-5].type != T_STRING)
+     error("Missing BMHD chunk\n");
+   if(sp[-2].type != T_STRING)
+     error("Missing BODY chunk\n");
+
+   /* Extract image size from BMHD */
+   s=(unsigned char *)STR0(sp[-5].u.string);
+   len=sp[-5].u.string->len;
+
+   if(len<20)
+     error("Short BMHD chunk\n");
+
+   free_svalue(sp-7);
+
+   sp[-7].u.integer = (s[0]<<8)|s[1];
+   sp[-7].type = T_INT;
+   sp[-7].subtype = NUMBER_NUMBER;
+   sp[-6].u.integer = (s[2]<<8)|s[3];
+   sp[-6].type = T_INT;
+   sp[-6].subtype = NUMBER_NUMBER;
+
+   f_aggregate(7);
+}
+
+
+/*
+**! method array _decode(string|array data)
+**! 	Decode an ILBM image file.
+**!
+**!     Result is a mapping,
+**!	<pre>
+**!	([
+**!	   "image": object image,
+**!
+**!        ... more ...
+**!     ])
+**!	</pre>
+**!
+**!	<tt>image</tt> is the stored image.
+**!
+*/
+
+static void parse_bmhd(struct BMHD *bmhd, unsigned char *s, INT32 len)
+{
+  if(len<20)
+    error("Short BMHD chunk\n");
+
+  bmhd->w = (s[0]<<8)|s[1];
+  bmhd->h = (s[2]<<8)|s[3];
+  bmhd->x = (EXTRACT_CHAR(s+4)<<8)|s[5];
+  bmhd->y = (EXTRACT_CHAR(s+6)<<8)|s[7];
+  bmhd->nPlanes = s[8];
+  bmhd->masking = s[9];
+  bmhd->compression = s[10];
+  bmhd->pad1 = s[11];
+  bmhd->transparentColor = (s[12]<<8)|s[13];
+  bmhd->xAspect = s[14];
+  bmhd->yAspect = s[15];
+  bmhd->pageWidth = (EXTRACT_CHAR(s+16)<<8)|s[17];
+  bmhd->pageHeight = (EXTRACT_CHAR(s+18)<<8)|s[19];
+}
+
+static void br1unpack(unsigned char *src, unsigned char *dst, int size)
+{
+  unsigned char d, *end=dst+size;
+  signed char c;
+
+  while(dst<end)
+    if((c=*src++)>=0)
+      do { *dst++ = *src++; } while(c--);
+    else if(c!=-128) {
+      d = *src++;
+      do { *dst++ = d; } while(c++);
+    }
+}
+
+
+static INT32 unpackByteRun1(unsigned char *src, INT32 srclen,
+			    unsigned char *dest, int destlen, int depth)
+{
+  unsigned char d, *src0 = src;
+  while(depth>0) {
+    int c, left = destlen;
+    while(left>0) {
+      if(srclen<=0)
+	return src+1-src0;
+      if((c=EXTRACT_CHAR(src++))>=0) {
+	if(srclen<c+2)
+	  return src+2+c-src0;
+	srclen -= c+2;
+	if(1+c>left) {
+	  c = left-1;
+	} else
+	  left -= c+1;
+	do { *dest++ = *src++; } while(c--);
+      } else if(c!=-128) {
+	if(srclen<2)
+	  return src+2-src0;
+	d = *src++;
+	srclen -= 2;
+	if(1-c>left) {
+	  c = 1-left;
+	  left = 0;
+	} else
+	  left -= 1-c;
+	do { *dest++ = d; } while(c++);
+      }
+    }
+    --depth;
+  }
+  return src-src0;
+}
+
+static void planar2chunky(unsigned char *src, int srcmod, int depth,
+			  int w, INT32 *dest)
+{
+  int x, p, bit=0x80;
+  /* Really slow... */
+  for(x=0; x<w; x++) {
+    INT32 pix = 0;
+    for(p=0; p<depth; p++)
+      if(src[p*srcmod]&bit)
+	pix |= 1<<p;
+    *dest++ = pix;
+    if(!(bit>>=1)) {
+      bit = 0x80;
+      src++;
+    }
+  }
+}
+
+static void parse_body(struct BMHD *bmhd, unsigned char *body, INT32 blen,
+		       struct image *img, struct image *alpha,
+		       struct neo_colortable *ctable)
+{
+  unsigned int x, y;
+  int rbyt = ((bmhd->w+15)&~15)>>3;
+  int eplanes = (bmhd->masking == mskHasMask? bmhd->nPlanes+1:bmhd->nPlanes);
+  unsigned char *line;
+  INT32 *cptr, *cline = alloca((rbyt<<3)*sizeof(INT32));
+  INT32 suse;
+  rgb_group *dest = img->img;
+
+  if(ctable != NULL && ctable->type != NCT_FLAT)
+    ctable = NULL;
+
+  switch(bmhd->compression) {
+  case cmpNone:
+    break;
+  case cmpByteRun1:
+    line = alloca(rbyt*eplanes);
+    break;
+  default:
+    error("Unsupported ILBM compression %d\n", bmhd->compression);
+  }
+
+  THREADS_ALLOW();
+
+  for(y=0; y<bmhd->h; y++) {
+    switch(bmhd->compression) {
+    case cmpNone:
+      line = body;
+      suse = rbyt*eplanes;
+      break;
+    case cmpByteRun1:
+      suse = unpackByteRun1(body, blen, line, rbyt, eplanes);
+      break;
+    }
+    body += suse;
+    if((blen -= suse)<0)
+      break;
+    planar2chunky(line, rbyt, bmhd->nPlanes, bmhd->w, cptr=cline);
+    if(ctable != NULL) {
+      int numcolors = ctable->u.flat.numentries;
+      struct nct_flat_entry *entries = ctable->u.flat.entries;
+      for(x=0; x<bmhd->w; x++)
+	if(*cptr<numcolors)
+	  *dest++ = entries[*cptr++].color;
+	else
+	  cptr++;
+    } else
+      for(x=0; x<bmhd->w; x++) {
+	/* ILBM-24 */
+	dest->r = ((*cptr)&0xff0000)>>16;
+	dest->g = ((*cptr)&0x00ff00)>>8;
+	dest->b = ((*cptr)&0x0000ff);
+	cptr++;
+	dest++;
+      }
+  }
+
+  THREADS_DISALLOW();
+
+  if(blen<0)
+    error("truncated or corrupt BODY chunk\n");
+}
+
+static void image_ilbm__decode(INT32 args)
+{
+  struct array *arr;
+  struct object *o;
+  struct image *img;
+  struct BMHD bmhd;
+  struct neo_colortable *ctable = NULL;
+  int n = 0;
+
+  if(args>0 && sp[-args].type == T_STRING) {
+    image_ilbm___decode(args);
+    args = 1;
+  }
+  
+  get_all_args("_decode", args, "%a", &arr);
+
+  if(args>1)
+    pop_n_elems(args-1);
+
+  if(arr->size < 6 ||
+     ITEM(arr)[2].type != T_STRING || ITEM(arr)[2].u.string->size_shift != 0 ||
+     ITEM(arr)[5].type != T_STRING || ITEM(arr)[5].u.string->size_shift != 0)
+    error("Image.ILBM._decode: illegal argument\n");
+
+  parse_bmhd(&bmhd, STR0(ITEM(arr)[2].u.string), ITEM(arr)[2].u.string->len);
+
+  push_text("image");
+  push_int(bmhd.w);
+  push_int(bmhd.h);
+  o=clone_object(image_program,2);
+  img=(struct image*)get_storage(o,image_program);
+  push_object(o);
+  n++;
+
+  if(ITEM(arr)[3].type == T_STRING && ITEM(arr)[3].u.string->size_shift == 0) {
+    unsigned char *pal = STR0(ITEM(arr)[3].u.string);
+    INT32 col, ncol = ITEM(arr)[3].u.string->len/3;
+    push_text("palette");
+    for(col=0; col<ncol; col++) {
+      push_int(*pal++);
+      push_int(*pal++);
+      push_int(*pal++);
+      f_aggregate(3);
+    }
+    f_aggregate(ncol);
+    push_object(clone_object(image_colortable_program,1));
+    ctable=(struct neo_colortable*)get_storage(sp[-1].u.object,
+					       image_colortable_program);
+    n++;
+  }
+
+  parse_body(&bmhd, STR0(ITEM(arr)[5].u.string), ITEM(arr)[5].u.string->len,
+	     img, NULL, ctable);
+
+  f_aggregate_mapping(2*n);
+  stack_swap();
+  pop_stack();
+}
+
+
+/*
+**! method object decode(string data)
+**! method object decode(array _decoded)
+**! method object decode(array __decoded)
+**!	Decodes ILBM data and creates an image object.
+**! 	
+**! see also: encode
+**!
+**! note
+**!	This function may throw errors upon illegal ILBM data.
+**!	This function uses <ref>__decode</ref> and
+**!	<ref>_decode</ref> internally.
+**!
+**! returns the decoded image as an image object
+*/
+
+void img_ilbm_decode(INT32 args)
+{
+   struct svalue *sv;
+
+   if (!args)
+      error("Image.ILBM.decode: too few argument\n");
+
+   if (sp[-args].type != T_MAPPING) {
+     image_ilbm__decode(args);
+     args = 1;
+   }
+     
+   if (sp[-args].type != T_MAPPING)
+     error("Image.ILBM.decode: illegal argument\n");
+
+   if(args>1)
+     pop_n_elems(args-1);
+
+   sv = simple_mapping_string_lookup(sp[-args].u.mapping, "image");
+
+   if(sv == NULL || sv->type != T_OBJECT)
+     error("Image.ILBM.decode: illegal argument\n");
+
+   ref_push_object(sv->u.object);
+   stack_swap();
+   pop_stack();
+}
+
+/** module *******************************************/
+
+struct program *image_encoding_ilbm_program=NULL;
+
+void init_image_ilbm(void)
+{
+   static char *str[] = { "BMHD", "CMAP", "CAMG", "BODY" };
+   int n;
+
+   for(n=0; n<4; n++) {
+     push_string(make_shared_binary_string(str[n], 4));
+     assign_svalue_no_free(&string_[n], sp-1);
+     pop_stack();
+   }
+
+   start_new_program();
+   
+   add_function("__decode",image_ilbm___decode,
+		"function(string:array)",0);
+   add_function("_decode",image_ilbm__decode,
+		"function(string|array:mapping)",0);
+   add_function("decode",img_ilbm_decode,
+		"function(string|array:object)",0);
+
+   image_encoding_ilbm_program=end_program();
+   push_object(clone_object(image_encoding_ilbm_program,0));
+   {
+     struct pike_string *s=make_shared_string("ILBM");
+     add_constant(s,sp-1,0);
+     free_string(s);
+   }
+   pop_stack();
+}
+
+void exit_image_ilbm(void)
+{
+  int n;
+  if(image_encoding_ilbm_program)
+  {
+    free_program(image_encoding_ilbm_program);
+    image_encoding_ilbm_program=NULL;
+  }
+  for(n=0; n<4; n++)
+    free_svalue(&string_[n]);
+}
diff --git a/src/modules/Image/image.c b/src/modules/Image/image.c
index 15ceafc3fd..9e36a5e6d1 100644
--- a/src/modules/Image/image.c
+++ b/src/modules/Image/image.c
@@ -1,9 +1,9 @@
-/* $Id: image.c,v 1.120 1999/04/06 11:36:41 per Exp $ */
+/* $Id: image.c,v 1.121 1999/04/06 17:24:26 marcus Exp $ */
 
 /*
 **! module Image
 **! note
-**!	$Id: image.c,v 1.120 1999/04/06 11:36:41 per Exp $
+**!	$Id: image.c,v 1.121 1999/04/06 17:24:26 marcus Exp $
 **! class image
 **!
 **!	The main object of the <ref>Image</ref> module, this object
@@ -97,7 +97,7 @@
 
 #include "stralloc.h"
 #include "global.h"
-RCSID("$Id: image.c,v 1.120 1999/04/06 11:36:41 per Exp $");
+RCSID("$Id: image.c,v 1.121 1999/04/06 17:24:26 marcus Exp $");
 #include "pike_macros.h"
 #include "object.h"
 #include "constants.h"
@@ -3486,6 +3486,8 @@ extern void init_image__xpm(void);
 extern void exit_image__xpm(void);
 extern void exit_image_xbm(void);
 extern void init_image_xbm(void);
+extern void exit_image_ilbm(void);
+extern void init_image_ilbm(void);
 
 /* dynamic encoders (dependent on other modules, loaded dynamically) */
 
@@ -3859,6 +3861,7 @@ void pike_module_init(void)
    init_image_pcx();
    init_image_xbm();
    init_image__xpm();
+   init_image_ilbm();
    init_image_x();
 }
 
@@ -3882,6 +3885,7 @@ void pike_module_exit(void)
    exit_image_pcx();
    exit_image__xpm();
    exit_image_xbm();
+   exit_image_ilbm();
    if (png_object) 
    {
       free_object(png_object);
-- 
GitLab