Index: trunk/psModules/src/objects/pmSourceIO.c
===================================================================
--- trunk/psModules/src/objects/pmSourceIO.c	(revision 35610)
+++ trunk/psModules/src/objects/pmSourceIO.c	(revision 36375)
@@ -69,4 +69,5 @@
 			psString *xfitname,    // Extension name for extended fitted measurements
 			psString *xradname,    // Extension name for radial apertures
+			psString *xgalname,    // Extension name for galaxy shapes
 			const pmFPAfile *file, // File of interest
 			const pmFPAview *view  // View to level of interest
@@ -140,4 +141,14 @@
         }
         *xradname = pmFPAfileNameFromRule (rule, file, view);
+    }
+
+    // EXTNAME for radial apertures
+    if (xgalname) {
+        const char *rule = psMetadataLookupStr(&status, menu, "CMF.XGAL");
+        if (!rule) {
+            psError(PS_ERR_UNKNOWN, true, "missing entry for CMF.XGAL in EXTNAME.RULES in camera.config");
+            return false;
+        }
+        *xgalname = pmFPAfileNameFromRule (rule, file, view);
     }
 
@@ -362,4 +373,7 @@
 	    status &= pmSourcesWrite_##TYPE##_XRAD (file->fits, readout, sources, file->header, xradname, recipe); \
 	}								\
+	if (xgalname) {							\
+	    status &= pmSourcesWrite_##TYPE##_XGAL (file->fits, sources, xgalname, recipe); \
+	}								\
     }
 
@@ -464,8 +478,11 @@
         }
 
-        // if this is not TRUE, the output files only contain the psf measurements.
-        bool XSRC_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_ANALYSIS");
+        // if none of these are TRUE, the output files only contain the psf measurements.
+	bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+	bool doAnnuli    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+        bool XSRC_OUTPUT = doPetrosian || doAnnuli;
         bool XFIT_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_FITS");
         bool XRAD_OUTPUT = psMetadataLookupBool(&status, recipe, "RADIAL_APERTURES");
+        bool XGAL_OUTPUT = psMetadataLookupBool(&status, recipe, "GALAXY_SHAPES");
 
         // define the EXTNAME values for the different data segments:
@@ -476,8 +493,10 @@
         psString xfitname = NULL;
         psString xradname = NULL;
+        psString xgalname = NULL;
         if (!pmSourceIOextnames(&headname, &dataname, &deteffname, 
 				XSRC_OUTPUT ? &xsrcname : NULL,
 				XFIT_OUTPUT ? &xfitname : NULL, 
 				XRAD_OUTPUT ? &xradname : NULL, 
+				XGAL_OUTPUT ? &xgalname : NULL, 
 				file, view)) {
             return false;
@@ -563,4 +582,7 @@
 		psMetadataAddStr (outhead, PS_LIST_TAIL, "XRADNAME", PS_META_REPLACE, "name of XRAD table extension", xradname);
             }
+            if (xgalname) {
+		psMetadataAddStr (outhead, PS_LIST_TAIL, "XGALNAME", PS_META_REPLACE, "name of XGAL table extension", xgalname);
+            }
 
             // these are case-sensitive since the EXTYPE is case-sensitive
@@ -609,4 +631,5 @@
 	psFree (xfitname);
 	psFree (xradname);
+	psFree (xgalname);
 	psFree (deteffname);
 
@@ -620,7 +643,28 @@
 	psFree (xfitname);
 	psFree (xradname);
+	psFree (xgalname);
 	psFree (deteffname);
 	return false;
 
+      case PM_FPA_FILE_CFF: {
+        // determine the output table format
+        psMetadata *recipe = psMetadataLookupMetadata(&status, config->recipes, "PSPHOT");
+        if (!status) {
+	    psError(PS_ERR_UNKNOWN, true, "missing recipe PSPHOT in config data");
+	    return false;
+        }
+
+        hdu = pmFPAviewThisHDU (view, fpa);
+        pmConfigConformHeader(hdu->header, file->format);
+        psFitsWriteBlank (file->fits, hdu->header, NULL);
+        file->header = hdu->header;
+        file->wrote_phu = true;
+	if (!pmSourcesWrite_CFF(readout, file->fits, sources, hdu->header, recipe)) {
+            psError(PS_ERR_UNKNOWN, false, "failed to write CFF");
+            return false;
+        }
+        break;
+      }
+        
       default:
         fprintf (stderr, "warning: type mismatch\n");
@@ -914,4 +958,16 @@
     psArray *sources = NULL;
     pmHDU *hdu;
+
+    // define the EXTNAME values for the different data segments:
+    psString headname = NULL;
+    psString dataname = NULL;
+    psString deteffname = NULL;
+    psString xsrcname = NULL;
+    psString xfitname = NULL;
+    psString xradname = NULL;
+    psString xgalname = NULL;
+
+    psMetadata *tableHeader = NULL;
+    char *xtension = NULL;
 
     switch (file->type) {
@@ -963,12 +1019,4 @@
         hdu = pmFPAviewThisHDU (view, file->fpa);
 
-        // define the EXTNAME values for the different data segments:
-        psString headname = NULL;
-        psString dataname = NULL;
-        psString deteffname = NULL;
-        psString xsrcname = NULL;
-        psString xfitname = NULL;
-        psString xradname = NULL;
-
         // determine the output table format. Assume if we need to output extendend source
         // parameters that they may exist in the input. 
@@ -981,8 +1029,12 @@
         }
 
-        // if this is not TRUE, the output files only contain the psf measurements.
-        bool XSRC_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_ANALYSIS");
+        // if none of these are TRUE, we only read the psf measurements
+        // XXX: shouldn't we look for these extensions and read the regardless of the recipe values?
+	bool doPetrosian = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_PETROSIAN");
+	bool doAnnuli    = psMetadataLookupBool (&status, recipe, "EXTENDED_SOURCE_ANNULI");
+        bool XSRC_OUTPUT = doPetrosian || doAnnuli;
         bool XFIT_OUTPUT = psMetadataLookupBool(&status, recipe, "EXTENDED_SOURCE_FITS");
         bool XRAD_OUTPUT = psMetadataLookupBool(&status, recipe, "RADIAL_APERTURES");
+        bool XGAL_OUTPUT = false; // psMetadataLookupBool(&status, recipe, "GALAXY_SHAPES");
 
         if (!pmSourceIOextnames(&headname, &dataname, &deteffname, 
@@ -990,4 +1042,5 @@
                 XFIT_OUTPUT ? &xfitname : NULL, 
                 XRAD_OUTPUT ? &xradname : NULL,
+                XGAL_OUTPUT ? &xgalname : NULL,
                 file, view)) {
             return false;
@@ -1033,8 +1086,8 @@
         }
 
-        psMetadata *tableHeader = psFitsReadHeader(NULL, file->fits); // The FITS header
+        tableHeader = psFitsReadHeader(NULL, file->fits); // The FITS header
         if (!tableHeader) psAbort("cannot read table header");
 
-        char *xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION");
+        xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION");
         if (!xtension) psAbort("cannot read table type");
 	if (strcmp (xtension, "BINTABLE")) {
@@ -1132,4 +1185,54 @@
         break;
 
+      case PM_FPA_FILE_CFF:
+        // read in header, if not yet loaded
+        hdu = pmFPAviewThisHDU (view, file->fpa);
+
+	// look these up in the camera config?
+	// headrule = {CHIP.NAME}.hdr
+	// datarule = {CHIP.NAME}.cff
+
+        // define the EXTNAME values for the different data segments:
+        headname = pmFPAfileNameFromRule("{CHIP.NAME}.hdr", file, view);
+        dataname = pmFPAfileNameFromRule("{CHIP.NAME}.cff", file, view);
+
+        // advance to the IMAGE HEADER extension
+        if (hdu->header == NULL) {
+            // if the IMAGE header does not exist, we have no data for this view
+            if (!psFitsMoveExtNameClean (file->fits, headname)) {
+                readout->data_exists = false;
+                psFree (headname);
+                psFree (dataname);
+                return true;
+            }
+            hdu->header = psFitsReadHeader (NULL, file->fits);
+        }
+
+        // advance to the table data extension
+        // since we have read the IMAGE header, the TABLE header should exist
+        if (!psFitsMoveExtName (file->fits, dataname)) {
+            psAbort("cannot find data extension %s in %s", dataname, file->filename);
+        }
+
+        tableHeader = psFitsReadHeader(NULL, file->fits); // The FITS header
+        if (!tableHeader) psAbort("cannot read table header");
+
+	// verify this is a binary table
+        char *xtension = psMetadataLookupStr (NULL, tableHeader, "XTENSION");
+        if (!xtension) psAbort("cannot read table type");
+	if (strcmp (xtension, "BINTABLE")) {
+	    psWarning ("no binary table in extension %s, skipping\n", dataname);
+            psFree(tableHeader);
+	    return false;
+	}
+
+	sources = pmSourcesRead_CFF(file->fits, hdu->header);
+
+        psTrace("psModules.objects", 6, "read CMF table from %s : %s : %s", file->filename, headname, dataname);
+        psFree (headname);
+        psFree (dataname);
+        psFree (tableHeader);
+        break;
+
       default:
         fprintf (stderr, "warning: type mismatch\n");
