ed793e195478d944c19112fa4e0cb0884debdbb9
braney
  Sun Sep 16 08:33:51 2012 -0700
fix twoBit recognition logic  (#9095).  Look for signature in file rather than .2bit suffix
diff --git src/lib/twoBit.c src/lib/twoBit.c
index f01e2ea..10ec2e2 100644
--- src/lib/twoBit.c
+++ src/lib/twoBit.c
@@ -263,47 +263,62 @@
 void twoBitClose(struct twoBitFile **pTbf)
 /* Free up resources associated with twoBitFile. */
 {
 struct twoBitFile *tbf = *pTbf;
 if (tbf != NULL)
     {
     freez(&tbf->fileName);
     carefulClose(&tbf->f);
     hashFree(&tbf->hash);
     /* The indexList is allocated out of the hash's memory pool. */
     bptFileClose(&tbf->bpt);
     freez(pTbf);
     }
 }
 
+boolean twoBitSigRead(FILE *f, boolean *isSwapped)
+/* read twoBit signature, return FALSE if not good 
+ * set isSwapped to TRUE if twoBit file is byte swapped */
+{
+bits32 sig;
+
+*isSwapped = FALSE;
+mustReadOne(f, sig);
+if (sig == twoBitSwapSig)
+    *isSwapped = TRUE;
+else if (sig != twoBitSig)
+    return FALSE;
+
+return TRUE;
+}
+
 static struct twoBitFile *twoBitOpenReadHeader(char *fileName)
 /* Open file, read in header but not index.  
  * Squawk and die if there is a problem. */
 {
-bits32 sig;
 struct twoBitFile *tbf;
 boolean isSwapped = FALSE;
 FILE *f = mustOpen(fileName, "rb");
 
 /* Allocate header verify signature, and read in
  * the constant-length bits. */
 AllocVar(tbf);
-mustReadOne(f, sig);
-if (sig == twoBitSwapSig)
-    isSwapped = tbf->isSwapped = TRUE;
-else if (sig != twoBitSig)
+
+if (!twoBitSigRead(f, &isSwapped))
     errAbort("%s doesn't have a valid twoBitSig", fileName);
+
+tbf->isSwapped = isSwapped;
 tbf->fileName = cloneString(fileName);
 tbf->f = f;
 tbf->version = readBits32(f, isSwapped);
 if (tbf->version != 0)
     {
     errAbort("Can only handle version 0 of this file. This is version %d",
     	(int)tbf->version);
     }
 tbf->seqCount = readBits32(f, isSwapped);
 tbf->reserved = readBits32(f, isSwapped);
 return tbf;
 }
 
 struct twoBitFile *twoBitOpen(char *fileName)
 /* Open file, read in header and index.  
@@ -758,31 +773,37 @@
 struct twoBitIndex *index;
 struct slName *name, *list = NULL;
 for (index = tbf->indexList; index != NULL; index = index->next)
     {
     name = slNameNew(index->name);
     slAddHead(&list, name);
     }
 twoBitClose(&tbf);
 slReverse(&list);
 return list;
 }
 
 boolean twoBitIsFile(char *fileName)
 /* Return TRUE if file is in .2bit format. */
 {
-return endsWith(fileName, ".2bit");
+FILE *f = mustOpen(fileName, "rb");
+boolean isSwapped;
+boolean isTwoBit = twoBitSigRead(f, &isSwapped);
+
+fclose(f);
+
+return isTwoBit;
 }
 
 boolean twoBitParseRange(char *rangeSpec, char **retFile, 
 	char **retSeq, int *retStart, int *retEnd)
 /* Parse out something in format
  *    file/path/name:seqName:start-end
  * or
  *    file/path/name:seqName
  * or
  *    file/path/name:seqName1,seqName2,seqName3,...
  * This will destroy the input 'rangeSpec' in the process.  Returns FALSE if
  * it doesn't fit this format, setting retFile to rangeSpec, and retSet to
  * null.  If it is the shorter form then start and end will both be returned
  * as zero, which is ok by twoBitReadSeqFrag.  Any of the return arguments
  * maybe NULL.
@@ -921,30 +942,36 @@
 if (s == NULL)
     s = spec->fileName;
 else
     s++;
 
 /* find end of file name and zero-terminate */
 e = strchr(s, ':');
 if (e == NULL)
     s = NULL; /* just file name */
 else
     {
     *e++ = '\0';
     s = e;
     }
 
+if (!twoBitIsFile(spec->fileName))
+    {
+    twoBitSpecFree(&spec);
+    return NULL; /* not a 2bit file */
+    }
+
 if (s != NULL)
     {
     /* chop seqs at commas and parse */
     numSeqs = chopString(s, ",", NULL, 0);
     AllocArray(seqSpecs, numSeqs);
     chopString(s, ",", seqSpecs, numSeqs);
     for (i = 0; i< numSeqs; i++)
         slSafeAddHead(&spec->seqs, parseSeqSpec(seqSpecs[i]));
     slReverse(&spec->seqs);
     }
 return spec;
 }
 
 struct twoBitSpec *twoBitSpecNewFile(char *twoBitFile, char *specFile)
 /* parse a file containing a list of specifications for sequences in the