/**************************************************************************\ * * This file is part of the Coin 3D visualization library. * Copyright (C) 1998-2007 by Systems in Motion. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * ("GPL") version 2 as published by the Free Software Foundation. * See the file LICENSE.GPL at the root directory of this source * distribution for additional information about the GNU GPL. * * For using Coin with software that can not be combined with the GNU * GPL, and for taking advantage of the additional benefits of our * support services, please contact Systems in Motion about acquiring * a Coin Professional Edition License. * * See http://www.coin3d.org/ for more information. * * Systems in Motion, Postboks 1283, Pirsenteret, 7462 Trondheim, NORWAY. * http://www.sim.no/ sales@sim.no coin-support@coin3d.org * \**************************************************************************/ #include "SoInput_Reader.h" #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif // HAVE_CONFIG_H #ifdef HAVE_UNISTD_H #include // dup() #endif // HAVE_UNISTD_H #ifdef HAVE_IO_H #include // Win32 dup() #endif // HAVE_IO_H #ifdef HAVE_SYS_STAT_H #include #endif #include "gzmemio.h" // We don't want to include bzlib.h, so we just define the constants // we use here #ifndef BZ_OK #define BZ_OK 0 #endif // BZ_OK #ifndef BZ_STREAM_END #define BZ_STREAM_END 4 #endif // BZ_STREAM_END #ifdef HAVE__FILENO #define fileno(a) _fileno(a) #endif // HAVE__FILENO #ifdef HAVE__DUP #define dup(a) _dup(a) #endif // HAVE__DUP // // abstract class // SoInput_Reader::SoInput_Reader(void) : dummyname("") { } SoInput_Reader::~SoInput_Reader() { } const SbString & SoInput_Reader::getFilename(void) { return this->dummyname; } FILE * SoInput_Reader::getFilePointer(void) { return NULL; } // creates the correct reader based on the file type in fp (will // examine the file header). If fullname is empty, it's assumed that // file FILE pointer is passed from the user, and that we cannot // necessarily find the file handle. SoInput_Reader * SoInput_Reader::createReader(FILE * fp, const SbString & fullname) { SoInput_Reader * reader = NULL; SbBool trycompression = FALSE; #ifdef HAVE_FSTAT // need to make sure stream is seekable to enable compression // support, because we need to fseek() the stream int fn = fileno(fp); struct stat sb; if ( fstat(fn, &sb) == 0 ) { if ( sb.st_mode & S_IFREG ) { // regular file trycompression = TRUE; } } #endif // HAVE_FSTAT if ( trycompression ) { unsigned char header[4]; long offset = ftell(fp); size_t siz = fread(header, 1, 4, fp); (void) fseek(fp, offset, SEEK_SET); fflush(fp); // needed since we fetch the file descriptor later if (header[0] == 'B' && header[1] == 'Z') { if (!cc_bzglue_available()) { SoDebugError::postWarning("SoInput_Reader::createReader", "File seems to be in bzip2 format, but " "libbz2 support is not available."); } else { int bzerror = BZ_OK; void * bzfp = cc_bzglue_BZ2_bzReadOpen(&bzerror, fp, 0, 0, NULL, 0); if ((bzerror == BZ_OK) && (bzfp != NULL)) { reader = new SoInput_BZ2FileReader(fullname.getString(), bzfp); } else { SoDebugError::postWarning("SoInput_Reader::createReader", "Unable to open bzip2 file."); } } } if ((reader == NULL) && (header[0] == 0x1f) && (header[1] == 0x8b)) { if (!cc_zlibglue_available()) { SoDebugError::postWarning("SoInput_Reader::createReader", "File seems to be in gzip format, but " "zlib support is not available."); } else { int fd = fileno(fp); // need to use dup() if we didn't open the file since gzdclose // will close it if (fd >= 0 && fullname.getLength() && fullname != "") fd = dup(fd); if (fd >= 0) { void * gzfp = 0; #ifdef HAVE_GZDOPEN gzfp = cc_zlibglue_gzdopen(fd, "rb"); #else // gzdopen() after reading from the compressed file does not work on Mac OS X if (fullname.getLength()) { gzfp = cc_zlibglue_gzopen(fullname.getString(), "rb"); } else { SoDebugError::postWarning("SoInput_Reader::createReader", "Passing FILE* for gzipped files on " "Mac OS X not allowed, unable to open."); } #endif if (gzfp) { reader = new SoInput_GZFileReader(fullname.getString(), gzfp); } } else { SoDebugError::postWarning("SoInput_Reader::createReader", "Unable to create file descriptor from stream."); } } } } if (reader == NULL) { reader = new SoInput_FileReader(fullname.getString(), fp); } return reader; } // // standard FILE * class // SoInput_FileReader::SoInput_FileReader(const char * const filenamearg, FILE * filepointer) { this->fp = filepointer; this->filename = filenamearg; } SoInput_FileReader::~SoInput_FileReader() { // Close files which are not a memory buffer nor the stdin and // which we do have a filename for (if we don't have a filename, // the FILE ptr was just passed in through setFilePointer() and // is the library programmer's responsibility). if (this->fp && (this->filename != "") && (this->filename.getLength())) { fclose(this->fp); } } SoInput_Reader::ReaderType SoInput_FileReader::getType(void) const { return REGULAR_FILE; } size_t SoInput_FileReader::readBuffer(char * buf, const size_t readlen) { return fread(buf, 1, readlen, this->fp); } const SbString & SoInput_FileReader::getFilename(void) { return this->filename; } FILE * SoInput_FileReader::getFilePointer(void) { return this->fp; } // // standard membuffer class // SoInput_MemBufferReader::SoInput_MemBufferReader(void * bufPointer, size_t bufSize) { this->buf = (char*) bufPointer; this->buflen = bufSize; this->bufpos = 0; } SoInput_MemBufferReader::~SoInput_MemBufferReader() { } SoInput_Reader::ReaderType SoInput_MemBufferReader::getType(void) const { return MEMBUFFER; } size_t SoInput_MemBufferReader::readBuffer(char * buffer, const size_t readlen) { size_t len = this->buflen - this->bufpos; if (len > readlen) len = readlen; memcpy(buffer, this->buf + this->bufpos, len); this->bufpos += len; return len; } // // gzip readers // // // gzipped membuffer class // SoInput_GZMemBufferReader::SoInput_GZMemBufferReader(void * bufPointer, size_t bufSize) { // FIXME: the bufSize cast (as size_t can be 64 bits wide) is there // to humour the interface of gzmemio -- should really be fixed // in the interface instead. 20050525 mortene. this->gzmfile = cc_gzm_open((uint8_t *)bufPointer, (uint32_t)bufSize); this->buf = bufPointer; } SoInput_GZMemBufferReader::~SoInput_GZMemBufferReader() { cc_gzm_close(this->gzmfile); } SoInput_Reader::ReaderType SoInput_GZMemBufferReader::getType(void) const { return GZMEMBUFFER; } size_t SoInput_GZMemBufferReader::readBuffer(char * buffer, const size_t readlen) { // FIXME: about the cast; see note about the call to cc_gzm_open() // above. 20050525 mortene. return cc_gzm_read(this->gzmfile, buffer, (uint32_t)readlen); } // // gzFile class // SoInput_GZFileReader::SoInput_GZFileReader(const char * const filenamearg, void * fp) { this->gzfp = fp; this->filename = filenamearg; } SoInput_GZFileReader::~SoInput_GZFileReader() { assert(this->gzfp); cc_zlibglue_gzclose(this->gzfp); } SoInput_Reader::ReaderType SoInput_GZFileReader::getType(void) const { return GZFILE; } size_t SoInput_GZFileReader::readBuffer(char * buf, const size_t readlen) { // FIXME: about the cast; see note about the call to cc_gzm_open() // above. 20050525 mortene. return cc_zlibglue_gzread(this->gzfp, (void*) buf, (uint32_t)readlen); } const SbString & SoInput_GZFileReader::getFilename(void) { return this->filename; } // // bzFile class // SoInput_BZ2FileReader::SoInput_BZ2FileReader(const char * const filenamearg, void * fp) { this->bzfp = fp; this->filename = filenamearg; } SoInput_BZ2FileReader::~SoInput_BZ2FileReader() { if (this->bzfp) { int bzerror = BZ_OK; cc_bzglue_BZ2_bzReadClose(&bzerror, this->bzfp); } } SoInput_Reader::ReaderType SoInput_BZ2FileReader::getType(void) const { return BZ2FILE; } size_t SoInput_BZ2FileReader::readBuffer(char * buf, const size_t readlen) { if (this->bzfp == NULL) { return 0; } int bzerror = BZ_OK; // FIXME: about the cast; see note about the call to cc_gzm_open() // above. 20050525 mortene. int ret = cc_bzglue_BZ2_bzRead(&bzerror, this->bzfp, buf, (uint32_t)readlen); if ((bzerror != BZ_OK) && (bzerror != BZ_STREAM_END)) { ret = -1; cc_bzglue_BZ2_bzReadClose(&bzerror, this->bzfp); this->bzfp = NULL; } return ret; } const SbString & SoInput_BZ2FileReader::getFilename(void) { return this->filename; } #undef BZ_OK #undef BZ_STREAM_END