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