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;
}
|