Blame libtiff/tif_stream.cxx

Packit 7838c8
/* $Id: tif_stream.cxx,v 1.13 2015-05-28 01:50:22 bfriesen Exp $ */
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * Copyright (c) 1988-1996 Sam Leffler
Packit 7838c8
 * Copyright (c) 1991-1996 Silicon Graphics, Inc.
Packit 7838c8
 *
Packit 7838c8
 * Permission to use, copy, modify, distribute, and sell this software and 
Packit 7838c8
 * its documentation for any purpose is hereby granted without fee, provided
Packit 7838c8
 * that (i) the above copyright notices and this permission notice appear in
Packit 7838c8
 * all copies of the software and related documentation, and (ii) the names of
Packit 7838c8
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
Packit 7838c8
 * publicity relating to the software without the specific, prior written
Packit 7838c8
 * permission of Sam Leffler and Silicon Graphics.
Packit 7838c8
 * 
Packit 7838c8
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
Packit 7838c8
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
Packit 7838c8
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
Packit 7838c8
 * 
Packit 7838c8
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
Packit 7838c8
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
Packit 7838c8
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit 7838c8
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
Packit 7838c8
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
Packit 7838c8
 * OF THIS SOFTWARE.
Packit 7838c8
 */
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * TIFF Library UNIX-specific Routines.
Packit 7838c8
 */
Packit 7838c8
#include "tiffiop.h"
Packit 7838c8
#include <iostream>
Packit 7838c8
Packit 7838c8
#ifndef __VMS
Packit 7838c8
using namespace std;
Packit 7838c8
#endif
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
  ISO C++ uses a 'std::streamsize' type to define counts.  This makes
Packit 7838c8
  it similar to, (but perhaps not the same as) size_t.
Packit 7838c8
Packit 7838c8
  The std::ios::pos_type is used to represent stream positions as used
Packit 7838c8
  by tellg(), tellp(), seekg(), and seekp().  This makes it similar to
Packit 7838c8
  (but perhaps not the same as) 'off_t'.  The std::ios::streampos type
Packit 7838c8
  is used for character streams, but is documented to not be an
Packit 7838c8
  integral type anymore, so it should *not* be assigned to an integral
Packit 7838c8
  type.
Packit 7838c8
Packit 7838c8
  The std::ios::off_type is used to specify relative offsets needed by
Packit 7838c8
  the variants of seekg() and seekp() which accept a relative offset
Packit 7838c8
  argument.
Packit 7838c8
Packit 7838c8
  Useful prototype knowledge:
Packit 7838c8
Packit 7838c8
  Obtain read position
Packit 7838c8
    ios::pos_type basic_istream::tellg()
Packit 7838c8
Packit 7838c8
  Set read position
Packit 7838c8
    basic_istream& basic_istream::seekg(ios::pos_type)
Packit 7838c8
    basic_istream& basic_istream::seekg(ios::off_type, ios_base::seekdir)
Packit 7838c8
Packit 7838c8
  Read data
Packit 7838c8
    basic_istream& istream::read(char *str, streamsize count)
Packit 7838c8
Packit 7838c8
  Number of characters read in last unformatted read
Packit 7838c8
    streamsize istream::gcount();
Packit 7838c8
Packit 7838c8
  Obtain write position
Packit 7838c8
    ios::pos_type basic_ostream::tellp()
Packit 7838c8
Packit 7838c8
  Set write position
Packit 7838c8
    basic_ostream& basic_ostream::seekp(ios::pos_type)
Packit 7838c8
    basic_ostream& basic_ostream::seekp(ios::off_type, ios_base::seekdir)
Packit 7838c8
Packit 7838c8
  Write data
Packit 7838c8
    basic_ostream& ostream::write(const char *str, streamsize count)
Packit 7838c8
*/
Packit 7838c8
Packit 7838c8
struct tiffis_data;
Packit 7838c8
struct tiffos_data;
Packit 7838c8
Packit 7838c8
extern "C" {
Packit 7838c8
Packit 7838c8
	static tmsize_t _tiffosReadProc(thandle_t, void*, tmsize_t);
Packit 7838c8
	static tmsize_t _tiffisReadProc(thandle_t fd, void* buf, tmsize_t size);
Packit 7838c8
	static tmsize_t _tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size);
Packit 7838c8
	static tmsize_t _tiffisWriteProc(thandle_t, void*, tmsize_t);
Packit 7838c8
	static uint64   _tiffosSeekProc(thandle_t fd, uint64 off, int whence);
Packit 7838c8
	static uint64   _tiffisSeekProc(thandle_t fd, uint64 off, int whence);
Packit 7838c8
	static uint64   _tiffosSizeProc(thandle_t fd);
Packit 7838c8
	static uint64   _tiffisSizeProc(thandle_t fd);
Packit 7838c8
	static int      _tiffosCloseProc(thandle_t fd);
Packit 7838c8
	static int      _tiffisCloseProc(thandle_t fd);
Packit 7838c8
	static int 	_tiffDummyMapProc(thandle_t , void** base, toff_t* size );
Packit 7838c8
	static void     _tiffDummyUnmapProc(thandle_t , void* base, toff_t size );
Packit 7838c8
	static TIFF*    _tiffStreamOpen(const char* name, const char* mode, void *fd);
Packit 7838c8
Packit 7838c8
struct tiffis_data
Packit 7838c8
{
Packit 7838c8
	istream	*stream;
Packit 7838c8
        ios::pos_type start_pos;
Packit 7838c8
};
Packit 7838c8
Packit 7838c8
struct tiffos_data
Packit 7838c8
{
Packit 7838c8
	ostream	*stream;
Packit 7838c8
	ios::pos_type start_pos;
Packit 7838c8
};
Packit 7838c8
Packit 7838c8
static tmsize_t
Packit 7838c8
_tiffosReadProc(thandle_t, void*, tmsize_t)
Packit 7838c8
{
Packit 7838c8
        return 0;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static tmsize_t
Packit 7838c8
_tiffisReadProc(thandle_t fd, void* buf, tmsize_t size)
Packit 7838c8
{
Packit 7838c8
        tiffis_data	*data = reinterpret_cast<tiffis_data *>(fd);
Packit 7838c8
Packit 7838c8
        // Verify that type does not overflow.
Packit 7838c8
        streamsize request_size = size;
Packit 7838c8
        if (static_cast<tmsize_t>(request_size) != size)
Packit 7838c8
          return static_cast<tmsize_t>(-1);
Packit 7838c8
Packit 7838c8
        data->stream->read((char *) buf, request_size);
Packit 7838c8
Packit 7838c8
        return static_cast<tmsize_t>(data->stream->gcount());
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static tmsize_t
Packit 7838c8
_tiffosWriteProc(thandle_t fd, void* buf, tmsize_t size)
Packit 7838c8
{
Packit 7838c8
	tiffos_data	*data = reinterpret_cast<tiffos_data *>(fd);
Packit 7838c8
	ostream		*os = data->stream;
Packit 7838c8
	ios::pos_type	pos = os->tellp();
Packit 7838c8
Packit 7838c8
        // Verify that type does not overflow.
Packit 7838c8
        streamsize request_size = size;
Packit 7838c8
        if (static_cast<tmsize_t>(request_size) != size)
Packit 7838c8
          return static_cast<tmsize_t>(-1);
Packit 7838c8
Packit 7838c8
	os->write(reinterpret_cast<const char *>(buf), request_size);
Packit 7838c8
Packit 7838c8
	return static_cast<tmsize_t>(os->tellp() - pos);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static tmsize_t
Packit 7838c8
_tiffisWriteProc(thandle_t, void*, tmsize_t)
Packit 7838c8
{
Packit 7838c8
	return 0;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static uint64
Packit 7838c8
_tiffosSeekProc(thandle_t fd, uint64 off, int whence)
Packit 7838c8
{
Packit 7838c8
	tiffos_data	*data = reinterpret_cast<tiffos_data *>(fd);
Packit 7838c8
	ostream		*os = data->stream;
Packit 7838c8
Packit 7838c8
	// if the stream has already failed, don't do anything
Packit 7838c8
	if( os->fail() )
Packit 7838c8
		return static_cast<uint64>(-1);
Packit 7838c8
Packit 7838c8
	switch(whence) {
Packit 7838c8
	case SEEK_SET:
Packit 7838c8
		{
Packit 7838c8
			// Compute 64-bit offset
Packit 7838c8
			uint64 new_offset = static_cast<uint64>(data->start_pos) + off;
Packit 7838c8
Packit 7838c8
			// Verify that value does not overflow
Packit 7838c8
			ios::off_type offset = static_cast<ios::off_type>(new_offset);
Packit 7838c8
			if (static_cast<uint64>(offset) != new_offset)
Packit 7838c8
				return static_cast<uint64>(-1);
Packit 7838c8
			
Packit 7838c8
			os->seekp(offset, ios::beg);
Packit 7838c8
		break;
Packit 7838c8
		}
Packit 7838c8
	case SEEK_CUR:
Packit 7838c8
		{
Packit 7838c8
			// Verify that value does not overflow
Packit 7838c8
			ios::off_type offset = static_cast<ios::off_type>(off);
Packit 7838c8
			if (static_cast<uint64>(offset) != off)
Packit 7838c8
				return static_cast<uint64>(-1);
Packit 7838c8
Packit 7838c8
			os->seekp(offset, ios::cur);
Packit 7838c8
			break;
Packit 7838c8
		}
Packit 7838c8
	case SEEK_END:
Packit 7838c8
		{
Packit 7838c8
			// Verify that value does not overflow
Packit 7838c8
			ios::off_type offset = static_cast<ios::off_type>(off);
Packit 7838c8
			if (static_cast<uint64>(offset) != off)
Packit 7838c8
				return static_cast<uint64>(-1);
Packit 7838c8
Packit 7838c8
			os->seekp(offset, ios::end);
Packit 7838c8
			break;
Packit 7838c8
		}
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	// Attempt to workaround problems with seeking past the end of the
Packit 7838c8
	// stream.  ofstream doesn't have a problem with this but
Packit 7838c8
	// ostrstream/ostringstream does. In that situation, add intermediate
Packit 7838c8
	// '\0' characters.
Packit 7838c8
	if( os->fail() ) {
Packit 7838c8
#ifdef __VMS
Packit 7838c8
		int		old_state;
Packit 7838c8
#else
Packit 7838c8
		ios::iostate	old_state;
Packit 7838c8
#endif
Packit 7838c8
		ios::pos_type	origin;
Packit 7838c8
Packit 7838c8
		old_state = os->rdstate();
Packit 7838c8
		// reset the fail bit or else tellp() won't work below
Packit 7838c8
		os->clear(os->rdstate() & ~ios::failbit);
Packit 7838c8
		switch( whence ) {
Packit 7838c8
			case SEEK_SET:
Packit 7838c8
                        default:
Packit 7838c8
				origin = data->start_pos;
Packit 7838c8
				break;
Packit 7838c8
			case SEEK_CUR:
Packit 7838c8
				origin = os->tellp();
Packit 7838c8
				break;
Packit 7838c8
			case SEEK_END:
Packit 7838c8
				os->seekp(0, ios::end);
Packit 7838c8
				origin = os->tellp();
Packit 7838c8
				break;
Packit 7838c8
		}
Packit 7838c8
		// restore original stream state
Packit 7838c8
		os->clear(old_state);	
Packit 7838c8
Packit 7838c8
		// only do something if desired seek position is valid
Packit 7838c8
		if( (static_cast<uint64>(origin) + off) > static_cast<uint64>(data->start_pos) ) {
Packit 7838c8
			uint64	num_fill;
Packit 7838c8
Packit 7838c8
			// clear the fail bit 
Packit 7838c8
			os->clear(os->rdstate() & ~ios::failbit);
Packit 7838c8
Packit 7838c8
			// extend the stream to the expected size
Packit 7838c8
			os->seekp(0, ios::end);
Packit 7838c8
			num_fill = (static_cast<uint64>(origin)) + off - os->tellp();
Packit 7838c8
			for( uint64 i = 0; i < num_fill; i++ )
Packit 7838c8
				os->put('\0');
Packit 7838c8
Packit 7838c8
			// retry the seek
Packit 7838c8
			os->seekp(static_cast<ios::off_type>(static_cast<uint64>(origin) + off), ios::beg);
Packit 7838c8
		}
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	return static_cast<uint64>(os->tellp());
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static uint64
Packit 7838c8
_tiffisSeekProc(thandle_t fd, uint64 off, int whence)
Packit 7838c8
{
Packit 7838c8
	tiffis_data	*data = reinterpret_cast<tiffis_data *>(fd);
Packit 7838c8
Packit 7838c8
	switch(whence) {
Packit 7838c8
	case SEEK_SET:
Packit 7838c8
		{
Packit 7838c8
			// Compute 64-bit offset
Packit 7838c8
			uint64 new_offset = static_cast<uint64>(data->start_pos) + off;
Packit 7838c8
			
Packit 7838c8
			// Verify that value does not overflow
Packit 7838c8
			ios::off_type offset = static_cast<ios::off_type>(new_offset);
Packit 7838c8
			if (static_cast<uint64>(offset) != new_offset)
Packit 7838c8
				return static_cast<uint64>(-1);
Packit 7838c8
Packit 7838c8
			data->stream->seekg(offset, ios::beg);
Packit 7838c8
			break;
Packit 7838c8
		}
Packit 7838c8
	case SEEK_CUR:
Packit 7838c8
		{
Packit 7838c8
			// Verify that value does not overflow
Packit 7838c8
			ios::off_type offset = static_cast<ios::off_type>(off);
Packit 7838c8
			if (static_cast<uint64>(offset) != off)
Packit 7838c8
				return static_cast<uint64>(-1);
Packit 7838c8
Packit 7838c8
			data->stream->seekg(offset, ios::cur);
Packit 7838c8
			break;
Packit 7838c8
		}
Packit 7838c8
	case SEEK_END:
Packit 7838c8
		{
Packit 7838c8
			// Verify that value does not overflow
Packit 7838c8
			ios::off_type offset = static_cast<ios::off_type>(off);
Packit 7838c8
			if (static_cast<uint64>(offset) != off)
Packit 7838c8
				return static_cast<uint64>(-1);
Packit 7838c8
Packit 7838c8
			data->stream->seekg(offset, ios::end);
Packit 7838c8
			break;
Packit 7838c8
		}
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	return (uint64) (data->stream->tellg() - data->start_pos);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static uint64
Packit 7838c8
_tiffosSizeProc(thandle_t fd)
Packit 7838c8
{
Packit 7838c8
	tiffos_data	*data = reinterpret_cast<tiffos_data *>(fd);
Packit 7838c8
	ostream		*os = data->stream;
Packit 7838c8
	ios::pos_type	pos = os->tellp();
Packit 7838c8
	ios::pos_type	len;
Packit 7838c8
Packit 7838c8
	os->seekp(0, ios::end);
Packit 7838c8
	len = os->tellp();
Packit 7838c8
	os->seekp(pos);
Packit 7838c8
Packit 7838c8
	return (uint64) len;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static uint64
Packit 7838c8
_tiffisSizeProc(thandle_t fd)
Packit 7838c8
{
Packit 7838c8
	tiffis_data	*data = reinterpret_cast<tiffis_data *>(fd);
Packit 7838c8
	ios::pos_type	pos = data->stream->tellg();
Packit 7838c8
	ios::pos_type	len;
Packit 7838c8
Packit 7838c8
	data->stream->seekg(0, ios::end);
Packit 7838c8
	len = data->stream->tellg();
Packit 7838c8
	data->stream->seekg(pos);
Packit 7838c8
Packit 7838c8
	return (uint64) len;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static int
Packit 7838c8
_tiffosCloseProc(thandle_t fd)
Packit 7838c8
{
Packit 7838c8
	// Our stream was not allocated by us, so it shouldn't be closed by us.
Packit 7838c8
	delete reinterpret_cast<tiffos_data *>(fd);
Packit 7838c8
	return 0;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static int
Packit 7838c8
_tiffisCloseProc(thandle_t fd)
Packit 7838c8
{
Packit 7838c8
	// Our stream was not allocated by us, so it shouldn't be closed by us.
Packit 7838c8
	delete reinterpret_cast<tiffis_data *>(fd);
Packit 7838c8
	return 0;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static int
Packit 7838c8
_tiffDummyMapProc(thandle_t , void** base, toff_t* size )
Packit 7838c8
{
Packit 7838c8
	(void) base;
Packit 7838c8
	(void) size;
Packit 7838c8
	return (0);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
static void
Packit 7838c8
_tiffDummyUnmapProc(thandle_t , void* base, toff_t size )
Packit 7838c8
{
Packit 7838c8
	(void) base;
Packit 7838c8
	(void) size;
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
/*
Packit 7838c8
 * Open a TIFF file descriptor for read/writing.
Packit 7838c8
 */
Packit 7838c8
static TIFF*
Packit 7838c8
_tiffStreamOpen(const char* name, const char* mode, void *fd)
Packit 7838c8
{
Packit 7838c8
	TIFF*	tif;
Packit 7838c8
Packit 7838c8
	if( strchr(mode, 'w') ) {
Packit 7838c8
		tiffos_data	*data = new tiffos_data;
Packit 7838c8
		data->stream = reinterpret_cast<ostream *>(fd);
Packit 7838c8
		data->start_pos = data->stream->tellp();
Packit 7838c8
Packit 7838c8
		// Open for writing.
Packit 7838c8
		tif = TIFFClientOpen(name, mode,
Packit 7838c8
				reinterpret_cast<thandle_t>(data),
Packit 7838c8
				_tiffosReadProc,
Packit 7838c8
                                _tiffosWriteProc,
Packit 7838c8
				_tiffosSeekProc,
Packit 7838c8
                                _tiffosCloseProc,
Packit 7838c8
				_tiffosSizeProc,
Packit 7838c8
				_tiffDummyMapProc,
Packit 7838c8
                                _tiffDummyUnmapProc);
Packit 7838c8
	} else {
Packit 7838c8
		tiffis_data	*data = new tiffis_data;
Packit 7838c8
		data->stream = reinterpret_cast<istream *>(fd);
Packit 7838c8
		data->start_pos = data->stream->tellg();
Packit 7838c8
		// Open for reading.
Packit 7838c8
		tif = TIFFClientOpen(name, mode,
Packit 7838c8
				reinterpret_cast<thandle_t>(data),
Packit 7838c8
				_tiffisReadProc,
Packit 7838c8
                                _tiffisWriteProc,
Packit 7838c8
				_tiffisSeekProc,
Packit 7838c8
                                _tiffisCloseProc,
Packit 7838c8
				_tiffisSizeProc,
Packit 7838c8
				_tiffDummyMapProc,
Packit 7838c8
                                _tiffDummyUnmapProc);
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	return (tif);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
} /* extern "C" */
Packit 7838c8
Packit 7838c8
TIFF*
Packit 7838c8
TIFFStreamOpen(const char* name, ostream *os)
Packit 7838c8
{
Packit 7838c8
	// If os is either a ostrstream or ostringstream, and has no data
Packit 7838c8
	// written to it yet, then tellp() will return -1 which will break us.
Packit 7838c8
	// We workaround this by writing out a dummy character and
Packit 7838c8
	// then seek back to the beginning.
Packit 7838c8
	if( !os->fail() && static_cast<int>(os->tellp()) < 0 ) {
Packit 7838c8
		*os << '\0';
Packit 7838c8
		os->seekp(0);
Packit 7838c8
	}
Packit 7838c8
Packit 7838c8
	// NB: We don't support mapped files with streams so add 'm'
Packit 7838c8
	return _tiffStreamOpen(name, "wm", os);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
TIFF*
Packit 7838c8
TIFFStreamOpen(const char* name, istream *is)
Packit 7838c8
{
Packit 7838c8
	// NB: We don't support mapped files with streams so add 'm'
Packit 7838c8
	return _tiffStreamOpen(name, "rm", is);
Packit 7838c8
}
Packit 7838c8
Packit 7838c8
/* vim: set ts=8 sts=8 sw=8 noet: */
Packit 7838c8
/*
Packit 7838c8
 * Local Variables:
Packit 7838c8
 * mode: c
Packit 7838c8
 * c-basic-offset: 8
Packit 7838c8
 * fill-column: 78
Packit 7838c8
 * End:
Packit 7838c8
 */
Packit 7838c8