libStatGen Software  1
GlfFile.cpp
1 /*
2  * Copyright (C) 2010 Regents of the University of Michigan
3  *
4  * This program is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 3 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program. If not, see <http://www.gnu.org/licenses/>.
16  */
17 #include <stdexcept>
18 #include <stdlib.h>
19 #include "GlfFile.h"
20 #include "GlfException.h"
21 
22 // Constructor, init variables.
24  : myFilePtr(NULL),
25  myEndMarker()
26 {
27  resetFile();
28 }
29 
30 
31 // Constructor, init variables and open the specified file based on the
32 // specified mode (READ/WRITE). Default is READ..
33 GlfFile::GlfFile(const char* filename, OpenType mode)
34  : myFilePtr(NULL),
35  myEndMarker()
36 {
37  resetFile();
38 
39  bool openStatus = true;
40  if(mode == READ)
41  {
42  // open the file for read.
43  openStatus = openForRead(filename);
44  }
45  else
46  {
47  // open the file for write.
48  openStatus = openForWrite(filename);
49  }
50  if(!openStatus)
51  {
52  // Failed to open the file - print error and abort.
53  fprintf(stderr, "%s\n", getStatusMessage());
54  std::cerr << "FAILURE - EXITING!!!" << std::endl;
55  exit(-1);
56  }
57 }
58 
60 {
61  resetFile();
62 }
63 
64 
65 // Open a glf file for reading with the specified filename.
66 bool GlfFile::openForRead(const char * filename)
67 {
68  // Reset for any previously operated on files.
69  resetFile();
70 
71  myFilePtr = ifopen(filename, "rb");
72 
73  if (myFilePtr == NULL)
74  {
75  std::string errorMessage = "Failed to Open ";
76  errorMessage += filename;
77  errorMessage += " for reading";
78  myStatus.setStatus(GlfStatus::FAIL_IO, errorMessage.c_str());
79  throw(GlfException(myStatus));
80  return(false);
81  }
82 
83  myIsOpenForRead = true;
84  // Successfully opened the file.
85  myStatus = GlfStatus::SUCCESS;
86  return(true);
87 }
88 
89 
90 // Open a glf file for reading with the specified filename and read the
91 // header into the specified header.
92 bool GlfFile::openForRead(const char * filename, GlfHeader& header)
93 {
94  if(!openForRead(filename))
95  {
96  return(false);
97  }
98 
99  // Read the header
100  if(!readHeader(header))
101  {
102  return(false);
103  }
104  return(true);
105 }
106 
107 
108 // Open a glf file for writing with the specified filename.
109 bool GlfFile::openForWrite(const char * filename, bool compressed)
110 {
111  // Reset for any previously operated on files.
112  resetFile();
113 
114  if(compressed)
115  {
116  myFilePtr = ifopen(filename, "wb", InputFile::BGZF);
117  }
118  else
119  {
120  myFilePtr = ifopen(filename, "wb", InputFile::UNCOMPRESSED);
121  }
122 
123  if (myFilePtr == NULL)
124  {
125  std::string errorMessage = "Failed to Open ";
126  errorMessage += filename;
127  errorMessage += " for writing";
128  myStatus.setStatus(GlfStatus::FAIL_IO, errorMessage.c_str());
129  throw(GlfException(myStatus));
130  return(false);
131  }
132 
133  myIsOpenForWrite = true;
134 
135  // Successfully opened the file.
136  myStatus = GlfStatus::SUCCESS;
137  return(true);
138 }
139 
140 
141 // Close the file if there is one open.
143 {
144  // Resetting the file will close it if it is open, and
145  // will reset all other variables.
146  resetFile();
147 }
148 
149 
150 // Returns whether or not the end of the file has been reached.
151 // return: int - true = EOF; false = not eof.
153 {
154  if (myFilePtr != NULL)
155  {
156  // File Pointer is set, so return if eof.
157  return(ifeof(myFilePtr));
158  }
159  // File pointer is not set, so return true, eof.
160  return true;
161 }
162 
163 
164 // Read the header from the currently opened file.
166 {
167  if(myIsOpenForRead == false)
168  {
169  // File is not open for read
171  "Cannot read header since the file is not open for reading");
172  throw(GlfException(myStatus));
173  return(false);
174  }
175 
176  if(myNextSection != HEADER)
177  {
178  // The header has already been read.
180  "Cannot read header since it has already been read.");
181  throw(GlfException(myStatus));
182  return(false);
183  }
184 
185  if(header.read(myFilePtr))
186  {
187  // The header has now been successfully read.
188  myNextSection = REF_SECTION;
189  myStatus = GlfStatus::SUCCESS;
190  return(true);
191  }
192  myStatus.setStatus(GlfStatus::UNKNOWN,
193  "Failed to read the header.");
194  throw(GlfException(myStatus));
195  return(false);
196 }
197 
198 
199 // Write the header to the currently opened file.
201 {
202  if(myIsOpenForWrite == false)
203  {
204  // File is not open for write
205  // -OR-
206  // The header has already been written.
208  "Cannot write header since the file is not open for writing");
209  throw(GlfException(myStatus));
210  return(false);
211  }
212 
213  if(myNextSection != HEADER)
214  {
215  // The header has already been written.
217  "Cannot write header since it has already been written");
218  throw(GlfException(myStatus));
219  return(false);
220  }
221 
222  if(header.write(myFilePtr))
223  {
224  // The header has now been successfully written.
225  myNextSection = REF_SECTION;
226  myStatus = GlfStatus::SUCCESS;
227  return(true);
228  }
229 
230  // return the status.
231  myStatus.setStatus(GlfStatus::UNKNOWN,
232  "Failed to write the header.");
233  throw(GlfException(myStatus));
234  return(false);
235 }
236 
237 
238 // Gets the next reference section from the file & stores it in the
239 // passed in section. It will read until a new section is found.
241 {
242  if(myIsOpenForRead == false)
243  {
244  // File is not open for read
246  "Cannot read reference section since the file is not open for reading");
247  throw(GlfException(myStatus));
248  return(false);
249  }
250 
251  if(myNextSection == HEADER)
252  {
253  // The header has not yet been read.
254  // TODO - maybe just read the header.
256  "Cannot read reference section since the header has not been read.");
257  throw(GlfException(myStatus));
258  return(false);
259  }
260 
261  // Keep reading until the next section is found.
262  if(myNextSection == RECORD)
263  {
264  GlfRecord record;
265  while(getNextRecord(record))
266  {
267  // Nothing to do, with the record.
268  }
269  }
270 
271  // Check for end of file. If end of file, return false.
272  if(isEOF())
273  {
274  return(false);
275  }
276 
277  if(myNextSection != REF_SECTION)
278  {
279  // Failed reading all the records, so throw exception.
280  myStatus.setStatus(GlfStatus::FAIL_IO,
281  "Failed to get to a reference section.");
282  throw(GlfException(myStatus));
283  return(false);
284  }
285 
286  // Ready to read the section:
287  if(refSection.read(myFilePtr))
288  {
289  myStatus = GlfStatus::SUCCESS;
290  // Next a record should be read.
291  myNextSection = RECORD;
292  return(true);
293  }
294 
295  // If it is the EOF, just return false.
296  if(isEOF())
297  {
298  return(false);
299  }
300  myStatus.setStatus(GlfStatus::UNKNOWN,
301  "Failed reading a reference section from the file.");
302  throw(GlfException(myStatus));
303  return(false);
304 }
305 
306 
307 // Write the reference section to the file.
309 {
310  if(myIsOpenForWrite == false)
311  {
312  // File is not open for write
314  "Cannot write reference section since the file is not open for writing");
315  throw(GlfException(myStatus));
316  return(false);
317  }
318 
319  if(myNextSection == HEADER)
320  {
321  // The header has not been written.
323  "Cannot write reference section since the header has not been written");
324  throw(GlfException(myStatus));
325  return(false);
326  }
327 
328  if(myNextSection == RECORD)
329  {
330  // did not write a end marker record, so write one now.
331  if(!writeRecord(myEndMarker))
332  {
333  // Failed to write the end marker record.
334  myStatus.setStatus(GlfStatus::FAIL_IO,
335  "Failed to write end of chromosome/section marker.");
336  throw(GlfException(myStatus));
337  return(false);
338  }
339  }
340 
341  if(myNextSection != REF_SECTION)
342  {
343  // Not ready to write a reference section.
344  myStatus.setStatus(GlfStatus::FAIL_IO,
345  "Not ready for a chromosome/section header.");
346  throw(GlfException(myStatus));
347  return(false);
348  }
349 
350  if(refSection.write(myFilePtr))
351  {
352  myStatus = GlfStatus::SUCCESS;
353  // A reference section has now been successfully written.
354  myNextSection = RECORD;
355  return(true);
356  }
357 
358  // return the status.
359  myStatus.setStatus(GlfStatus::UNKNOWN,
360  "Failed writing a reference section to the file.");
361  throw(GlfException(myStatus));
362  return(false);
363 }
364 
365 
366 // Gets the next reference section from the file & stores it in the
367 // passed in record.
369 {
370  if(myIsOpenForRead == false)
371  {
372  // File is not open for read
374  "Cannot read reference section since the file is not open for reading");
375  throw(GlfException(myStatus));
376  return(false);
377  }
378 
379  if(myNextSection == HEADER)
380  {
381  // The header has not yet been read.
383  "Cannot read reference section since the header has not been read.");
384  throw(GlfException(myStatus));
385  return(false);
386  }
387 
388  if(myNextSection == REF_SECTION)
389  {
390  // The reference section has not yet been read.
391  // TODO - maybe just read the reference section.
393  "Cannot read record since a reference section has not been read.");
394  throw(GlfException(myStatus));
395  return(false);
396  }
397 
398  // Check for end of file. If end of file, return false.
399  if(isEOF())
400  {
401  return(false);
402  }
403 
404  // Read the record.
405  if(record.read(myFilePtr))
406  {
407  myStatus = GlfStatus::SUCCESS;
408  if(record.getRecordType() != 0)
409  {
410  return(true);
411  }
412  else
413  {
414  // Not an error, so no exception thrown, but no more records.
415  // The next thing is a reference section.
416  myNextSection = REF_SECTION;
417  return(false);
418  }
419  }
420 
421  myStatus.setStatus(GlfStatus::UNKNOWN,
422  "Failed reading a record from the file.");
423  throw(GlfException(myStatus));
424  return(false);
425 }
426 
427 
428 // Write the reference section to the file.
429 bool GlfFile::writeRecord(const GlfRecord& record)
430 {
431  if(myIsOpenForWrite == false)
432  {
433  // File is not open for write
434  // -OR-
435  // The header has already been written.
437  "Cannot write record since the file is not open for writing");
438  throw(GlfException(myStatus));
439  return(false);
440  }
441 
442  if(myNextSection == HEADER)
443  {
444  // The header has not been written.
446  "Cannot write record since the header has not been written");
447  throw(GlfException(myStatus));
448  return(false);
449  }
450 
451  if(myNextSection != RECORD)
452  {
453  // The header has not been written.
455  "Cannot write record since a reference section has not been written");
456  throw(GlfException(myStatus));
457  return(false);
458  }
459 
460  if(record.write(myFilePtr))
461  {
462  myStatus = GlfStatus::SUCCESS;
463  // The record has now been successfully written.
464 
465  // Check if it was the end marker - if so, set that next a
466  // reference section is expected.
467  if(record.getRecordType() == 0)
468  {
469  myNextSection = REF_SECTION;
470  }
471  return(true);
472  }
473 
474  // return the status.
475  myStatus.setStatus(GlfStatus::UNKNOWN,
476  "Failed writing a record to the file.");
477  throw(GlfException(myStatus));
478  return(false);
479 }
480 
481 
482 // Return the number of records that have been read/written so far.
484 {
485  return(myRecordCount);
486 }
487 
488 
489 // Reset variables for each file.
490 void GlfFile::resetFile()
491 {
492  // Close the file.
493  if (myFilePtr != NULL)
494  {
495  // If we already have an open file, close it.
496 
497  // First check if this is a write file and an end record needs to
498  // be written, which is the case if the state is RECORD.
499  if(myIsOpenForWrite && (myNextSection == RECORD))
500  {
501  if(!writeRecord(myEndMarker))
502  {
503  // Failed to write the end marker record.
504  myStatus.setStatus(GlfStatus::FAIL_IO,
505  "Failed to write end of chromosome/section marker.");
506  throw(GlfException(myStatus));
507  }
508  }
509  ifclose(myFilePtr);
510  myFilePtr = NULL;
511  }
512 
513  myIsOpenForRead = false;
514  myIsOpenForWrite = false;
515  myRecordCount = 0;
516  myStatus = GlfStatus::SUCCESS;
517  myNextSection = HEADER;
518 }
519 
520 
521 // Default Constructor.
523 {
524 }
525 
526 
527 // Constructor that opens the specified file for read.
528 GlfFileReader::GlfFileReader(const char* filename)
529 {
530  if(!openForRead(filename))
531  {
532  // Failed to open for reading - print error and abort.
533  fprintf(stderr, "%s\n", getStatusMessage());
534  std::cerr << "FAILURE - EXITING!!!" << std::endl;
535  exit(-1);
536  }
537 }
538 
539 
540 GlfFileReader::~GlfFileReader()
541 {
542 }
543 
544 
545 // Default Constructor.
547 {
548 }
549 
550 
551 // Constructor that opens the specified file for write.
552 GlfFileWriter::GlfFileWriter(const char* filename)
553 {
554  if(!openForWrite(filename))
555  {
556  // Failed to open for reading - print error and abort.
557  fprintf(stderr, "%s\n", getStatusMessage());
558  std::cerr << "FAILURE - EXITING!!!" << std::endl;
559  exit(-1);
560  }
561 }
562 
563 
564 GlfFileWriter::~GlfFileWriter()
565 {
566 }
int ifeof(IFILE file)
Check to see if we have reached the EOF (returns 0 if not EOF).
Definition: InputFile.h:654
IFILE ifopen(const char *filename, const char *mode, InputFile::ifileCompression compressionMode=InputFile::DEFAULT)
Open a file with the specified name and mode, using a filename of "-" to indicate stdin/stdout.
Definition: InputFile.h:562
int ifclose(IFILE &file)
Close the file.
Definition: InputFile.h:580
GlfException objects should be thrown by functions that operate on Glf files for exceptions.
Definition: GlfException.h:28
GlfFileReader()
Default Constructor.
Definition: GlfFile.cpp:522
GlfFileWriter()
Default Constructor.
Definition: GlfFile.cpp:546
bool getNextRefSection(GlfRefSection &refSection)
Gets the next reference section from the file & stores it in the passed in section,...
Definition: GlfFile.cpp:240
virtual ~GlfFile()
Closes the file if there is one open, adding an end marker record if there is a previous section and ...
Definition: GlfFile.cpp:59
bool writeRefSection(const GlfRefSection &refSection)
Write the reference section to the file, adding an end marker record if there is a previous section a...
Definition: GlfFile.cpp:308
const char * getStatusMessage()
Get the Status of the last call that sets status.
Definition: GlfFile.h:135
bool openForWrite(const char *filename, bool compressed=true)
Open a glf file for writing with the specified filename.
Definition: GlfFile.cpp:109
bool getNextRecord(GlfRecord &record)
Gets the nextrecord from the file & stores it in the passed in record.
Definition: GlfFile.cpp:368
OpenType
Enum for indicating whether to open the file for read or write.
Definition: GlfFile.h:33
@ READ
open for reading.
Definition: GlfFile.h:34
GlfFile()
Default Constructor.
Definition: GlfFile.cpp:23
bool openForRead(const char *filename)
Open a glf file for reading with the specified filename.
Definition: GlfFile.cpp:66
void close()
Close the file if there is one open, adding an end marker record if there is a previous section and o...
Definition: GlfFile.cpp:142
bool writeHeader(GlfHeader &header)
Writes the specified header into the file.
Definition: GlfFile.cpp:200
bool readHeader(GlfHeader &header)
Reads the header section from the file and stores it in the passed in header.
Definition: GlfFile.cpp:165
uint32_t getCurrentRecordCount()
Return the number of records that have been read/written so far.
Definition: GlfFile.cpp:483
bool isEOF()
Returns whether or not the end of the file has been reached.
Definition: GlfFile.cpp:152
bool writeRecord(const GlfRecord &record)
Writes the specified record into the file.
Definition: GlfFile.cpp:429
This class allows a user to easily get/set the fields in a GLF header.
Definition: GlfHeader.h:30
bool read(IFILE filePtr)
Read the header from the specified file (file MUST be in the correct position for reading the header)...
Definition: GlfHeader.cpp:80
bool write(IFILE filePtr) const
Write the header to the specified file.
Definition: GlfHeader.cpp:141
This class allows a user to easily get/set the fields in a GLF record.
Definition: GlfRecord.h:29
int getRecordType() const
Return the record type.
Definition: GlfRecord.h:126
bool write(IFILE filePtr) const
Write the record to the specified file.
Definition: GlfRecord.cpp:113
bool read(IFILE filePtr)
Read the record from the specified file (file MUST be in the correct position for reading a record).
Definition: GlfRecord.cpp:65
This class allows a user to easily get/set the fields in a GLF section/chromosome header.
Definition: GlfRefSection.h:32
bool read(IFILE filePtr)
Read the refSection from the specified file (file MUST be in the correct position for reading a refSe...
bool write(IFILE filePtr) const
Write the refSection to the specified file.
void setStatus(Status newStatus, const char *newMessage)
Set the status with the specified values.
Definition: GlfStatus.cpp:74
@ FAIL_ORDER
method failed because it was called out of order, like trying to read a file without opening it for r...
Definition: GlfStatus.h:35
@ UNKNOWN
unknown result (default value should never be used)
Definition: GlfStatus.h:33
@ SUCCESS
method completed successfully.
Definition: GlfStatus.h:32
@ FAIL_IO
method failed due to an I/O issue.
Definition: GlfStatus.h:34
@ BGZF
bgzf file.
Definition: InputFile.h:48
@ UNCOMPRESSED
uncompressed file.
Definition: InputFile.h:46