src/random_access_gzFile.cpp
60c84217
 // random_access_gzFile.cpp
 // presents C-style calls based on an ifstream-derived C++ class
 //
 // like gzio.c from the zlib distro,
 // but for dealing with reading >2GB files in win32, and efficient random access.
 // Copyright (C) Insilicos LLC 2008, ALl Rights Reserved.
 // For conditions of distribution and use, see copyright notice in zlib.h
 //
 // based on:
 /* gzio.c -- IO on .gz files
 * Copyright (C) 1995-2005 Jean-loup Gailly.
 * For conditions of distribution and use, see copyright notice in zlib.h
 */
 
 // efficient random access stuff based on
 /* zran.c -- example of zlib/gzip stream indexing and random access
 * Copyright (C) 2005 Mark Adler
 * For conditions of distribution and use, see copyright notice in zlib.h
 Version 1.0  29 May 2005  Mark Adler */
 
 #include "random_access_gzFile.h"
 #include "zlib.h"
 
 struct random_access_gzFile {
 	pwiz::util::random_access_compressed_ifstream *istrm;
 };
 
 /* ===========================================================================
 Opens a gzip (.gz) file for reading or writing. The mode parameter
 is as in fopen ("rb" or "wb"). The file is given either by file descriptor
 or path name (if fd == -1).
 random_access_gzopen returns NULL if the file could not be opened or if there was
 insufficient memory to allocate the (de)compression state; errno
 can be checked to distinguish the two cases (if errno is zero, the
 zlib error is Z_MEM_ERROR).
 */
 random_access_gzFile *random_access_gzopen (const char *path)
 {
 	random_access_gzFile *ret = new random_access_gzFile;
 	if (ret) {
 		ret->istrm = new pwiz::util::random_access_compressed_ifstream(path);
 		if (ret->istrm && !*(ret->istrm)) {
 			delete ret->istrm;
 			delete ret;
 			ret = NULL;
 		} 
 	}
 	return ret;
 }
 
 /* ===========================================================================
 Reads the given number of uncompressed bytes from the compressed file.
 gzread returns the number of bytes actually read (0 for end of file).
 */
 int random_access_gzread (random_access_gzFile *file,
 				 char *buf,
 				 unsigned len)
 {
 	file->istrm->clear(); // clear any stale failbit
 	file->istrm->read((char *)buf,len);
 	return file->istrm->gcount();
 }
 /* ===========================================================================
 Reads one byte from the compressed file. gzgetc returns this byte
 or -1 in case of end of file or error.
 */
 int random_access_gzgetc(random_access_gzFile *file)
 {
 	char c;
 	file->istrm->clear(); // clear any stale failbit
 	file->istrm->read( &c, 1);
 	return (file->istrm->gcount() == 1) ? (int)c : -1;
 }
 
 /* ===========================================================================
 Reads bytes from the compressed file until len-1 characters are
 read, or a newline character is read and transferred to buf, or an
 end-of-file condition is encountered.  The string is then terminated
 with a null character.
 gzgets returns buf, or Z_NULL in case of error.
 */
 char * random_access_gzgets(random_access_gzFile *file, char *buf, int len) {
 	file->istrm->clear(); // clear any stale failbit
 	file->istrm->getline(buf,len); // this does NOT retain the \n
 	int got = file->istrm->gcount();
 	if (got && (got < (len-1)) && !file->istrm->fail() && !file->istrm->eof()) {
 		// looks like a newline was read then discarded
 		buf[(got-1)] = '\n';
 		buf[got] = 0;
 	}
 	return (*buf?buf:NULL);
 }
 
 /* ===========================================================================
 Sets the starting position for the next gzread on the given
 compressed file. The offset represents a number of bytes in the
 gzseek returns the resulting offset location as measured in bytes from
 the beginning of the uncompressed stream, or -1 in case of error.
 NOTE - bpratt borrows zran code here for better performance
 */
 random_access_gzFile_off_t random_access_gzseek (random_access_gzFile *file,
 							   random_access_gzFile_off_t offset,
 							   int whence)
 {
 	if (file == NULL) {
 			return -1L;
 	}
 	file->istrm->clear(); // clear any stale error flags
 	switch (whence) {
 		case SEEK_SET:
 			file->istrm->seekg(boost::iostreams::offset_to_position(offset));
 			break;
 		case SEEK_CUR:
 			file->istrm->seekg(boost::iostreams::offset_to_position(offset),std::ios_base::cur);
 			break;
 		case SEEK_END:
 			file->istrm->seekg(boost::iostreams::offset_to_position(offset),std::ios_base::end);
 			break;
 	}
 	return file->istrm->tellg();
 }
 
 /* ===========================================================================
 Returns the starting position for the next gzread on the
 given compressed file. This position represents a number of bytes in the
 uncompressed data stream.
 */
 random_access_gzFile_off_t random_access_gztell(random_access_gzFile *file)
 {
 	return file?(random_access_gzFile_off_t)(file->istrm->tellg()):-1;
 }
 
 /* ===========================================================================
 Returns 1 when EOF has previously been detected reading the given
 input stream, otherwise zero.
 */
 int random_access_gzeof (random_access_gzFile *s)
 {
 	return s?s->istrm->eof():0;
 }
 
 /* ===========================================================================
 Returns 1 if reading and doing so transparently, otherwise zero.
 */
 int random_access_gzdirect(random_access_gzFile *file)
 {
 	if ((file == NULL) || (file->istrm == NULL)) {
 		return 0;
 	}
 	return !file->istrm->getCompressionType();
 }
 
 /* ===========================================================================
 Flushes all pending output if necessary, closes the compressed file
 and deallocates all the (de)compression state.
 */
 int random_access_gzclose (random_access_gzFile *file)
 {
 	if (file == NULL) {
 		return Z_STREAM_ERROR;
 	}
 	delete file->istrm;
 	delete file;
 	return 0;
 }