Index: /branches/eam_branches/ohana.20150429/src/libfits/Makefile
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/Makefile	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/Makefile	(revision 38329)
@@ -37,14 +37,15 @@
 
 MATRIX_OBJ = \
-$(MATR)/F_add_M_value.$(ARCH).o 		$(MATR)/F_add_M.$(ARCH).o        \
-$(MATR)/F_create_M.$(ARCH).o 			$(MATR)/F_divide_M.$(ARCH).o     \
-$(MATR)/F_free_M.$(ARCH).o 			$(MATR)/F_copy_M.$(ARCH).o       \
-$(MATR)/F_write_M.$(ARCH).o 			$(MATR)/F_get_M_value.$(ARCH).o  \
-$(MATR)/F_multiply_M.$(ARCH).o 			$(MATR)/F_read_M.$(ARCH).o       \
-$(MATR)/F_insert_M.$(ARCH).o 			$(MATR)/F_set_M_value.$(ARCH).o  \
-$(MATR)/F_convert_format.$(ARCH).o              $(MATR)/F_read_segment.$(ARCH).o \
-$(MATR)/F_read_portion.$(ARCH).o		$(MATR)/F_load_M.$(ARCH).o	 \
-$(MATR)/F_matrix.$(ARCH).o                      $(MATR)/F_compress_M.$(ARCH).o   \
-$(MATR)/F_uncompress_data.$(ARCH).o
+$(MATR)/F_add_M_value.$(ARCH).o 		$(MATR)/F_add_M.$(ARCH).o          \
+$(MATR)/F_create_M.$(ARCH).o 			$(MATR)/F_divide_M.$(ARCH).o       \
+$(MATR)/F_free_M.$(ARCH).o 			$(MATR)/F_copy_M.$(ARCH).o         \
+$(MATR)/F_write_M.$(ARCH).o 			$(MATR)/F_get_M_value.$(ARCH).o    \
+$(MATR)/F_multiply_M.$(ARCH).o 			$(MATR)/F_read_M.$(ARCH).o         \
+$(MATR)/F_insert_M.$(ARCH).o 			$(MATR)/F_set_M_value.$(ARCH).o    \
+$(MATR)/F_convert_format.$(ARCH).o              $(MATR)/F_read_segment.$(ARCH).o   \
+$(MATR)/F_read_portion.$(ARCH).o		$(MATR)/F_load_M.$(ARCH).o	   \
+$(MATR)/F_matrix.$(ARCH).o                      $(MATR)/F_compress_utils.$(ARCH).o \
+$(MATR)/F_compress_M.$(ARCH).o   		$(MATR)/F_compress_data.$(ARCH).o  \
+$(MATR)/F_uncompress_M.$(ARCH).o                $(MATR)/F_uncompress_data.$(ARCH).o
 
 TABLE_OBJ = \
@@ -55,5 +56,6 @@
 $(TABL)/F_set_column.$(ARCH).o			$(TABL)/F_get_column.$(ARCH).o   \
 $(TABL)/F_table_row.$(ARCH).o			$(TABL)/F_free_T.$(ARCH).o       \
-$(TABL)/F_table_varlength.$(ARCH).o		$(TABL)/F_copy_T.$(ARCH).o
+$(TABL)/F_table_varlength.$(ARCH).o		$(TABL)/F_copy_T.$(ARCH).o       \
+$(TABL)/F_compress_T.$(ARCH).o                  $(TABL)/F_uncompress_T.$(ARCH).o
 
 EXTERN_OBJ = \
Index: /branches/eam_branches/ohana.20150429/src/libfits/extern/gzip.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/extern/gzip.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/extern/gzip.c	(revision 38329)
@@ -131,9 +131,10 @@
     if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
 
-    stream.zalloc = (alloc_func)0;
-    stream.zfree = (free_func)0;
+    stream.zalloc = Z_NULL;
+    stream.zfree  = Z_NULL;
+    stream.opaque = Z_NULL;
 
-    // MAX_WBITS = 15
-    err = inflateInit2(&stream, -15);
+    // err = inflateInit2(&stream, -15);
+    err = inflateInit(&stream);
     if (err != Z_OK) return err;
 
@@ -156,5 +157,5 @@
   z_stream stream;
   int err;
-
+  
   stream.next_in = (Bytef*)source;
   stream.avail_in = (uInt)sourceLen;
@@ -167,8 +168,10 @@
   if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
 
-  stream.zalloc = (alloc_func)0;
-  stream.zfree = (free_func)0;
+  stream.zalloc = Z_NULL;
+  stream.zfree  = Z_NULL;
+  stream.opaque = Z_NULL;
 
-  err = deflateInit(&stream);
+  // the '5' is the compression level: make this a user argument
+  err = deflateInit(&stream, 5);
   if (err != Z_OK) return err;
 
Index: /branches/eam_branches/ohana.20150429/src/libfits/include/gfitsio.h
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/include/gfitsio.h	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/include/gfitsio.h	(revision 38329)
@@ -73,4 +73,5 @@
   off_t                   datasize; // size of the buffer (including block padding at the end)
   off_t                   validsize;  // size of the valid portion of the table (< validsize if file is short)
+  off_t                   heap_start; // byte offset to start of HEAP
 } FTable;
 
@@ -85,12 +86,32 @@
 } VTable;
 
-typedef struct {
-  int   maxlen; 	      // max size of all table rows
-  int   nbytes;		      // number of bytes per column element
-  int   Nstart;		      // byte offset of this column relative to first column
-  off_t heap_start;	      // byte offset to start of HEAP
-  char  format;		      // data format character (one of: XLABIJEDCM)
-  char  mode;		      // access data pointer type (one of P or Q)
+// description / metadata needed for a single varlength column.  A varlength column has a
+// 2-element array giving the (length,offset) of data in the heap.  Below, 'real data' are
+// the values in the heap; 'metadata' are the values in the main table.
+typedef struct {
+  int   column;		      // field number (of the metadata)
+  char  format;		      // format character for real data (one of: XLABIJKEDCM)
+  char  mode;		      // format character for metadata (one of P [float] or Q [double])
+  int   maxlen; 	      // max size of all table rows for this column
+  int   nbytes;		      // number of bytes per real data column element 
+  int   offset;		      // byte offset of the metadata column relative to first column
 } VarLengthColumn;
+
+typedef struct {
+  char ttype[16]; 	      // TTYPE field of original table
+  char ttype_cmt[80];	      // comment associated with TTYPE
+  char tunit[16];	      // TUNIT field of original table
+  char tunit_cmt[80];	      // comment associated with TUNIT
+  char tformat[16];	      // TFORM field of original table
+  char tformat_cmt[80];	      // comment associated with TFORM
+  char zctype[80];	      // compression type for this field
+  VarLengthColumn zdef;	      // description of the output variable length column
+
+  char datatype[80];	      // named data type associated with ttype (eg, 18J -> int, 18D -> double)
+  int Nvalues;		      // number of values per row (eg 18J -> 18 int values)
+  int pixsize;		      // number of bytes per value of this row (eg, 18J -> 4 bytes)
+  int rowsize;		      // number of bytes for a full row (Nvalues * pixsize)
+  int offset;		      // byte offset of the real data column relative to first column
+} TableField;
 
 # ifndef PROTO
@@ -133,4 +154,5 @@
 off_t   gfits_data_min_size            PROTO((Header *header));
 off_t   gfits_data_pad_size            PROTO((off_t rawsize));
+off_t   gfits_heap_start               PROTO((Header *header));
 int 	gfits_extended_to_primary      PROTO((Header *header, int simple, char *comment));
 int 	gfits_primary_to_extended      PROTO((Header *header, char *exttype, char *comment));
@@ -166,13 +188,31 @@
 void   	gfits_set_matrix_value         PROTO((Matrix *matrix, off_t x, off_t y, double value)); 
 int     gfits_write_matrix             PROTO((char *filename, Matrix *matrix)); 
+
 int     gfits_uncompress_image 	       PROTO((Header *header, Matrix *matrix, FTable *ftable));
 int     gfits_uncompress_data  	       PROTO((char *zdata, int Nzdata, char *cmptype, char **optname, char **optvalue, int Nopt, char *outdata, int *Nout, int out_pixsize));
 int     gfits_distribute_data  	       PROTO((Matrix *matrix, int bitpix, char *data, int Ndata, int *otile, int oblank, int *ztile, int zblank, float zscale, float zzero));
+
+int     gfits_compress_data  	       PROTO((char *zdata, int *Nzdata, char *cmptype, char **optname, char **optvalue, int Nopt, char *rawdata, int Nraw, int raw_pixsize));
+int     gfits_compress_image 	       PROTO((Header *header, Matrix *matrix, FTable *ftable, int *Ztile, char *zcmptype));
+int     gfits_collect_data   	       PROTO((Matrix *matrix, char *raw, int Nraw, int raw_pixsize, int *otile, int oblank, int *ztile, int zblank, float zscale, float zzero));
+int     gfits_copy_keywords_compress   PROTO((Header *srchead, Header *tgthead));
+
+off_t   gfits_tile_size                PROTO((Matrix *matrix, int *otile, int *ztile));
+int 	gfits_imtile_maxsize           PROTO((Matrix *matrix, int *ztile));
+int 	gfits_imtile_count             PROTO((Matrix *matrix, int *ztile, int *ntile));
+int 	gfits_imtile_start             PROTO((Matrix *matrix, int *otile));
+int 	gfits_imtile_next              PROTO((Matrix *matrix, int *ztile, int *ntile, int *otile));
+
 int     gfits_byteswap_zdata   	       PROTO((char *zdata, int Nzdata, int bitpix));
 int     gfits_extension_is_compressed  PROTO((Header *header));
-off_t   gfits_tile_size                PROTO((Matrix *matrix, int *otile, int *ztile));
 int     gfits_uncompressed_data_pixsize PROTO((char *cmptype, int out_bitpix, char **optname, char **optvalue, int Noptions));
 int     gfits_vartable_heap_pixsize    PROTO((char format));
 
+int     gfits_varlength_column_add_data PROTO((FTable *table, char *data, off_t Ndata, int row, VarLengthColumn *column));
+void   *gfits_varlength_column_pointer  PROTO((FTable *ftable, VarLengthColumn *column, off_t row, off_t *length));
+int     gfits_varlength_column_define   PROTO((FTable *ftable, VarLengthColumn *def, int column));
+int     gfits_varlength_column_finish   PROTO((FTable *ftable, VarLengthColumn *def));
+int     gfits_byteswap_varlength_column PROTO((FTable *ftable, int column));
+
 /******************************* Table functions *************/
 
@@ -182,4 +222,5 @@
 char   *gfits_table_print              PROTO((FTable *ftable,...));
 int     gfits_add_rows                 PROTO((FTable *ftable, char *data, off_t Nrow, off_t Nbytes));
+int     gfits_set_table_rows           PROTO((Header *header, FTable *table, off_t Nrows));
 int     gfits_bintable_format          PROTO((char *format, char *type, int *Nval, int *Nbytes));
 int     gfits_create_table             PROTO((Header *header, FTable *ftable));
@@ -226,6 +267,5 @@
 int     gfits_write_Theader            PROTO((char *filename, Header *header));
 
-int     gfits_varlength_column_define  PROTO((FTable *ftable, VarLengthColumn *def, int column));
-void   *gfits_varlength_column_pointer PROTO((FTable *ftable, VarLengthColumn *column, off_t row, off_t *length));
+int     gfits_compress_table           PROTO((FTable *srctable, FTable *tgttable, int ztilelen, char *zcmptype));
 
 #endif /* FITSIO */
Index: /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_M.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_M.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_M.c	(revision 38329)
@@ -3,26 +3,7 @@
 # include <zlib.h>
 
-# define ESCAPE { \
-  if (ztile != NULL) free (ztile); \
-  if (optname != NULL) { \
-    for (j = 0; j < Noptions; j++) { \
-      free (optname[j]); \
-      free (optvalue[j]); \
-    } \
-    free (optname); \
-    free (optvalue); \
-  } \
-  if (out != NULL) free (out); \
-  if (otile != NULL) free (otile); \
-  if (ntile != NULL) free (ntile); \
-  return (FALSE); }
-
-# define MOD_KEYWORD(ZNAME,NAME,TYPE,OUT,VALUE) { \
-    gfits_modify (theader, ZNAME, TYPE, 1, OUT);	  \
-    gfits_delete (theader, NAME, 1); }
-
 // the user needs to specify the various compression options:
-// ztile[i] 
-// zcmptype
+// ztile[i] (may be NULL)
+// zcmptype 
 
 // steps to convert an image to a compressed table:
@@ -35,23 +16,21 @@
 // * update header keywords
 
-// XXX do not try to support compression of an image with an associated table (not valid)
-
-int gfits_compress_image (Header *header, Matrix *matrix, FTable *ftable, int *ztile, char *zcmptype) {
-
-  // off_t Nzdata, Nzrows, zcol;
-  // int i, j, status, zimage, Nout, max_tile_size;
-  // char cmptype[80];
-  // char zaxis[10], naxis[10], key[10], word[81], exttype[81], checksum[81], datasum[81];
-  // int Noptions, NOPTIONS, zblank, oblank;
-  // VarLengthColumn zdef;
-  // float zscale, zzero;
-
-  // int zdata_pixsize, odata_pixsize;
-  // int *otile = NULL;
-  // int *ntile = NULL;
-  // char **optname = NULL;
-  // char **optvalue = NULL;
-  // char *out = NULL;
-  // char *zdata = NULL;
+// we do not try to support compression of an image with an associated table (not valid)
+
+# define ESCAPE(A) { fprintf (stderr, "error in %s @ line %d\n", __func__, __LINE__); goto escape; }
+
+int gfits_compress_image (Header *header, Matrix *matrix, FTable *ftable, int *Ztile, char *zcmptype) {
+
+  int i;
+
+  // pointers to track the tile data
+  int *otile = NULL;
+  int *ntile = NULL;
+  char *raw = NULL;
+  char *zdata = NULL;
+
+  int *ztile = Ztile;
+
+  Header *theader = ftable->header;
 
   // determine the number of tiles (from ztile[] and image size)
@@ -67,41 +46,73 @@
 
   // creates an empty (Naxes = 2, Naxis[i] = 0) table header with XTENSION = BINTABLE, EXTNAME = COMPRESSED_IMAGE
-  gfits_create_table_header (&theader, "BINTABLE", "COMPRESSED_IMAGE");
+  if (!gfits_create_table_header (theader, "BINTABLE", "COMPRESSED_IMAGE")) ESCAPE(A);
 
   // by using "P" format, we are limited to 32bit pointers (2GB heap)
   // XXX how is the "B" format used?
-  gfits_define_bintable_column (&theader, "1PB(0)", "COMPRESSED_DATA", "compressed image data", "none", 1.0, 0.0);
-
-  // XXX I need to copy the bulk of the header from the matrix header -> ftable.header
-  gfits_create_table (&theader, ftable);
-  // copy original header to output header
-  // XXX gfits_copy_header (header, theader); -- I need to copy only the desired keywords.
+  if (!gfits_define_bintable_column (theader, "1PB(0)", "COMPRESSED_DATA", "compressed image data", "none", 1.0, 0.0)) ESCAPE (A);
+  if (!gfits_delete (theader, "TUNIT1", 1)) ESCAPE(A);
+
+  // allocates the default data array (ftable->buffer)
+  if (!gfits_create_table (theader, ftable)) ESCAPE (A);
+
+  // copy original header to output header (XXX this needs to be finished)
+  if (!gfits_copy_keywords_compress (header, theader)) ESCAPE (A);
   
-  // this allocates the data array 
+  // this allocates the pointer data array for the full set of tiles (NOT the heap)
   char *tmpbuffer = NULL;
   ALLOCATE_ZERO (tmpbuffer, char, Ntile);
-  gfits_set_bintable_column (&theader, &ftable, "COMPRESSED_DATA", tmpbuffer, Ntile);
+  if (!gfits_set_bintable_column (theader, ftable, "COMPRESSED_DATA", tmpbuffer, Ntile)) ESCAPE (A);
+  free (tmpbuffer);
 
   // add ZIMAGE from output header
-  gfits_modify_alt (theader, "ZIMAGE", "%t", 1, TRUE);
-
-  // translate image-specific keywords to Z versions (updates the Z version, removes the old version)
-  // XXX use the header or the structure as authoratative?
-  MOVE_KEYWORD ("ZBITPIX", "BITPIX", "%d");
-  MOVE_KEYWORD ("ZNAXIS",  "NAXIS",  "%d");
+  if (!gfits_modify_alt (theader, "ZIMAGE", "%t", 1, TRUE)) ESCAPE (A);
+
+  // define compression-specific keywords, update header as needed.
+  if (!gfits_modify (theader, "ZCMPTYPE", "%s", 1, zcmptype)) ESCAPE(A);
+
+  if (!gfits_modify_alt (theader, "ZSIMPLE", "%t", 1, TRUE)) ESCAPE (A);
+  // gfits_modify (header, "ZTENSION", "%s", 1, exttype);
+
+  // supply the Z* header values from the source image header
+  if (!gfits_modify (theader, "ZBITPIX", "%d", 1, header[0].bitpix)) ESCAPE (A);
+
+  if (!gfits_modify (theader, "ZNAXIS",  "%d", 1, header[0].Naxes)) ESCAPE (A);
+
+  char keyword[11];
+  for (i = 0; i < header[0].Naxes; i++) {
+    snprintf (keyword, 10, "ZNAXIS%d", i + 1);
+    if (!gfits_modify (theader, keyword, OFF_T_FMT, 1,  header[0].Naxis[i])) ESCAPE (A);
+  }
 
   for (i = 0; i < header->Naxes; i++) {
-    snprintf (zaxis, 10, "ZNAXIS%d", i + 1);
-    snprintf (naxis, 10, "NAXIS%d", i + 1);
-    MOD_KEYWORD (zaxis,  naxis,  OFF_T_FMT,  header->Naxis[i]);
-  }    
-
-  for (i = 0; i < header->Naxes; i++) {
-    snprintf (key, 10, "ZTILE%d", i + 1);
-    if (!gfits_modify (theader, key, "%d", 1, ztile[i])) ESCAPE;
-  }
-
-  // define compression-specific keywords, update header as needed.
-  if (!gfits_modify (header, "ZCMPTYPE", "%s", 1, zcmptype)) ESCAPE;
+    snprintf (keyword, 10, "ZTILE%d", i + 1);
+    if (!gfits_modify (theader, keyword, "%d", 1, ztile[i])) ESCAPE(A);
+  }
+
+  if (!gfits_modify (theader, "BSCALE", "%lf", 1, header[0].bscale)) ESCAPE (A);
+  if (!gfits_modify (theader, "BZERO",  "%lf", 1, header[0].bzero)) ESCAPE (A);
+
+  // other keywords to define:
+  // ZEXTEND
+  // ZBLOCKED
+  // ZHECKSUM
+  // ZDATASUM
+  // PCOUNT -> ZPCOUNT
+  // GCOUNT -> ZGCOUNT
+
+  float zscale = 1.0;
+  // gfits_modify (header, "ZSCALE", "%f", 1, zscale);
+
+  float zzero = 0.0;
+  // gfits_modify (header, "ZZERO", "%f", 1, zzero);
+
+  int zblank = 32767;
+  // gfits_modify (header, "ZBLANK", "%d", 1, zblank);
+
+  int oblank = 32767;
+  // gfits_modify (header, "BLANK", "%d", 1, oblank);
+
+# if (0)
+  // need to set ZNAMEnn and ZVALnn if they are defined and used
 
   // search for algorithm-specific keywords. these are used to control compression options
@@ -114,101 +125,23 @@
     if (!gfits_modify (header, key, "%s", 1, optvalue[i])) break;
   }
-
-# if (0)
-  // XXX get ZMASKCMP 
-  int zsimple, have_zsimple;
-  int have_ztension;
-
-  // NOTE target of %t must be int length
-  // XXX how do I specify this??
-  // have_zsimple  = gfits_scan_alt (header, "ZSIMPLE", "%t", 1, &zsimple);
-  // have_ztension = gfits_scan (header, "ZTENSION", "%s", 1, exttype);
-
-  // this is a very bogus case: we cannot have both keywords
-  if (have_zsimple && have_ztension) ESCAPE;
-
-  // if neither are present, we have an image that is not really following the standard:
-  // assume it is a PHU
-  if (!have_zsimple && !have_ztension) {
-    header->simple = TRUE;
-    gfits_extended_to_primary (header, header->simple, "Image data");
-
-    MOD_KEYWORD_ALT ("ZEXTEND",  "EXTEND",   "%t", &header->extend, header->extend);
-    MOD_KEYWORD_ALT ("ZBLOCKED", "BLOCKED",  "%t", &header->extend, header->extend);
-  }
-
-  // have_zsimple : image comes from a PHU
-  if (have_zsimple) {
-    header->simple = zsimple;
-    gfits_delete (header, "ZSIMPLE", 1);
-    gfits_extended_to_primary (header, header->simple, "Image data");
-
-    MOD_KEYWORD_ALT ("ZEXTEND",  "EXTEND",   "%t", &header->extend, header->extend);
-    MOD_KEYWORD_ALT ("ZBLOCKED", "BLOCKED",  "%t", &header->extend, header->extend);
-  } 
-
-  // have_ztension : image comes from an extension
-  if (have_ztension) {
-    gfits_delete (header, "ZTENSION", 1);
-    gfits_modify_extended (header, exttype, "Image extension");
-
-    // we may have an uncompressed PCOUNT / GCOUNT value, otherwise set to 0,1
-    if (gfits_scan (header, "ZPCOUNT", "%d", 1, &header->pcount)) {
-	gfits_delete (header, "ZPCOUNT", 1);
-	gfits_modify (header, "PCOUNT", "%d", 1, header->pcount);
-    } else {
-	header->pcount = 0;
-	gfits_modify (header, "PCOUNT", "%d", 1, header->pcount);
-    }
-    if (gfits_scan (header, "ZGCOUNT", "%d", 1, &header->gcount)) {
-	gfits_delete (header, "ZGCOUNT", 1);
-	gfits_modify (header, "GCOUNT", "%d", 1, header->gcount);
-    } else {
-	header->pcount = 1;
-	gfits_modify (header, "GCOUNT", "%d", 1, header->gcount);
-    }
-  } else {
-    header->pcount = 0;
-    header->gcount = 1;
-    gfits_modify (header, "PCOUNT", "%d", 1, header->pcount);
-    gfits_modify (header, "GCOUNT", "%d", 1, header->gcount);
-  }
-
-  MOD_KEYWORD ("ZHECKSUM", "CHECKSUM", "%s", checksum,        checksum);
-  MOD_KEYWORD ("ZDATASUM", "DATASUM",  "%s", datasum,         datasum);
-
-  zscale = 1;
-  gfits_scan (header, "ZSCALE", "%f", 1, &zscale);
-
-  zblank = 32767;
-  gfits_scan (header, "ZBLANK", "%d", 1, &zblank);
-
-  oblank = 32767;
-  gfits_scan (header, "BLANK", "%d", 1, &oblank);
-
-  zzero = 0;
-  gfits_scan (header, "ZZERO", "%f", 1, &zzero);
 # endif
 
-  // XXX how to define zdef?
   VarLengthColumn zdef;
-  if (!gfits_varlength_column_define (ftable, &zdef, zcol)) ESCAPE;
-
-  max_tile_size = gfits_imtile_maxsize (matrix, ztile);
-
-  // size of an element in the vartable heap section
-  zdata_pixsize = gfits_vartable_heap_pixsize (zdef.format);
-
-  // size of a pixel in the final image (not needed)
-  // raw_pixsize = gfits_uncompressed_data_pixsize (cmptype, header[0].bitpix, optname, optvalue, Noptions)
+  if (!gfits_varlength_column_define (ftable, &zdef, 1)) ESCAPE(A);
+
+  // allocate the working buffers to the max tile size
+  int max_tile_size = gfits_imtile_maxsize (matrix, ztile);
 
   // size of a pixel in the raw image tile:
-  raw_pixsize = abs(header[0].bitpix) / 8;
+  int raw_pixsize = abs(header[0].bitpix) / 8;
+
+  // size of a pixel in the raw image tile:
+  int tile_pixsize = gfits_uncompressed_data_pixsize (zcmptype, header[0].bitpix, NULL, NULL, 0);
 
   ALLOCATE (raw,   char, raw_pixsize*max_tile_size);
-  ALLOCATE (zdata, char, raw_pixsize*max_tile_size); // 
+  ALLOCATE (zdata, char, raw_pixsize*max_tile_size);
 
   // init the otile[] counters
-  gfits_imfile_start (matrix, otile);
+  if (!gfits_imtile_start (matrix, otile)) ESCAPE (A);
 
   // compress the data : copy into a tile, compress the tile, then add to the output table
@@ -217,35 +150,55 @@
 
     // size of the current tile
-    Nraw = gfits_tile_size (matrix, otile, ztile);
+    int Nraw = gfits_tile_size (matrix, otile, ztile);
 
     // copy the raw pixels from their native matrix locations to the temporary output buffer
-    if (!gfits_collect_data (matrix, raw, Nraw, raw_pixsize, otile, oblank, ztile, zblank, zscale, zzero)) return (FALSE);
+    if (!gfits_collect_data (matrix, raw, Nraw, raw_pixsize, otile, oblank, ztile, zblank, zscale, zzero)) ESCAPE(A);
 
     // XXX the tile must not be > 2GB
-
-    Nzdata = raw_pixsize*max_tile_size; // available space, replaced with actual output size on compression
-    if (!gfits_compress_data (zdata, &Nzdata, zcmptype, optname, optvalue, Noptions, raw, Nraw, raw_pixsize)) return (FALSE);
-
-    if (!gfits_varlength_column_add_data (ftable, zdata, Nzdata, i, &zdef)) return FALSE;
+   
+    // optname, optvalue = NULL, Noptions = 0
+
+    int Nzdata = raw_pixsize*max_tile_size; // available space, replaced with actual output size on compression
+    if (!gfits_compress_data (zdata, &Nzdata, zcmptype, NULL, NULL, 0, raw, Nraw, tile_pixsize)) ESCAPE(A);
+
+    if (!gfits_varlength_column_add_data (ftable, zdata, Nzdata, i, &zdef)) ESCAPE(A);
 
     // XXX need to activate
-    if (FALSE) gfits_byteswap_zdata (zdata, Nzdata, zdata_pixsize) return (FALSE);
+    // if (FALSE) gfits_byteswap_zdata (zdata, Nzdata, zdata_pixsize) ESCAPE(A);
 
     // update the otile[] counters, carrying to the next dimension if needed
-    gfits_imfile_next (matrix, ztile, ntile, otile);
-  }
+    gfits_imtile_next (matrix, ztile, ntile, otile);
+  }
+
+  if (!gfits_varlength_column_finish (ftable, &zdef)) ESCAPE(A);
+
+  free (raw);
+  free (zdata);
+
+  free (otile);
+  free (ntile);
+
+  if (!Ztile) free (ztile);
   return (TRUE);
+
+escape:
+  FREE (raw);
+  FREE (zdata);
+
+  FREE (otile);
+  FREE (ntile);
+
+  if (!Ztile) FREE (ztile);
+  return FALSE;
 }
 
-  // this takes place in three major steps:
-  // 1) rawdata -> tiledata (copy a tile chunk to the tiledata buffer)
-  // 2) compress tiledata -> zdata
-  // 3) add zdata to table data heap
-
-  // heapdata.pixsize : zdef.format
-  // zdata.pixsize : depends on compression
-  // odata.pixsize : depends on compression
-  // idata.pixsize : header.bitpix
-
+int gfits_copy_keywords_compress (Header *srchead, Header *tgthead) {
+
+  int i;
+
+  for (i = 0; i < srchead->datasize; i += FT_LINE_LENGTH) {
+  }
+  return TRUE;
+}
 
 // raw_pixsize is the bytes / pixel for the input matrix
@@ -298,4 +251,16 @@
       } } }
 
+  // we need to set up switches for all of the possible combinations:
+  // this macro is used at the inner switch to run the actual loop
+  // note we copy Optr to Iptr 
+# define SCALE_AND_DIST_FLOAT(TYPE, SIZE) {					\
+    TYPE *Optr = (TYPE *) &matrix->buffer[SIZE*(offset + start)];	\
+    for (j = 0; j < Ztile[0]; j++, Iptr++, Optr++) {			\
+      if (!isfinite(*Optr)) {						\
+	*Iptr = zblank;							\
+      } else {								\
+	*Iptr = (*Optr - zzero) / zscale;				\
+      } } }
+
   // this macro sets up the outer switch and calls above macro with all output bitpix options
 # define SETUP_INSIZE(TYPE, SIZE) {			\
@@ -312,8 +277,8 @@
 	break;						\
       case -32:						\
-	SCALE_AND_DIST (float, 4);			\
+	SCALE_AND_DIST_FLOAT (float, 4);			\
 	break;						\
       case -64:						\
-	SCALE_AND_DIST (double, 8);			\
+	SCALE_AND_DIST_FLOAT (double, 8);			\
 	break;						\
       default:						\
Index: /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_data.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_data.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_data.c	(revision 38329)
@@ -3,19 +3,47 @@
 # include <zlib.h>
 
-int gfits_compress_data (char *zdata, int *Nzdata, char *cmptype, char **optname, char **optvalue, int Nopt, char *rawdata, int Nraw, int raw_pixsize) {
+/* functions defined in ricecomp.c */
+int fits_rcomp(int a[], int nx,	unsigned char *c, int clen, int nblock);
+int fits_rdecomp (unsigned char *c, int clen, unsigned int array[], int nx, int nblock);
+int fits_rdecomp_short (unsigned char *c, int clen, unsigned short array[], int nx, int nblock);
+int fits_rdecomp_byte (unsigned char *c, int clen, unsigned char array[], int nx, int nblock);
+
+/* functions defined in fits_hcompress.c */
+# define LONGLONG long long
+int fits_hcompress(int *a, int ny, int nx, int scale, char *output, long *nbytes, int *status);
+int fits_hcompress64(LONGLONG *a, int ny, int nx, int scale, char *output, long *nbytes, int *status);
+
+/* functions defined in fits_hdeccompress.c */
+int fits_hdecompress(unsigned char *input, int smooth, int *a, int *ny, int *nx, int *scale, int *status);
+int fits_hdecompress64(unsigned char *input, int smooth, LONGLONG *a, int *ny, int *nx, int *scale, int *status);
+
+/* functions defined in pliocomp.c */
+int pl_p2li (int *pxsrc, int xs, short *lldst, int npix);
+int pl_l2pi (short *ll_src, int xs, int *px_dst, int npix);
+
+/* functions defined in gzip.c */
+int gfits_gz_stripheader (unsigned char *data, int *ndata);
+int gfits_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
+int gfits_compress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
+
+static int pass = 0;
+
+int gfits_compress_data (char *zdata, int *Nzdata, char *cmptype, 
+			 char **optname, char **optvalue, int Nopt, 
+			 char *rawdata, int Nrawpix, int rawpix_size) {
 
   int status;
-  static int Ninsum = 0;
-  static int Noutsum = 0;
 
   if (!strcasecmp(cmptype, "GZIP_1")) {
-    unsigned long tNraw = Nraw * out_pixsize;
+    unsigned long Nbytes = Nrawpix * rawpix_size;
 
     // the data must be byteswapped before compression begins
-    if (!gfits_byteswap_zdata (rawdata, Nraw, raw_pixsize)) return (FALSE);
+    // if (!gfits_byteswap_zdata (rawdata, Nrawpix, rawpix_size)) return (FALSE);
 
     // Nzdata is the size of the allocated buffer before the function is called, returns the actual size
-    // tNraw is the number of bytes in the raw data buffer
-    status = gfits_compress ((Bytef *) zdata, &Nzdata, (Bytef *) rawdata, tNraw);
+    // Nbytes is the number of bytes in the raw data buffer
+    uLongf destLen = *Nzdata;
+    status = gfits_compress ((Bytef *) zdata, &destLen, (Bytef *) rawdata, Nbytes);
+    *Nzdata = destLen;
     if (status != Z_OK) {
       fprintf (stderr, "error in compress (GZIP)\n");
@@ -23,4 +51,36 @@
     }
 
+    // test of deflate (vs I/O)
+    { 
+      char *srcbuf, *tgtbuf;
+      ALLOCATE (srcbuf, char, destLen);
+      memcpy (srcbuf, zdata, destLen);
+
+      ALLOCATE (tgtbuf, char, Nbytes);
+      
+      uLongf Ndeflate = Nbytes;
+      status = gfits_uncompress ((Bytef *) tgtbuf, &Ndeflate, (Bytef *) zdata, destLen);
+      if (status != Z_OK) {
+	fprintf (stderr, "error in uncompress (GZIP) : %d vs %d\n", status, Z_OK);
+	return (FALSE);
+      }
+      
+      myAssert (Ndeflate == Nbytes, "invalid output size?");
+
+      int i; 
+      for (i = 0; i < Ndeflate; i++) {
+	myAssert (rawdata[i] == tgtbuf[i], "data mismatch?");
+      }
+
+    }
+
+    if (pass == 0) {
+      int i;
+      for (i = 0; i < 32; i++) {
+	fprintf (stderr, "0x%02hhx ", zdata[i]);
+      }
+      fprintf (stderr, "\n");
+      pass = 1;
+    }
     return (TRUE);
   }
Index: /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_utils.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_utils.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_compress_utils.c	(revision 38329)
@@ -49,4 +49,5 @@
     otile[i] = 0;
   }
+  return TRUE;
 }
 
Index: /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_matrix.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_matrix.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_matrix.c	(revision 38329)
@@ -22,4 +22,19 @@
     size = FT_RECORD_SIZE * Nrec;
   }
+
+  return (size);
+}
+
+off_t gfits_heap_start (Header *header) {
+  
+  int i;
+  off_t size;
+
+  if (header[0].Naxes == 0) return (0);
+
+  size = abs(header[0].bitpix / 8);
+
+  for (i = 0; i < header[0].Naxes; i++)
+    size *= header[0].Naxis[i];
 
   return (size);
Index: /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_uncompress_M.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_uncompress_M.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_uncompress_M.c	(revision 38329)
@@ -4,4 +4,5 @@
 
 # define ESCAPE { \
+  fprintf (stderr, "error in %s @ line %d\n", __func__, __LINE__); \
   if (ztile != NULL) free (ztile); \
   if (optname != NULL) { \
Index: /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_uncompress_data.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_uncompress_data.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/matrix/F_uncompress_data.c	(revision 38329)
@@ -26,4 +26,6 @@
 int gfits_uncompress (Bytef *dest, uLongf *destLen, const Bytef *source, uLong sourceLen);
 
+static int pass = 0;
+
 int gfits_uncompress_data (char *zdata, int Nzdata, char *cmptype, char **optname, char **optvalue, int Nopt, char *outdata, int *Nout, int out_pixsize) {
 
@@ -36,7 +38,18 @@
 
     // for GZIP data, I need to check for and remove the header on the first block:
-    gfits_gz_stripheader ((unsigned char *)zdata, &Nzdata);
+    // XXX maybe not anymore
+    // gfits_gz_stripheader ((unsigned char *)zdata, &Nzdata);
+
+    if (pass == 0) {
+      int i;
+      for (i = 0; i < 32; i++) {
+	fprintf (stderr, "0x%02hhx ", zdata[i]);
+      }
+      fprintf (stderr, "\n");
+      pass = 1;
+    }
 
     // uncompress does not require us to know the expected number of pixel; it tells us the number
+    // XXX shouldn't we validate the result : we think we know the size
     status = gfits_uncompress ((Bytef *) outdata, &tNout, (Bytef *) zdata, Nzdata);
     if (status != Z_OK) {
@@ -47,5 +60,5 @@
 
     // the resulting uncompressed data is byteswapped
-    if (!gfits_byteswap_zdata (outdata, *Nout, out_pixsize)) return (FALSE);
+    // if (!gfits_byteswap_zdata (outdata, *Nout, out_pixsize)) return (FALSE);
 
     return (TRUE);
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_compress_T.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_compress_T.c	(revision 38329)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_compress_T.c	(revision 38329)
@@ -0,0 +1,195 @@
+# include <ohana.h>
+# include <gfitsio.h>
+# include <zlib.h>
+
+// the user needs to specify the various compression options:
+// ztilelen (may be 0)
+// zcmptype 
+
+// steps to convert an image to a compressed table:
+// * determine the number of tiles (from ztile[] and image size)
+// * construct an empty table with the right dimensions (1 column, Ntile rows)
+// * loop over tiles
+// * extract tile data to a buffer
+// * compress the buffer data
+// * insert in table heap
+// * update header keywords
+
+// we do not try to support compression of an image with an associated table (not valid)
+
+# define ESCAPE(A) { fprintf (stderr, "error in %s @ line %d\n", __func__, __LINE__); goto escape; }
+
+int gfits_collect_table_data (FTable *table, char *raw, int col, int row_start, int Nrows, int rowsize);
+
+int gfits_compress_table (FTable *srctable, FTable *tgttable, int ztilelen, char *zcmptype) {
+
+  int i, j;
+
+  char keyword[81];
+
+  char *raw = NULL;
+  char *zdata = NULL;
+
+  Header *srcheader = srctable->header;
+  Header *tgtheader = tgttable->header;
+
+  int Ntile, ztilelast;
+  if (srcheader->Naxis[1] % ztilelen) {
+    Ntile = srcheader->Naxis[1] / ztilelen + 1;
+    ztilelast = srcheader->Naxis[1] % ztilelen;
+  } else {
+    Ntile = srcheader->Naxis[1] / ztilelen;
+    ztilelast = ztilelen;
+  }
+
+  // EXTNAME is not mandatory, but I need to keep it
+  char extname[80];
+  if (!gfits_scan (srcheader, "EXTNAME", "%s", 1, extname)) {
+    strcpy (extname, "COMPRESSED_TABLE");
+  }
+
+  // creates an empty (Naxes = 2, Naxis[i] = 0) table header with XTENSION = BINTABLE, EXTNAME = COMPRESSED_TABLE
+  if (!gfits_create_table_header (tgtheader, "BINTABLE", extname)) ESCAPE(A);
+
+  int Nfields;
+  if (!gfits_scan (srcheader, "TFIELDS", "%d", 1, &Nfields)) ESCAPE(A);
+
+  TableField *fields = NULL;
+  ALLOCATE (fields, TableField, Nfields);
+  for (i = 0; i < Nfields; i++) {
+    snprintf (keyword, 80, "TTYPE%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].ttype)) ESCAPE(A);
+    if (!gfits_scan_alt (srcheader, keyword, "%C", 1, fields[i].ttype_cmt)) ESCAPE(A);
+
+    // TUNIT is not mandatory
+    snprintf (keyword, 80, "TUNIT%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].tunit)) {
+      fields[i].tunit[0] = 0;
+    } else {
+      if (!gfits_scan_alt (srcheader, keyword, "%C", 1, fields[i].tunit_cmt)) ESCAPE(A);
+    }
+    
+    snprintf (keyword, 80, "TFORM%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].tformat)) ESCAPE(A);
+    if (!gfits_scan_alt (srcheader, keyword, "%C", 1, fields[i].tformat_cmt)) ESCAPE(A);
+
+    // XXX this should depend on the field type, but for now just use a single type (GZIP_1)
+    strcpy (fields[i].zctype, zcmptype);
+
+    // by using "P" format, we are limited to 32bit pointers (2GB heap)
+    if (!gfits_define_bintable_column (tgtheader, "1QB(0)", fields[i].ttype, fields[i].ttype_cmt, fields[i].tunit, 1.0, 0.0)) ESCAPE (A);
+  }    
+
+  // allocates the default data array (tgttable->buffer)
+  if (!gfits_create_table (tgtheader, tgttable)) ESCAPE (A);
+
+  // copy original header to output header (XXX this needs to be finished)
+  if (!gfits_copy_keywords_compress (srcheader, tgtheader)) ESCAPE (A);
+  
+  // this allocates the pointer data array for the full set of tiles (NOT the heap)
+  char *tmpbuffer = NULL;
+  ALLOCATE_ZERO (tmpbuffer, char, 16*Ntile); // need space for Ntile entries, each of width 16 bytes (2 long)
+  for (i = 0; i < Nfields; i++) {
+    if (!gfits_set_bintable_column (tgtheader, tgttable, fields[i].ttype, tmpbuffer, Ntile)) ESCAPE (A);
+  }
+  free (tmpbuffer);
+    
+  // add ZIMAGE from output header
+  if (!gfits_modify_alt (tgtheader, "ZTABLE", "%t", 1, TRUE)) ESCAPE (A);
+
+  // define compression-specific keywords, update header as needed.
+  if (!gfits_modify (tgtheader, "ZTILELEN", "%d", 1, ztilelen)) ESCAPE(A);
+
+  if (!gfits_modify (tgtheader, "ZNAXIS1", OFF_T_FMT, 1, srcheader->Naxis[0])) ESCAPE (A);
+  if (!gfits_modify (tgtheader, "ZNAXIS2", OFF_T_FMT, 1, srcheader->Naxis[1])) ESCAPE (A);
+
+  off_t pcount;
+  if (!gfits_scan (srcheader, "PCOUNT", OFF_T_FMT, 1, &pcount)) ESCAPE (A);
+  if (!gfits_modify (tgtheader, "ZPCOUNT", OFF_T_FMT, 1, pcount)) ESCAPE (A);
+
+  off_t theap;
+  if (gfits_scan (srcheader, "THEAP", OFF_T_FMT, 1, &theap)) {
+    if (!gfits_modify (tgtheader, "ZTHEAP", OFF_T_FMT, 1, theap)) ESCAPE (A);
+  }
+  
+  int max_width = 0;
+  int offset = 0; // bytes from first column of first field to the current field (accumulate to set)
+
+  for (i = 0; i < Nfields; i++) {
+    snprintf (keyword, 81, "ZFORM%d", i+1);
+    if (!gfits_modify (tgtheader, keyword, "%s", 1, fields[i].tformat)) ESCAPE (A);
+    if (!gfits_varlength_column_define (tgttable, &fields[i].zdef, i+1)) ESCAPE(A);
+    if (!gfits_bintable_format (fields[i].tformat, fields[i].datatype, &fields[i].Nvalues, &fields[i].pixsize)) ESCAPE(A); // 
+    fields[i].rowsize = fields[i].Nvalues*fields[i].pixsize;
+    max_width = MAX(max_width, fields[i].rowsize);
+
+    // compression type per column (XXX for now we are just using zcmptype, as set above)
+    snprintf (keyword, 81, "ZCTYP%d", i+1);
+    if (!gfits_modify (tgtheader, keyword, "%s", 1, fields[i].zctype)) ESCAPE (A);
+
+    fields[i].offset = offset;
+    offset += fields[i].offset;
+  }
+
+  // allocate the intermediate storage buffers
+  ALLOCATE (raw,   char, max_width*ztilelen);
+  ALLOCATE (zdata, char, max_width*ztilelen);
+
+  // compress the data : copy into a tile, compress the tile, then add to the output table
+  // each tile -> 1 row of the output table
+  for (i = 0; i < Ntile; i++) {
+
+    for (j = 0; j < Nfields; j++) {
+
+      int Nrows = (i == Ntile - 1) ? ztilelast : ztilelen;
+      int row_start = i*ztilelen; 
+      // ^- first row for this tile & field
+      // NOTE: assumes each tile has the same length, ex the last (true for now)
+
+      // copy the raw pixels from their native matrix locations to the temporary output buffer
+      if (!gfits_collect_table_data (srctable, raw, fields[j].offset, row_start, Nrows, fields[j].rowsize)) ESCAPE(A);
+      
+      // optname, optvalue = NULL, Noptions = 0
+      
+      int Nraw = Nrows*fields[j].Nvalues; // number of pixels
+      int Nzdata = max_width*ztilelen; // available space, replaced with actual output size on compression
+      if (!gfits_compress_data (zdata, &Nzdata, fields[j].zctype, NULL, NULL, 0, raw, Nraw, fields[j].pixsize)) ESCAPE(A);
+      
+      if (!gfits_varlength_column_add_data (tgttable, zdata, Nzdata, i, &fields[j].zdef)) ESCAPE(A);
+      
+      // XXX need to activate
+      // if (FALSE) gfits_byteswap_zdata (zdata, Nzdata, zdata_pixsize) ESCAPE(A);
+    }
+  }
+
+  for (i = 0; i < Nfields; i++) {
+    if (!gfits_varlength_column_finish (tgttable, &fields[i].zdef)) ESCAPE(A);
+  }
+
+  free (raw);
+  free (zdata);
+  return (TRUE);
+
+escape:
+  FREE (raw);
+  FREE (zdata);
+  return FALSE;
+}
+
+// raw_pixsize is the bytes / pixel for the input matrix
+// place the raw image bytes for the current tile into the tile buffer
+int gfits_collect_table_data (FTable *table, char *raw, int col, int row_start, int Nrows, int rowsize) {
+
+  off_t i;
+
+  // we are copying NN rows of the column which starts at XX and has MM bytes per row
+
+  off_t Nx = table->header->Naxis[0];
+
+  for (i = 0; i < Nrows; i++) {
+    int row = row_start + i;
+    memcpy (&raw[i*rowsize], &table->buffer[Nx*row + col], rowsize);
+  }
+
+  return (TRUE);
+}
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_copy_T.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_copy_T.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_copy_T.c	(revision 38329)
@@ -6,6 +6,7 @@
 
   /* find buffer size */
-  out[0].validsize = in[0].validsize;
-  out[0].datasize  = in[0].datasize;
+  out[0].validsize  = in[0].validsize;
+  out[0].datasize   = in[0].datasize;
+  out[0].heap_start = in[0].heap_start;
 
   ALLOCATE (out[0].buffer, char, out[0].datasize);
@@ -28,7 +29,8 @@
 
   /* find buffer size */
-  out[0].datasize = in[0].datasize;
-  out[0].pad      = in[0].pad;
-  out[0].Nrow     = in[0].Nrow;
+  out[0].datasize   = in[0].datasize;
+  // out[0].heap_start = in[0].heap_start;
+  out[0].pad        = in[0].pad;
+  out[0].Nrow       = in[0].Nrow;
 
   off_t Nrows = out[0].Nrow;
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_create_T.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_create_T.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_create_T.c	(revision 38329)
@@ -4,8 +4,9 @@
 /*********************** fits init table *******************************/
 int gfits_init_table (FTable *table) {
-  table[0].header = NULL;
-  table[0].buffer = NULL;
-  table[0].datasize = 0;
-  table[0].validsize = 0;
+  table[0].header     = NULL;
+  table[0].buffer     = NULL;
+  table[0].datasize   = 0;
+  table[0].heap_start = 0;
+  table[0].validsize  = 0;
   return (TRUE);
 
@@ -42,6 +43,21 @@
   }
   table[0].datasize = Nbytes;
+  table[0].heap_start = gfits_heap_start (header);
   return (TRUE);
 
+}
+
+/*********************** fits create table *******************************/
+int gfits_set_table_rows (Header *header, FTable *table, off_t Nrows) {
+
+    header[0].Naxis[1] = Nrows;
+    gfits_modify (header, "NAXIS2", OFF_T_FMT, 1,  Nrows);
+
+    off_t Nbytes = gfits_data_size (header);
+    REALLOCATE (table[0].buffer, char, Nbytes);
+    bzero (table[0].buffer, Nbytes);
+    table[0].datasize = Nbytes;
+    table[0].heap_start = gfits_heap_start (header);
+  return (TRUE);
 }
 
@@ -60,4 +76,5 @@
   Ny = table[0].header[0].Naxis[0];
   table[0].datasize = gfits_data_size (header);
+  // table[0].heap_start = gfits_heap_start (header);
   table[0].pad = table[0].datasize - Nx*Ny;
  
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_define_column.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_define_column.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_define_column.c	(revision 38329)
@@ -66,7 +66,11 @@
   sprintf (field, "TTYPE%d", Nfields);
   gfits_modify (header, field, "%s", 1, label);
-  gfits_modify_alt (header, field, "%C", 1, comment);
-  sprintf (field, "TUNIT%d", Nfields);
-  gfits_modify (header, field, "%s", 1, unit);
+  if (comment) {
+    gfits_modify_alt (header, field, "%C", 1, comment);
+  }
+  if (unit) {
+    sprintf (field, "TUNIT%d", Nfields);
+    gfits_modify (header, field, "%s", 1, unit);
+  }
   sprintf (field, "TFORM%d", Nfields);
   gfits_modify (header, field, "%s", 1, format);
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_read_T.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_read_T.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_read_T.c	(revision 38329)
@@ -45,19 +45,17 @@
     if (Nread < gfits_data_min_size (table[0].header)) {
       fprintf (stderr, "error: fits read error in %s, read "OFF_T_FMT", need "OFF_T_FMT"\n", __func__,  Nread,  gfits_data_min_size (table[0].header));
-      if (padIfShort) {
-	memset (&table[0].buffer[Nread], 0, Nbytes - Nread);
-	fprintf (stderr, "warning: file missing data, padding with zeros: USE AT YOUR OWN RISK!\n");
-	table[0].validsize = Nread;
-	table[0].datasize = Nbytes;
-	return (TRUE);
-      } else {
-	gfits_free_table  (table);
+      if (!padIfShort) {
+	gfits_free_table (table);
 	return (FALSE);
       }
-    }
-    fprintf (stderr, "warning: file missing pad\n");
+      memset (&table[0].buffer[Nread], 0, Nbytes - Nread);
+      fprintf (stderr, "warning: file missing data, padding with zeros: USE AT YOUR OWN RISK!\n");
+    } else {
+      fprintf (stderr, "warning: file missing pad\n");
+    }
   }
   table[0].validsize = Nread;
   table[0].datasize = Nbytes;
+  table[0].heap_start = gfits_heap_start (table->header);
   return (TRUE);
 }	
@@ -93,13 +91,10 @@
     } 
     fprintf (stderr, "error: fits read error in %s, read "OFF_T_FMT", need "OFF_T_FMT"\n", __func__,  Nread,  Nbytes);
-    if (padIfShort) {
-      memset (&table[0].buffer[Nread], 0, Nbytes - Nread);
-      fprintf (stderr, "warning: file missing data, padding with zeros: USE AT YOUR OWN RISK!\n");
-      table[0].validsize = Nread;
-      table[0].datasize = Nbytes;
-    } else {
+    if (!padIfShort) {
       free (table[0].buffer);
       return (FALSE);
     }
+    memset (&table[0].buffer[Nread], 0, Nbytes - Nread);
+    fprintf (stderr, "warning: file missing data, padding with zeros: USE AT YOUR OWN RISK!\n");
   }
 
@@ -107,5 +102,7 @@
   table[0].header[0].Naxis[1] = Nrows;
   gfits_modify (table[0].header, "NAXIS2",  OFF_T_FMT, 1,  Nrows);
-  table[0].datasize = gfits_data_size (table[0].header);
+  table[0].validsize = Nread;
+  table[0].datasize = Nbytes;
+  table[0].heap_start = gfits_heap_start (table->header);
 
   return (TRUE);
@@ -122,4 +119,5 @@
   Ny = table[0].header[0].Naxis[1];
   table[0].datasize = gfits_data_size (table[0].header);
+  // table[0].heap_start = gfits_heap_start (table[0].header);
   table[0].pad = table[0].datasize - Nx*Ny;
 
@@ -206,4 +204,5 @@
     for (i = 0; i < Nrow; i++) table[0].row[i] = row[i];
     table[0].datasize = gfits_data_size (table[0].header);
+    // table[0].heap_start = gfits_heap_start (table[0].header);
     table[0].pad      = table[0].datasize - Nx*Ny;
     return (TRUE);
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_set_column.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_set_column.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_set_column.c	(revision 38329)
@@ -18,5 +18,5 @@
 int gfits_set_bintable_column (Header *header, FTable *table, char *label, void *data, off_t Nrow) {
 
-  off_t Nx, Ny, nbytes;
+  off_t Nx, Ny;
   int i, N, Nfields;
   int Nval, Nbytes, Nstart, Nv, Nb;
@@ -55,13 +55,9 @@
   gfits_scan (header, "NAXIS1", OFF_T_FMT, 1,  &Nx);
   gfits_scan (header, "NAXIS2", OFF_T_FMT, 1,  &Ny);
+
+  // if no rows have yet been assigned, we need to allocate the full data buffer
   if (Ny == 0) { 
     Ny = Nrow;
-    header[0].Naxis[1] = Ny;
-    gfits_modify (header, "NAXIS2", OFF_T_FMT, 1,  Ny);
-
-    nbytes = gfits_data_size (header);
-    REALLOCATE (table[0].buffer, char, MAX (nbytes, 1));
-    bzero (table[0].buffer, nbytes);
-    table[0].datasize = nbytes;
+    gfits_set_table_rows (header, table, Ny);
   }
   if (Ny != Nrow) return (FALSE);
@@ -181,5 +177,5 @@
 int gfits_set_bintable_column_reformat (Header *header, FTable *table, char *label, char *intype, void *data, off_t Nrow) {
 
-  off_t Nx, Ny, nbytes;
+  off_t Nx, Ny;
   int i, N, Nfields;
   int Nval, NbytesOut, Nstart, Nv, Nb;
@@ -220,11 +216,5 @@
   if (Ny == 0) { 
     Ny = Nrow;
-    header[0].Naxis[1] = Ny;
-    gfits_modify (header, "NAXIS2", OFF_T_FMT, 1,  Ny);
-
-    nbytes = gfits_data_size (header);
-    REALLOCATE (table[0].buffer, char, MAX (nbytes, 1));
-    bzero (table[0].buffer, nbytes);
-    table[0].datasize = nbytes;
+    gfits_set_table_rows (header, table, Ny);
   }
   if (Ny != Nrow) return (FALSE);
@@ -701,5 +691,5 @@
 int gfits_set_table_column (Header *header, FTable *table, char *label, void *data, off_t Nrow) {
 
-  off_t Nx, Ny, nbytes;
+  off_t Nx, Ny;
   int i, N, Nfields, Nval, Nbytes, Nstart, Nv, Nb;
   char tlabel[80], field[80], format[80], cformat[80], type[16], tmp[16];
@@ -731,11 +721,5 @@
   if (Ny == 0) { 
     Ny = Nrow;
-    header[0].Naxis[1] = Ny;
-    gfits_modify (header, "NAXIS2", OFF_T_FMT, 1,  Ny);
-
-    nbytes = gfits_data_size (header);
-    REALLOCATE (table[0].buffer, char, MAX (nbytes, 1));
-    bzero (table[0].buffer, nbytes);
-    table[0].datasize = nbytes;
+    gfits_set_table_rows (header, table, Ny);
   }
   if (Ny != Nrow) return (FALSE);
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_format.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_format.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_format.c	(revision 38329)
@@ -8,13 +8,12 @@
 int gfits_bintable_format (char *format, char *type, int *Nval, int *Nbytes) {
 
-  char *Lchar, *Fchar;
-  int Nv;
-
-  if (format == (char *) NULL) return (FALSE);
-  if (format[0] == 0) return (FALSE);
-  Lchar = &format[strlen(format) - 1];
-
-  Nv = strtol (format, &Fchar, 10);
-  if (Fchar != Lchar) return (FALSE);
+  char *Fchar;
+
+  if (format == (char *) NULL) return (FALSE); // format must be defined
+  if (format[0] == 0) return (FALSE);	       // format must not be empty string
+  // char *Lchar = &format[strlen(format) - 1];	       // last-char pointer
+
+  int Nv = strtol (format, &Fchar, 10);            // Fchar points at end of leading number
+  // if (Fchar != Lchar) return (FALSE);       -- this test is invalid for eg 1PB(nn)
   if ((Nv == 0) && (Fchar == format)) Nv = 1;
 
@@ -51,4 +50,10 @@
     { *Nbytes = 8;  strcpy (type, "double"); *Nval = Nv;               }
     break;
+  case  'C':
+    { *Nbytes = 8;  strcpy (type, "float");  *Nval = 2*Nv;             }
+    break;
+  case  'M':
+    { *Nbytes = 16; strcpy (type, "double"); *Nval = 2*Nv;             }
+    break;
   case  'P':
     { *Nbytes = 4;  strcpy (type, "var");    *Nval = 2*Nv;             }
@@ -56,10 +61,4 @@
   case  'Q':
     { *Nbytes = 8;  strcpy (type, "var64"); *Nval = 2*Nv;             }
-    break;
-  case  'C':
-    { *Nbytes = 8;  strcpy (type, "float");  *Nval = 2*Nv;             }
-    break;
-  case  'M':
-    { *Nbytes = 16; strcpy (type, "double"); *Nval = 2*Nv;             }
     break;
   default:
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_row.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_row.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_row.c	(revision 38329)
@@ -28,4 +28,5 @@
   REALLOCATE (table[0].buffer, char, MAX (nbytes, 1));
   table[0].datasize = nbytes;
+  table[0].heap_start = gfits_heap_start (header);
   
   memcpy (&table[0].buffer[Nstart], data, Nbytes*Nrow);
@@ -67,4 +68,5 @@
 
   table[0].datasize = gfits_data_size (table[0].header);
+  // table[0].heap_start = gfits_heap_start (header);
   table[0].pad      = table[0].datasize - Nx*Ny;
 
@@ -102,4 +104,5 @@
   REALLOCATE (table[0].buffer, char, MAX (nbytes, 1));
   table[0].datasize = nbytes;
+  table[0].heap_start = gfits_heap_start (header);
   return (TRUE);
 }
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_varlength.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_varlength.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_table_varlength.c	(revision 38329)
@@ -15,4 +15,6 @@
   snprintf (field, 80, "TFORM%d", column);
   if (!gfits_scan (ftable->header, field, "%s", 1, format)) return (FALSE);
+
+  def->column = column;
 
   // find and remove the max field length element
@@ -49,4 +51,5 @@
   if (*p1 == 'I') { def->nbytes = 2;  def->format = *p1; }
   if (*p1 == 'J') { def->nbytes = 4;  def->format = *p1; }
+  if (*p1 == 'K') { def->nbytes = 8;  def->format = *p1; }
   if (*p1 == 'E') { def->nbytes = 4;  def->format = *p1; }
   if (*p1 == 'D') { def->nbytes = 8;  def->format = *p1; }
@@ -55,18 +58,58 @@
   if (!def->nbytes) { return (FALSE); }
   
-  /* scan columns to find column offset */
-  def->Nstart = 0;
+  /* scan columns to find column offset for metadata column*/
+  def->offset = 0;
   for (i = 1; i < column; i++) {
     sprintf (field, "TFORM%d", i);
     gfits_scan (ftable->header, field, "%s", 1, format);
     gfits_bintable_format (format, tmpline, &Nv, &Nb);
-    def->Nstart += Nv*Nb;
+    def->offset += Nv*Nb;
   }
 
   // heap_start must be long long so file may be very large
-  if (!gfits_scan (ftable->header, "THEAP", OFF_T_FMT, 1,  &def->heap_start)) {
-    def->heap_start = ftable->header->Naxis[0]*ftable->header->Naxis[1];
-  }
-
+  // confirm that ftable->heap_start is correctly set?
+
+  return TRUE;
+}
+
+# define SWAP_WORD \
+  tmp = pchar[0]; pchar[0] = pchar[3]; pchar[3] = tmp; \
+  tmp = pchar[1]; pchar[1] = pchar[2]; pchar[2] = tmp;
+
+# define SWAP_DBLE \
+  tmp = pchar[0]; pchar[0] = pchar[7]; pchar[7] = tmp; \
+  tmp = pchar[1]; pchar[1] = pchar[6]; pchar[6] = tmp; \
+  tmp = pchar[2]; pchar[2] = pchar[5]; pchar[5] = tmp; \
+  tmp = pchar[3]; pchar[3] = pchar[4]; pchar[4] = tmp;
+
+int gfits_byteswap_varlength_column (FTable *ftable, int column) {
+
+# ifdef BYTE_SWAP  
+  VarLengthColumn zdef;
+  if (!gfits_varlength_column_define (ftable, &zdef, column)) return FALSE;
+
+  char *bufstart = &ftable->buffer[zdef.offset];
+
+  int i;
+  char *pchar, tmp;
+
+  off_t Nx = ftable->header->Naxis[0];
+
+  for (i = 0; i < ftable->header->Naxis[1]; i++) {
+    if (zdef.mode == 'P') {
+      pchar = &bufstart[i*Nx];
+      SWAP_WORD;
+      pchar = &bufstart[i*Nx + 4];
+      SWAP_WORD;
+    }      
+    if (zdef.mode == 'Q') {
+      char *pchar, tmp;
+      pchar = &bufstart[i*Nx];
+      SWAP_DBLE;
+      pchar = &bufstart[i*Nx + 8];
+      SWAP_DBLE;
+    }
+  }
+# endif
   return TRUE;
 }
@@ -85,13 +128,9 @@
   Nx = ftable->header->Naxis[0];
 
-# define SWAP_WORD \
-  tmp = pchar[0]; pchar[0] = pchar[3]; pchar[3] = tmp; \
-  tmp = pchar[1]; pchar[1] = pchar[2]; pchar[2] = tmp;
-
 # ifdef BYTE_SWAP
   char *pchar, tmp;
-  pchar = &ftable->buffer[row*Nx + column->Nstart];
+  pchar = &ftable->buffer[row*Nx + column->offset];
   SWAP_WORD;
-  pchar = &ftable->buffer[row*Nx + column->Nstart + 4];
+  pchar = &ftable->buffer[row*Nx + column->offset + 4];
   SWAP_WORD;
 # endif
@@ -99,5 +138,5 @@
   if (column->mode == 'P') {
     int *ptr;
-    ptr = (int *) &ftable->buffer[row*Nx + column->Nstart];
+    ptr = (int *) &ftable->buffer[row*Nx + column->offset];
     *length = ptr[0];
     offset = ptr[1];
@@ -105,10 +144,10 @@
   if (column->mode == 'Q') {
     off_t *ptr;
-    ptr = (off_t *) &ftable->buffer[row*Nx + column->Nstart];
+    ptr = (off_t *) &ftable->buffer[row*Nx + column->offset];
     *length = ptr[0];
     offset = ptr[1];
   }
 
-  result = (void *) (ftable->buffer + column->heap_start + offset);
+  result = (void *) (ftable->buffer + ftable->heap_start + offset);
   return result;
 }
@@ -121,11 +160,8 @@
 // swap before writing out
 
-// Here are operations we need to do:
-
 int gfits_varlength_column_add_data (FTable *table, char *data, off_t Ndata, int row, VarLengthColumn *column) {
 
   // find the current starting point for new data (end of current buffer main data + current heap
   off_t heap_offset = gfits_data_min_size (table->header);
-  char *heap_ptr = ftable->buffer + heap_offset;
 
   // extend the buffer size to add the new data
@@ -133,4 +169,6 @@
   REALLOCATE (table->buffer, char, Nbytes);
 
+  char *heap_ptr = table->buffer + heap_offset;
+
   // add the new data to the table buffer
   memcpy (heap_ptr, data, Ndata);
@@ -142,29 +180,55 @@
   // find the cell for the specified row & column
   // the values in the main table for this row and varlength column:
-  Nx = ftable->header->Naxis[0];
+  int Nx = table->header->Naxis[0];
 
   // set the cell values
   if (column->mode == 'P') {
     int *ptr;
-    ptr = (int *) &ftable->buffer[row*Nx + column->Nstart];
+    ptr = (int *) &table->buffer[row*Nx + column->offset];
     ptr[0] = Ndata;
-    ptr[1] = heap_offset;
+    ptr[1] = heap_offset - table->heap_start;
   } 
   if (column->mode == 'Q') {
     off_t *ptr;
-    ptr = (off_t *) &ftable->buffer[row*Nx + column->Nstart];
+    ptr = (off_t *) &table->buffer[row*Nx + column->offset];
     ptr[0] = Ndata;
-    ptr[1] = heap_offset;
+    ptr[1] = heap_offset - table->heap_start;
   }
 
   // update maxlen
+  // fprintf (stderr, "row: %d, Ndata: %d, maxlen: %d\n", (int) row, (int) Ndata, (int) column->maxlen);
   column->maxlen = MAX (column->maxlen, Ndata);
 
   off_t pcount;
-  gfits_scan (ftable->header, "PCOUNT", OFF_T_FMT, 1, &pcount);
+  gfits_scan (table->header, "PCOUNT", OFF_T_FMT, 1, &pcount);
 
   pcount += Ndata;
-  gfits_modify (header, "PCOUNT", OFF_T_FMT, 1, pcount);
-
-  return TRUE;
-}
+  gfits_modify (table->header, "PCOUNT", OFF_T_FMT, 1, pcount);
+  table->header->pcount = pcount;
+  table->datasize = gfits_data_size (table->header);
+
+  return TRUE;
+}
+
+// update the header TFORM value for this entry
+int gfits_varlength_column_finish (FTable *ftable, VarLengthColumn *def) {
+
+  char field[81];
+  char format[81];
+
+  // grab the value of TFORMn for this column
+  snprintf (field, 80, "TFORM%d", def->column);
+  if (!gfits_scan (ftable->header, field, "%s", 1, format)) return FALSE;
+
+  // find and update the max field length element
+  char *p1 = strchr (format, '(');
+  if (!p1) return (FALSE); // not a valid varlength column -- missing (e_max)
+  
+  p1 ++;
+  *p1 = 0;
+
+  snprintf (p1, 80 - (p1 - format), "%d)", def->maxlen);
+  if (!gfits_modify (ftable->header, field, "%s", 1, format)) return FALSE;
+
+  return TRUE;
+}
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_uncompress_T.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_uncompress_T.c	(revision 38329)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_uncompress_T.c	(revision 38329)
@@ -0,0 +1,164 @@
+# include <ohana.h>
+# include <gfitsio.h>
+# include <zlib.h>
+
+# define ESCAPE(A) { fprintf (stderr, "error in %s @ line %d\n", __func__, __LINE__); goto escape; }
+
+int gfits_distribute_table_data (FTable *table, char *raw, int col, int row_start, int Nrows, int rowsize);
+
+int gfits_uncompress_table (FTable *srctable, FTable *tgttable, char *zcmptype) {
+
+  int i;
+
+  char keyword[81];
+
+  char *raw = NULL;
+  char *zdata = NULL;
+
+  Header *srcheader = srctable->header;
+  Header *tgtheader = tgttable->header;
+
+  int ztilelen;
+  if (!gfits_scan (srcheader, "ZTILELEN", "%d", 1, &ztilelen)) ESCAPE(A);
+  // XXX if ZTILELEN is missing, it should have the value of ZNAXIS2
+
+  // EXTNAME is not mandatory, keep it if it exists:
+  char extname[80];
+  if (!gfits_scan (srcheader, "EXTNAME", "%s", 1, extname)) {
+    strcpy (extname, "UNCOMPRESSED_TABLE");
+  }
+
+  // creates an empty (Naxes = 2, Naxis[i] = 0) table header with XTENSION = BINTABLE, EXTNAME = COMPRESSED_TABLE
+  if (!gfits_create_table_header (tgtheader, "BINTABLE", extname)) ESCAPE(A);
+
+  int Nfields;
+  if (!gfits_scan (srcheader, "TFIELDS", "%d", 1, &Nfields)) ESCAPE(A);
+
+  // below we generate a fake table with tmpbuffers.  allocated it to the max needed size
+  int max_width = 0;
+  int offset = 0;
+
+  TableField *fields = NULL;
+  ALLOCATE (fields, TableField, Nfields);
+  for (i = 0; i < Nfields; i++) {
+    snprintf (keyword, 80, "TTYPE%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].ttype)) ESCAPE(A);
+    if (!gfits_scan_alt (srcheader, keyword, "%C", 1, fields[i].ttype_cmt)) ESCAPE(A);
+
+    // TUNIT is not mandatory
+    snprintf (keyword, 80, "TUNIT%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].tunit)) {
+      fields[i].tunit[0] = 0;
+    } else {
+      if (!gfits_scan_alt (srcheader, keyword, "%C", 1, fields[i].tunit_cmt)) ESCAPE(A);
+    }
+    
+    snprintf (keyword, 80, "ZFORM%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].tformat)) ESCAPE(A);
+    if (!gfits_scan_alt (srcheader, keyword, "%C", 1, fields[i].tformat_cmt)) ESCAPE(A);
+
+    snprintf (keyword, 80, "ZCTYP%d", i+1);
+    if (!gfits_scan (srcheader, keyword, "%s", 1, fields[i].zctype)) {
+      strcpy (fields[i].zctype, "GZIP_2"); // XXX NOTE: not yet supported
+    }
+
+    if (!gfits_bintable_format (fields[i].tformat, fields[i].datatype, &fields[i].Nvalues, &fields[i].pixsize)) ESCAPE(A);
+    fields[i].rowsize = fields[i].Nvalues*fields[i].pixsize;
+    max_width = MAX(max_width, fields[i].rowsize);
+
+    fields[i].offset = offset;
+    offset += fields[i].offset;
+
+    if (!gfits_varlength_column_define (srctable, &fields[i].zdef, i + 1)) ESCAPE(A);
+
+    if (!gfits_define_bintable_column (tgtheader, fields[i].tformat, fields[i].ttype, fields[i].ttype_cmt, fields[i].tunit, 1.0, 0.0)) ESCAPE (A);
+  }    
+
+  // allocates the default data array (tgttable->buffer)
+  if (!gfits_create_table (tgtheader, tgttable)) ESCAPE (A);
+
+  // copy original header to output header (XXX this needs to be finished)
+  if (!gfits_copy_keywords_compress (srcheader, tgtheader)) ESCAPE (A);
+  
+  off_t Nx, Ny;
+  if (!gfits_scan (srcheader, "ZNAXIS1", OFF_T_FMT, 1, &Nx)) ESCAPE (A);
+  if (!gfits_scan (srcheader, "ZNAXIS2", OFF_T_FMT, 1, &Ny)) ESCAPE (A);
+  myAssert (Nx == tgtheader->Naxis[0], "table definition error?");
+
+  // this allocates the pointer data array for the full set of tiles (NOT the heap)
+  char *tmpbuffer = NULL;
+  ALLOCATE_ZERO (tmpbuffer, char, max_width*Ny);
+  for (i = 0; i < Nfields; i++) {
+    if (!gfits_set_bintable_column (tgtheader, tgttable, fields[i].ttype, tmpbuffer, Ny)) ESCAPE (A);
+  }
+  free (tmpbuffer);
+    
+  int Ntile = srcheader->Naxis[1];
+  int ztilelast = (tgtheader->Naxis[1] % ztilelen) ? tgtheader->Naxis[1] % ztilelen : ztilelen;
+
+  // allocate the intermediate storage buffers
+  ALLOCATE (raw,   char, max_width*ztilelen);
+  ALLOCATE (zdata, char, max_width*ztilelen);
+
+  // uncompress the data : extract a tile's compressed data, uncompress the tile, insert into full table
+  // each tile -> 1 row of the output table
+  
+  off_t row;
+  for (row = 0; row < srcheader->Naxis[1]; row++) {
+
+    for (i = 0; i < Nfields; i++) {
+
+      // gfits_uncompress_data can take values specific to the compression mode
+      // optname, optvalue = NULL, Noptions = 0
+
+      // XXX note that this function currently byteswaps.  I should redo the code to make
+      // byteswap of the varlength data segment a separate function
+
+      off_t Nzdata;
+      char *zdata = gfits_varlength_column_pointer (srctable, &fields[i].zdef, row, &Nzdata);
+      if (!zdata) ESCAPE(A);
+    
+      int Nrows = (row == Ntile - 1) ? ztilelast : ztilelen;
+      int Nraw = Nrows*fields[i].Nvalues; // number of pixels
+
+      if (!gfits_uncompress_data (zdata, Nzdata, fields[i].zctype, NULL, NULL, 0, raw, &Nraw, fields[i].pixsize)) ESCAPE(A);
+
+      off_t row_start = row*ztilelen; 
+      // ^- first row for this tile & field
+      // NOTE: assumes each tile has the same length, ex the last (true for now)
+
+      // copy the raw pixels from their native matrix locations to the temporary output buffer
+      if (!gfits_distribute_table_data (tgttable, raw, fields[i].offset, row_start, Nrows, fields[i].rowsize)) ESCAPE(A);
+      
+      // XXX need to activate
+      // if (FALSE) gfits_byteswap_zdata (zdata, Nzdata, zdata_pixsize) ESCAPE(A);
+    }
+  }
+
+  free (raw);
+  free (zdata);
+  return (TRUE);
+
+escape:
+  FREE (raw);
+  FREE (zdata);
+  return FALSE;
+}
+
+// raw_pixsize is the bytes / pixel for the input matrix
+// place the raw image bytes for the current tile into the tile buffer
+int gfits_distribute_table_data (FTable *table, char *raw, int col, int row_start, int Nrows, int rowsize) {
+
+  off_t i;
+
+  // we are copying NN rows into the column which starts at XX and has MM bytes per row
+
+  off_t Nx = table->header->Naxis[0];
+
+  for (i = 0; i < Nrows; i++) {
+    int row = row_start + i;
+    memcpy (&table->buffer[Nx*row + col], &raw[i*rowsize], rowsize);
+  }
+
+  return (TRUE);
+}
Index: /branches/eam_branches/ohana.20150429/src/libfits/table/F_write_T.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/table/F_write_T.c	(revision 38328)
+++ /branches/eam_branches/ohana.20150429/src/libfits/table/F_write_T.c	(revision 38329)
@@ -84,4 +84,5 @@
   Nx = ftable[0].header[0].Naxis[0]; // final output table size on disk 
   ftable[0].datasize = gfits_data_size (ftable[0].header);
+  ftable[0].heap_start = gfits_heap_start (ftable[0].header);
 
   Nskip = start * Nx;
Index: /branches/eam_branches/ohana.20150429/src/libfits/test/compress.sh
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/test/compress.sh	(revision 38329)
+++ /branches/eam_branches/ohana.20150429/src/libfits/test/compress.sh	(revision 38329)
@@ -0,0 +1,22 @@
+
+macro go
+ mcreate z 500 500
+ set x = xramp(z)
+ wd x test.raw.fits -bitpix -32 -bzero 0 -bscale 1
+ wd x test.cmp.fits -bitpix -32 -bzero 0 -bscale 1 -compress
+ rd b test.cmp.fits -x 0
+ set d = x - b
+ stat d
+ exec funpack -S test.cmp.fits > test.fun.fits
+end
+
+macro ttest
+
+ create x 0 100
+ set y = x^2
+
+ create ID 1 101 -int
+ write -fits test test.raw.tbl x y ID
+
+ write -fits test test.cmp.tbl x y ID -compress
+end
Index: /branches/eam_branches/ohana.20150429/src/libfits/test/test.zlib.c
===================================================================
--- /branches/eam_branches/ohana.20150429/src/libfits/test/test.zlib.c	(revision 38329)
+++ /branches/eam_branches/ohana.20150429/src/libfits/test/test.zlib.c	(revision 38329)
@@ -0,0 +1,73 @@
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <assert.h>
+# include <zlib.h>
+
+# define NSRC 100
+# define NTGT 200
+
+int main (int argc, char **argv) {
+  
+  int i, err;
+  char srcbuf[NSRC], tgtbuf[NTGT], outbuf[NTGT];
+  
+  { 
+    z_stream zdn;
+    zdn.next_in = srcbuf;
+    zdn.avail_in = NSRC;
+    zdn.next_out = tgtbuf;
+    zdn.avail_out = NTGT;
+  
+    zdn.zalloc = Z_NULL;
+    zdn.zfree  = Z_NULL;
+    zdn.opaque = Z_NULL;
+
+    for (i = 0; i < NSRC; i++) srcbuf[i] = i; 
+    memset (tgtbuf, 0, NTGT);
+    memset (outbuf, 0, NTGT);
+
+    // the '5' is the compression level: make this a user argument
+    err = deflateInit(&zdn, 5);
+    if (err != Z_OK) { fprintf (stderr, "error 1: %d vs %d\n", err, Z_OK); exit (1); }
+  
+    err = deflate(&zdn, Z_FINISH);
+    if (err != Z_STREAM_END) { fprintf (stderr, "error 2: %d vs %d\n", err, Z_STREAM_END); exit (2); }
+
+    assert (zdn.total_out <= NTGT);
+
+    fprintf (stderr, "result: %d bytes\n", (int) zdn.total_out);
+    for (i = 0; i < zdn.total_out; i++) {
+      fprintf (stderr, "%d : 0x%02hhx\n", i, tgtbuf[i]);
+    }
+  }
+
+  {
+    z_stream zup;
+    zup.next_in = tgtbuf;
+    zup.avail_in = NTGT;
+    zup.next_out = outbuf;
+    zup.avail_out = NTGT;
+  
+    zup.zalloc = Z_NULL;
+    zup.zfree  = Z_NULL;
+    zup.opaque = Z_NULL;
+
+    // the '5' is the compression level: make this a user argument
+    err = inflateInit(&zup);
+    if (err != Z_OK) { fprintf (stderr, "error 1: %d vs %d\n", err, Z_OK); exit (1); }
+  
+    err = inflate(&zup, Z_FINISH);
+    if (err != Z_STREAM_END) { fprintf (stderr, "error 2: %d vs %d\n", err, Z_STREAM_END); exit (2); }
+
+    assert (zup.total_out <= NTGT);
+
+    fprintf (stderr, "result: %d bytes\n", (int) zup.total_out);
+    for (i = 0; i < zup.total_out; i++) {
+      fprintf (stderr, "%d : 0x%02hhx : 0x%02hhx\n", i, outbuf[i], srcbuf[i]);
+      assert (outbuf[i] == srcbuf[i]);
+    }
+  }
+
+  exit (0);
+}
