GlfFile.cpp

00001 /*
00002  *  Copyright (C) 2010  Regents of the University of Michigan
00003  *
00004  *   This program is free software: you can redistribute it and/or modify
00005  *   it under the terms of the GNU General Public License as published by
00006  *   the Free Software Foundation, either version 3 of the License, or
00007  *   (at your option) any later version.
00008  *
00009  *   This program is distributed in the hope that it will be useful,
00010  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *   GNU General Public License for more details.
00013  *
00014  *   You should have received a copy of the GNU General Public License
00015  *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016  */
00017 #include <stdexcept>
00018 #include <stdlib.h>
00019 #include "GlfFile.h"
00020 #include "GlfException.h"
00021 
00022 // Constructor, init variables.
00023 GlfFile::GlfFile()
00024     : myFilePtr(NULL),
00025       myEndMarker()
00026 {
00027     resetFile();
00028 }
00029 
00030 
00031 // Constructor, init variables and open the specified file based on the
00032 // specified mode (READ/WRITE).  Default is READ..
00033 GlfFile::GlfFile(const char* filename, OpenType mode)
00034     : myFilePtr(NULL),
00035       myEndMarker()
00036 {
00037     resetFile();
00038 
00039     bool openStatus = true;
00040     if(mode == READ)
00041     {
00042         // open the file for read.
00043         openStatus = openForRead(filename);
00044     }
00045     else
00046     {
00047         // open the file for write.
00048         openStatus = openForWrite(filename);
00049     }
00050     if(!openStatus)
00051     {
00052         // Failed to open the file - print error and abort.
00053         fprintf(stderr, "%s\n", getStatusMessage());
00054         std::cerr << "FAILURE - EXITING!!!" << std::endl;
00055         exit(-1);
00056     }
00057 }
00058 
00059 GlfFile::~GlfFile()
00060 {
00061     resetFile();
00062 }
00063 
00064 
00065 // Open a glf file for reading with the specified filename.
00066 bool GlfFile::openForRead(const char * filename)
00067 {
00068     // Reset for any previously operated on files.
00069     resetFile();
00070 
00071     myFilePtr = ifopen(filename, "rb");
00072    
00073     if (myFilePtr == NULL)
00074     {
00075         std::string errorMessage = "Failed to Open ";
00076         errorMessage += filename;
00077         errorMessage += " for reading";
00078         myStatus.setStatus(GlfStatus::FAIL_IO, errorMessage.c_str());
00079         throw(GlfException(myStatus));
00080         return(false);
00081     }
00082 
00083     myIsOpenForRead = true;
00084     // Successfully opened the file.
00085     myStatus = GlfStatus::SUCCESS;
00086     return(true);
00087 }
00088 
00089 
00090 // Open a glf file for reading with the specified filename and read the
00091 // header into the specified header.
00092 bool GlfFile::openForRead(const char * filename, GlfHeader& header)
00093 {
00094     if(!openForRead(filename))
00095     {
00096         return(false);
00097     }
00098 
00099     // Read the header
00100     if(!readHeader(header))
00101     {
00102         return(false);
00103     }
00104     return(true);
00105 }
00106 
00107 
00108 // Open a glf file for writing with the specified filename.
00109 bool GlfFile::openForWrite(const char * filename)
00110 {
00111     // Reset for any previously operated on files.
00112     resetFile();
00113 
00114     myFilePtr = ifopen(filename, "wb", InputFile::BGZF);
00115     
00116     if (myFilePtr == NULL)
00117     {
00118         std::string errorMessage = "Failed to Open ";
00119         errorMessage += filename;
00120         errorMessage += " for writing";
00121         myStatus.setStatus(GlfStatus::FAIL_IO, errorMessage.c_str());
00122         throw(GlfException(myStatus));
00123         return(false);
00124     }
00125    
00126     myIsOpenForWrite = true;
00127 
00128     // Successfully opened the file.
00129     myStatus = GlfStatus::SUCCESS;
00130     return(true);
00131 }
00132 
00133 
00134 // Close the file if there is one open.
00135 void GlfFile::close()
00136 {
00137     // Resetting the file will close it if it is open, and
00138     // will reset all other variables.
00139     resetFile();
00140 }
00141 
00142 
00143 // Returns whether or not the end of the file has been reached.
00144 // return: int - true = EOF; false = not eof.
00145 bool GlfFile::isEOF()
00146 {
00147     if (myFilePtr != NULL)
00148     {
00149         // File Pointer is set, so return if eof.
00150         return(ifeof(myFilePtr));
00151     }
00152     // File pointer is not set, so return true, eof.
00153     return true;
00154 }
00155 
00156 
00157 // Read the header from the currently opened file.
00158 bool GlfFile::readHeader(GlfHeader& header)
00159 {
00160     if(myIsOpenForRead == false)
00161     {
00162         // File is not open for read
00163         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00164                            "Cannot read header since the file is not open for reading");
00165         throw(GlfException(myStatus));
00166         return(false);
00167     }
00168 
00169     if(myNextSection != HEADER)
00170     {
00171         // The header has already been read.
00172         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00173                            "Cannot read header since it has already been read.");
00174         throw(GlfException(myStatus));
00175         return(false);
00176     }
00177 
00178     if(header.read(myFilePtr))
00179     {
00180         // The header has now been successfully read.
00181         myNextSection = REF_SECTION;
00182         myStatus = GlfStatus::SUCCESS;
00183         return(true);
00184     }
00185     myStatus.setStatus(GlfStatus::UNKNOWN, 
00186                        "Failed to read the header.");
00187     throw(GlfException(myStatus));
00188     return(false);
00189 }
00190 
00191 
00192 // Write the header to the currently opened file.
00193 bool GlfFile::writeHeader(GlfHeader& header)
00194 {
00195     if(myIsOpenForWrite == false)
00196     {
00197         // File is not open for write
00198         // -OR-
00199         // The header has already been written.
00200         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00201                            "Cannot write header since the file is not open for writing");
00202         throw(GlfException(myStatus));
00203         return(false);
00204     }
00205 
00206     if(myNextSection != HEADER)
00207     {
00208         // The header has already been written.
00209         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00210                            "Cannot write header since it has already been written");
00211         throw(GlfException(myStatus));
00212         return(false);
00213     }
00214 
00215     if(header.write(myFilePtr))
00216     {
00217         // The header has now been successfully written.
00218         myNextSection = REF_SECTION;
00219         myStatus = GlfStatus::SUCCESS;
00220         return(true);
00221     }
00222 
00223     // return the status.
00224     myStatus.setStatus(GlfStatus::UNKNOWN, 
00225                        "Failed to write the header.");
00226     throw(GlfException(myStatus));
00227     return(false);
00228 }
00229 
00230 
00231 // Gets the next reference section from the file & stores it in the
00232 // passed in section.  It will read until a new section is found.
00233 bool GlfFile::getNextRefSection(GlfRefSection& refSection)
00234 {
00235     if(myIsOpenForRead == false)
00236     {
00237         // File is not open for read
00238         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00239                            "Cannot read reference section since the file is not open for reading");
00240         throw(GlfException(myStatus));
00241         return(false);
00242     }
00243 
00244     if(myNextSection == HEADER)
00245     {
00246         // The header has not yet been read.
00247         // TODO - maybe just read the header.
00248         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00249                            "Cannot read reference section since the header has not been read.");
00250         throw(GlfException(myStatus));
00251         return(false);
00252     }
00253 
00254     // Keep reading until the next section is found.
00255     if(myNextSection == RECORD)
00256     {
00257         GlfRecord record;
00258         while(getNextRecord(record))
00259         {
00260             // Nothing to do, with the record.
00261         }
00262     }
00263 
00264     // Check for end of file.  If end of file, return false.
00265     if(isEOF())
00266     {
00267         return(false);
00268     }
00269 
00270     if(myNextSection != REF_SECTION)
00271     {
00272         // Failed reading all the records, so throw exception.
00273         myStatus.setStatus(GlfStatus::FAIL_IO, 
00274                            "Failed to get to a reference section.");
00275         throw(GlfException(myStatus));
00276         return(false);
00277     }
00278 
00279     // Ready to read the section:
00280     if(refSection.read(myFilePtr))
00281     {
00282         myStatus = GlfStatus::SUCCESS;
00283         // Next a record should be read.
00284         myNextSection = RECORD;
00285         return(true);
00286     }
00287 
00288     // If it is the EOF, just return false.
00289     if(isEOF())
00290     {
00291         return(false);
00292     }
00293     myStatus.setStatus(GlfStatus::UNKNOWN, 
00294                        "Failed reading a reference section from the file.");
00295     throw(GlfException(myStatus));
00296     return(false);
00297 }
00298 
00299 
00300 // Write the reference section to the file.
00301 bool GlfFile::writeRefSection(const GlfRefSection& refSection)
00302 {
00303     if(myIsOpenForWrite == false)
00304     {
00305         // File is not open for write
00306         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00307                            "Cannot write reference section since the file is not open for writing");
00308         throw(GlfException(myStatus));
00309         return(false);
00310     }
00311 
00312     if(myNextSection == HEADER)
00313     {
00314         // The header has not been written.
00315         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00316                            "Cannot write reference section since the header has not been written");
00317         throw(GlfException(myStatus));
00318        return(false);
00319     }
00320 
00321     if(myNextSection == RECORD)
00322     {
00323         // did not write a end marker record, so write one now.
00324         if(!writeRecord(myEndMarker))
00325         {
00326             // Failed to write the end marker record.
00327             myStatus.setStatus(GlfStatus::FAIL_IO,
00328                                "Failed to write end of chromosome/section marker.");
00329             throw(GlfException(myStatus));
00330             return(false);
00331         }
00332     }
00333 
00334     if(myNextSection != REF_SECTION)
00335     {
00336         // Not ready to write a reference section.
00337         myStatus.setStatus(GlfStatus::FAIL_IO,
00338                            "Not ready for a chromosome/section header.");
00339         throw(GlfException(myStatus));
00340         return(false);
00341     }
00342 
00343     if(refSection.write(myFilePtr))
00344     {
00345         myStatus = GlfStatus::SUCCESS;
00346         // A reference section has now been successfully written.
00347         myNextSection = RECORD;
00348         return(true);
00349     }
00350 
00351     // return the status.
00352     myStatus.setStatus(GlfStatus::UNKNOWN, 
00353                        "Failed writing a reference section to the file.");
00354     throw(GlfException(myStatus));
00355     return(false);    
00356 }
00357 
00358 
00359 // Gets the next reference section from the file & stores it in the
00360 // passed in record.
00361 bool GlfFile::getNextRecord(GlfRecord& record)
00362 {
00363     if(myIsOpenForRead == false)
00364     {
00365         // File is not open for read
00366         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00367                            "Cannot read reference section since the file is not open for reading");
00368         throw(GlfException(myStatus));
00369         return(false);
00370     }
00371 
00372     if(myNextSection == HEADER)
00373     {
00374         // The header has not yet been read.
00375         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00376                            "Cannot read reference section since the header has not been read.");
00377         throw(GlfException(myStatus));
00378         return(false);
00379     }
00380     
00381     if(myNextSection == REF_SECTION)
00382     {
00383         // The reference section has not yet been read.
00384         // TODO - maybe just read the reference section.
00385         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00386                            "Cannot read record since a reference section has not been read.");
00387         throw(GlfException(myStatus));
00388         return(false);
00389     }
00390 
00391     // Read the record.
00392     if(record.read(myFilePtr))
00393     {
00394         myStatus = GlfStatus::SUCCESS;
00395         if(record.getRecordType() != 0)
00396         {
00397             return(true);
00398         }
00399         else
00400         {
00401             // Not an error, so no exception thrown, but no more records.
00402             // The next thing is a reference section.
00403             myNextSection = REF_SECTION;
00404             return(false);
00405         }
00406     }
00407     
00408     myStatus.setStatus(GlfStatus::UNKNOWN, 
00409                        "Failed reading a record from the file.");
00410     throw(GlfException(myStatus));
00411     return(false);
00412 }
00413 
00414 
00415 // Write the reference section to the file.
00416 bool GlfFile::writeRecord(const GlfRecord& record)
00417 {
00418     if(myIsOpenForWrite == false)
00419     {
00420         // File is not open for write
00421         // -OR-
00422         // The header has already been written.
00423         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00424                            "Cannot write record since the file is not open for writing");
00425         throw(GlfException(myStatus));
00426        return(false);
00427     }
00428 
00429     if(myNextSection == HEADER)
00430     {
00431         // The header has not been written.
00432         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00433                            "Cannot write record since the header has not been written");
00434         throw(GlfException(myStatus));
00435         return(false);
00436     }
00437 
00438     if(myNextSection != RECORD)
00439     {
00440         // The header has not been written.
00441         myStatus.setStatus(GlfStatus::FAIL_ORDER, 
00442                            "Cannot write record since a reference section has not been written");
00443         throw(GlfException(myStatus));
00444         return(false);
00445     }
00446 
00447     if(record.write(myFilePtr))
00448     {
00449         myStatus = GlfStatus::SUCCESS;
00450         // The record has now been successfully written.
00451 
00452         // Check if it was the end marker - if so, set that next a 
00453         // reference section is expected.
00454         if(record.getRecordType() == 0)
00455         {
00456             myNextSection = REF_SECTION;
00457         }
00458         return(true);
00459     }
00460 
00461     // return the status.
00462     myStatus.setStatus(GlfStatus::UNKNOWN, 
00463                        "Failed writing a record to the file.");
00464     throw(GlfException(myStatus));
00465     return(false);    
00466 }
00467 
00468 
00469 // Return the number of records that have been read/written so far.
00470 uint32_t GlfFile::getCurrentRecordCount()
00471 {
00472     return(myRecordCount);
00473 }
00474 
00475 
00476 // Reset variables for each file.
00477 void GlfFile::resetFile()
00478 {
00479     // Close the file.
00480     if (myFilePtr != NULL)
00481     {
00482         // If we already have an open file, close it.
00483         // First check to see if an end record needs to be written, which
00484         // is the case if the state is RECORD.
00485         if(myNextSection == RECORD)
00486         {
00487             if(!writeRecord(myEndMarker))
00488             {
00489                 // Failed to write the end marker record.
00490                 myStatus.setStatus(GlfStatus::FAIL_IO,
00491                                    "Failed to write end of chromosome/section marker.");
00492                 throw(GlfException(myStatus));
00493             }
00494         }
00495         ifclose(myFilePtr);
00496         myFilePtr = NULL;
00497     }
00498 
00499     myIsOpenForRead = false;
00500     myIsOpenForWrite = false;
00501     myRecordCount = 0;
00502     myStatus = GlfStatus::SUCCESS;
00503     myNextSection = HEADER;
00504 }
00505 
00506 
00507 // Default Constructor.
00508 GlfFileReader::GlfFileReader()
00509 {
00510 }
00511 
00512 
00513 // Constructor that opens the specified file for read.
00514 GlfFileReader::GlfFileReader(const char* filename)
00515 {
00516     if(!openForRead(filename))
00517     {
00518         // Failed to open for reading - print error and abort.
00519         fprintf(stderr, "%s\n", getStatusMessage());
00520         std::cerr << "FAILURE - EXITING!!!" << std::endl;
00521         exit(-1);
00522     }
00523 }
00524 
00525 
00526 GlfFileReader::~GlfFileReader()
00527 {
00528 }
00529 
00530 
00531 // Default Constructor.
00532 GlfFileWriter::GlfFileWriter()
00533 {
00534 }
00535 
00536 
00537 // Constructor that opens the specified file for write.
00538 GlfFileWriter::GlfFileWriter(const char* filename)
00539 {
00540     if(!openForWrite(filename))
00541     {
00542         // Failed to open for reading - print error and abort.
00543         fprintf(stderr, "%s\n", getStatusMessage());
00544         std::cerr << "FAILURE - EXITING!!!" << std::endl;
00545         exit(-1);
00546     }
00547 }
00548 
00549 
00550 GlfFileWriter::~GlfFileWriter()
00551 {
00552 }
Generated on Wed Nov 17 15:38:29 2010 for StatGen Software by  doxygen 1.6.3