023255de913dda73eeceee882e1b5f824c94f34f
jcasper
  Tue Apr 18 10:52:42 2023 -0700
Need to catch errors on opening a hic file with Straw, because the
magic string check can also generate an exception.  refs #31071

diff --git src/hg/lib/straw/cStraw.cpp src/hg/lib/straw/cStraw.cpp
index b284723..31a663c 100644
--- src/hg/lib/straw/cStraw.cpp
+++ src/hg/lib/straw/cStraw.cpp
@@ -1,169 +1,181 @@
 
 #include <cstring>
 #include <iostream>
 #include <fstream>
 #include <iostream>
 #include <sstream>
 #include <map>
 #include <set>
 #include <vector>
 #include <streambuf>
 #include "zlib.h"
 #include "straw.h"
 using namespace std;
 
 // Supplementary functions for invoking Straw in C
 
 
 void getHeaderFields(Straw *hicFile, string &genome, vector<string> &chromNames, vector<int> &chromSizes, vector<int> &bpResolutions, vector<int> &fragResolutions, vector<string> &attributes)
 /* Retrieve .hic header fields from the supplied filename and return them in the supplied variables. */
 {
   hicFile->loadHeader();
   genome = hicFile->genome;
   chromNames = hicFile->chrNames;
   chromSizes = hicFile->chrSizes;
   bpResolutions = hicFile->bpResolutions;
   fragResolutions = hicFile->fragResolutions;
   map<std::string,std::string>::iterator loop;
   for (loop=hicFile->attributes.begin(); loop!=hicFile->attributes.end(); loop++) {
     attributes.insert(attributes.end(), loop->first);
     attributes.insert(attributes.end(), loop->second);
   }
 }
 
 
-extern "C" Straw *cStrawOpen(char *fname) {
-    return new Straw(fname);
+extern "C" char *cStrawOpen(char *fname, Straw **p)
+/* Create a Straw object based on the hic file at the provided path and set *p to point to it.
+ * On error, set *p = NULL and return a non-null string describing the error. */
+{
+    try {
+        *p = new Straw(fname);
+    } catch (strawException& err) {
+      char *errMsg = (char*) calloc((size_t) strlen(err.what())+1, sizeof(char));
+      strcpy(errMsg, err.what());
+      delete *p;
+      *p = NULL;
+      return errMsg;
+    }
+    return NULL;
 }
 
 extern "C" void cStrawClose(Straw **hicFile) {
     delete *hicFile;
     *hicFile = NULL;
 }
 
 extern "C" char *cStraw (Straw *hicFile, char *norm, int binsize, char *chr1loc, char *chr2loc, char *unit, int **xActual, int **yActual, double **counts, int *numRecords)
 /* Wrapper function to retrieve a data chunk from a .hic file, for use by C libraries.
  * norm is one of NONE/VC/VC_SQRT/KR.
  * binsize is one of the supported bin sizes as determined by cStrawHeader.
  * chr1loc and chr2loc are the two positions to retrieve interaction data for, specified as chr:start-end.
  * unit is one of BP/FRAG.
  * Values are returned in newly allocated arrays in xActual, yActual, and counts, with the number of
  * returned records in numRecords.
  * The function returns NULL unless an error was encountered, in which case the return value points
  * to a character string explaining the error. */
 {
     string thisnorm(norm);
     string thischr1loc(chr1loc);
     string thischr2loc(chr2loc);
     string thisunit(unit);
     vector<int> thisx;
     vector<int> thisy;
     vector<float> thiscounts;
     try {
       hicFile->straw(thisnorm, binsize, thischr1loc, thischr2loc, unit, thisx, thisy, thiscounts);
     } catch (strawException& err) {
       char *errMsg = (char*) calloc((size_t) strlen(err.what())+1, sizeof(char));
       strcpy(errMsg, err.what());
       return errMsg;
     }
     *numRecords = thisx.size();
     *xActual = (int*) calloc((size_t) *numRecords, sizeof(int));
     *yActual = (int*) calloc((size_t) *numRecords, sizeof(int));
     *counts = (double*) calloc((size_t) *numRecords, sizeof(double));
     for (int i=0; i<*numRecords; i++)
         {
         (*xActual)[i] = thisx[i];
         (*yActual)[i] = thisy[i];
         (*counts)[i] = (double) thiscounts[i];
         }
     return NULL;
 }
 
 
 extern "C" char *cStrawHeader (Straw *hicFile, char **genome, char ***chromNames, int **chromSizes, int *nChroms, char ***bpResolutions, int *nBpRes, char ***fragResolutions, int *nFragRes, char ***attributes, int *nAttributes)
 /* Wrapper function to retrieve header fields from a .hic file, for use by C libraries.
  * This retrieves the assembly name, list of chromosome names, list of available binsize resolutions,
  * and list of available fragment resolutions in the specific .hic file.
  * The function returns NULL unless an error was encountered, in which case the return value points
  * to a character string explaining the error. */
 {
   string genomeString;
   vector<string> chromNameVector;
   vector<int> chromSizeVector;
   vector<int> bpResolutionVector;
   vector<int> fragResolutionVector;
   vector<string> attributeVector;
   try {
     getHeaderFields(hicFile, genomeString, chromNameVector, chromSizeVector, bpResolutionVector, fragResolutionVector, attributeVector);
   } catch (strawException& err) {
     char *errMsg = (char*) calloc((size_t) strlen(err.what())+1, sizeof(char));
     strcpy(errMsg, err.what());
     return errMsg;
   }
   if (genome != NULL)
   {
     *genome = (char*) malloc((genomeString.length()+1)*sizeof(char));
     strcpy(*genome, genomeString.c_str());
   }
   if (nChroms != NULL)
   {
     *nChroms = chromNameVector.size();
   }
   if (chromNames != NULL)
   {
     *chromNames = (char**) calloc((size_t) chromNameVector.size(), sizeof(char*));
     for (int i=0; i<chromNameVector.size(); i++)
     {
       (*chromNames)[i] = (char*) malloc((chromNameVector[i].length()+1)*sizeof(char));
       strcpy((*chromNames)[i], chromNameVector[i].c_str());
     }
   }
   if (chromSizes != NULL)
   {
     *chromSizes = (int*) calloc((size_t) chromSizeVector.size(), sizeof(int));
     for (int i=0; i<chromSizeVector.size(); i++)
     {
       (*chromSizes)[i] = chromSizeVector[i];
     }
   }
   if (nBpRes != NULL)
   {
     *nBpRes = bpResolutionVector.size();
   }
   if (bpResolutions != NULL)
   {
     *bpResolutions = (char**) calloc((size_t) bpResolutionVector.size(), sizeof(char*));
     for (int i=0; i<bpResolutionVector.size(); i++)
     {
       (*bpResolutions)[i] = (char*) malloc((to_string(bpResolutionVector[i]).length()+1)*sizeof(char));
       strcpy((*bpResolutions)[i], to_string(bpResolutionVector[i]).c_str());
     }
   }
   if (nFragRes != NULL)
   {
     *nFragRes = fragResolutionVector.size();
   }
   if (fragResolutions != NULL)
   {
     *fragResolutions = (char**) calloc((size_t) fragResolutionVector.size(), sizeof(char*));
     for (int i=0; i<fragResolutionVector.size(); i++)
     {
       (*fragResolutions)[i] = (char*) malloc((to_string(fragResolutionVector[i]).length()+1)*sizeof(char));
       strcpy((*fragResolutions)[i], to_string(fragResolutionVector[i]).c_str());
     }
   }
   if (nAttributes != NULL)
   {
     *nAttributes = attributeVector.size();
   }
   if (attributes != NULL)
   {
     *attributes = (char**) calloc((size_t) attributeVector.size(), sizeof(char*));
     for (int i=0; i<attributeVector.size(); i++)
     {
       (*attributes)[i] = (char*) malloc((attributeVector[i].length()+1)*sizeof(char));
       strcpy((*attributes)[i], attributeVector[i].c_str());
     }
   }
   return NULL;
 }