Index: /branches/eam_branches/ipp-20130904/psModules/src/camera/pmFPAfileIO.c
===================================================================
--- /branches/eam_branches/ipp-20130904/psModules/src/camera/pmFPAfileIO.c	(revision 36151)
+++ /branches/eam_branches/ipp-20130904/psModules/src/camera/pmFPAfileIO.c	(revision 36152)
@@ -222,4 +222,5 @@
       case PM_FPA_FILE_CMP:
       case PM_FPA_FILE_CMF:
+      case PM_FPA_FILE_CFF:
       case PM_FPA_FILE_WCS:
       case PM_FPA_FILE_SRCTEXT:
Index: /branches/eam_branches/ipp-20130904/psModules/src/objects/pmSourceIO.c
===================================================================
--- /branches/eam_branches/ipp-20130904/psModules/src/objects/pmSourceIO.c	(revision 36151)
+++ /branches/eam_branches/ipp-20130904/psModules/src/objects/pmSourceIO.c	(revision 36152)
@@ -1132,4 +1132,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:
+        psString headname = pmFPAfileNameFromRule("{CHIP.NAME}.hdr", file, view);
+        psString 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);
+        }
+
+        psMetadata *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");
Index: /branches/eam_branches/ipp-20130904/psModules/src/objects/pmSourceIO_CFF.c
===================================================================
--- /branches/eam_branches/ipp-20130904/psModules/src/objects/pmSourceIO_CFF.c	(revision 36152)
+++ /branches/eam_branches/ipp-20130904/psModules/src/objects/pmSourceIO_CFF.c	(revision 36152)
@@ -0,0 +1,157 @@
+/** @file  pmSourceIO.c
+ *
+ *  @author EAM, IfA
+ *
+ *  @version $Revision: 1.3 $ $Name: not supported by cvs2svn $
+ *  @date $Date: 2009-02-18 02:44:19 $
+ *
+ *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#include <pslib.h>
+
+#include "pmConfig.h"
+#include "pmDetrendDB.h"
+
+#include "pmHDU.h"
+#include "pmFPA.h"
+#include "pmFPALevel.h"
+#include "pmFPAview.h"
+#include "pmFPAfile.h"
+
+#include "pmTrend2D.h"
+#include "pmResiduals.h"
+#include "pmGrowthCurve.h"
+#include "pmSpan.h"
+#include "pmFootprintSpans.h"
+#include "pmFootprint.h"
+#include "pmPeaks.h"
+#include "pmMoments.h"
+#include "pmModelFuncs.h"
+#include "pmModel.h"
+#include "pmModelUtils.h"
+#include "pmModelClass.h"
+#include "pmSourceMasks.h"
+#include "pmSourceExtendedPars.h"
+#include "pmSourceDiffStats.h"
+#include "pmSourceSatstar.h"
+#include "pmSource.h"
+#include "pmSourceFitModel.h"
+#include "pmPSF.h"
+#include "pmPSFtry.h"
+
+#include "pmSourceIO.h"
+#include "pmSourceOutputs.h"
+
+// read in a readout from the fits file
+psArray *pmSourcesRead_CFF (psFits *fits, psMetadata *header)
+{
+    PS_ASSERT_PTR_NON_NULL(fits, false);
+    PS_ASSERT_PTR_NON_NULL(header, false);
+
+    bool status;
+    psF32 *PAR, *dPAR;
+    psEllipseAxes axes;
+
+    // define PSF model type
+    // XXX need to carry the extra model parameters
+    int modelType = pmModelClassGetType ("PS_MODEL_GAUSS");
+
+    char *PSF_NAME = psMetadataLookupStr (&status, header, "PSF_NAME");
+    if (PSF_NAME != NULL) {
+        modelType = pmModelClassGetType (PSF_NAME);
+    }
+    assert (modelType > -1);
+
+    // We get the size of the table, and allocate the array of sources first because the table
+    // is large and ephemeral --- when the table gets blown away, whatever is allocated after
+    // the table is read blocks the free.  In fact, it's better to read the table row by row.
+    long numSources = psFitsTableSize(fits); // Number of sources in table
+    psArray *sources = psArrayAlloc(numSources); // Array of sources, to return
+
+    // convert the table to the pmSource entriesa
+    for (int i = 0; i < numSources; i++) {
+        psMetadata *row = psFitsReadTableRow(fits, i); // Table row
+        if (!row) {
+            psError(psErrorCodeLast(), false, "Unable to read row %d of sources", i);
+            psFree(sources);
+            return NULL;
+        }
+
+	// here are the things we read from the FITS table
+
+	unsigned int ID = psMetadataLookupU32 (&status, row, "IPP_IDET");
+	float X = psMetadataLookupF32 (&status, row, "X_PSF");
+	float Y = psMetadataLookupF32 (&status, row, "Y_PSF");
+
+        float apRadius   = psMetadataLookupS32 (&status, row, "AP_RADIUS");
+        float kronRadius = psMetadataLookupF32 (&status, row, "KRON_RADIUS");
+        float petRadius  = psMetadataLookupU32 (&status, row, "PETRO_RADIUS");
+        bool fitGalaxy   = psMetadataLookupU32 (&status, row, "FIT_GALAXY");
+
+        float Rmajor     = psMetadataLookupU32 (&status, row, "R_MAJOR");
+        float Rminor     = psMetadataLookupU32 (&status, row, "R_MINOR");
+        float theta      = psMetadataLookupU32 (&status, row, "THETA");
+        float Sindex     = psMetadataLookupU32 (&status, row, "INDEX");
+
+        pmSource *source = pmSourceAlloc ();
+        pmModel *model = pmModelAlloc (modelType);
+        source->modelPSF  = model;
+        source->type = PM_SOURCE_TYPE_STAR; // XXX this should be added to the flags
+
+	// NOTE: A SEGV here because "model" is NULL is probably caused by not initialising the models.
+	psF32 *PAR = model->params->data.F32;
+	psF32 *dPAR = model->dparams->data.F32;
+
+        source->seq          = ID;
+        PAR[PM_PAR_XPOS]     = X;
+        PAR[PM_PAR_YPOS]     = Y;
+
+	dPAR[PM_PAR_XPOS] = 0.0;
+	dPAR[PM_PAR_YPOS] = 0.0;
+
+	PAR[PM_PAR_SKY]   = 0.0;
+	dPAR[PM_PAR_SKY]  = 0.0;
+
+	PAR[PM_PAR_I0]    = 1.0;
+	dPAR[PM_PAR_I0]   = 0.0;
+
+	source->sky       = PAR[PM_PAR_SKY];
+	source->skyErr    = dPAR[PM_PAR_SKY];
+
+	source->psfMag    = 0.0;
+	source->psfMagErr    = 0.0;
+	source->apMag     = 0.0;
+
+	axes.major        = 1.0;
+	axes.minor        = 1.0;
+	axes.theta        = 0.0;
+	pmPSF_AxesToModel (PAR, axes, modelType);
+
+	float peakFlux    = 1.0;
+
+        source->peak = pmPeakAlloc(PAR[PM_PAR_XPOS], PAR[PM_PAR_YPOS], peakFlux, PM_PEAK_LONE);
+        source->peak->rawFlux = peakFlux;
+        source->peak->smoothFlux = peakFlux;
+        source->peak->xf   = PAR[PM_PAR_XPOS]; // more accurate position
+        source->peak->yf   = PAR[PM_PAR_YPOS]; // more accurate position
+        source->peak->dx   = dPAR[PM_PAR_XPOS];
+        source->peak->dy   = dPAR[PM_PAR_YPOS];
+
+        assert (status);
+
+        sources->data[i] = source;
+        psFree(row);
+    }
+
+    return sources;
+}
+
