2005.01.25 18:29 "[Tiff] issues with TIFFStreamOpen", by Michael Rinne

2005.01.27 21:51 "Re: [Tiff] issues with TIFFStreamOpen", by Edward Lam

I've attached a new tif_stream.cxx incorporating all the changes mentioned above. I haven't tested them though. Please let me know if it works for you. It's much appreciated, Michael!

Oops, I forgot to change the call to TIFFClientOpen() in the write code path to pass data instead of fd. Try this attachment instead which should work better.

-Edward

/* $Id: tif_stream.cxx,v 1.2 2004/11/13 11:19:15 dron Exp $ */

/*
 * Copyright (c) 1988-1996 Sam Leffler
 * Copyright (c) 1991-1996 Silicon Graphics, Inc.
 *
 * Permission to use, copy, modify, distribute, and sell this software and
 * its documentation for any purpose is hereby granted without fee, provided
 * that (i) the above copyright notices and this permission notice appear in
 * all copies of the software and related documentation, and (ii) the names of
 * Sam Leffler and Silicon Graphics may not be used in any advertising or
 * publicity relating to the software without the specific, prior written
 * permission of Sam Leffler and Silicon Graphics.
 *
 * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
 * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
 *
 * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
 * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
 * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
 * OF THIS SOFTWARE.
 */

/*
 * TIFF Library UNIX-specific Routines.
 */
#include <iostream>
#include "tiffiop.h"

using namespace std;

class tiffis_data
{
  public:

        istream *myIS;
        long    myStreamStartPos;
};

class tiffos_data
{
  public:

        ostream *myOS;
        long    myStreamStartPos;
};

static tsize_t
_tiffosReadProc(thandle_t, tdata_t, tsize_t)
{
        return 0;
}

static tsize_t
_tiffisReadProc(thandle_t fd, tdata_t buf, tsize_t size)
{
        tiffis_data     *data = (tiffis_data *)fd;

        data->myIS->read((char *)buf, (int)size);

        return data->myIS->gcount();
}

static tsize_t
_tiffosWriteProc(thandle_t fd, tdata_t buf, tsize_t size)
{
        tiffos_data     *data = (tiffos_data *)fd;
        ostream         *os = data->myOS;
        int             pos = os->tellp();

        os->write((const char *)buf, size);

        return ((int)os->tellp()) - pos;
}

static tsize_t
_tiffisWriteProc(thandle_t, tdata_t, tsize_t)
{
        return 0;
}

static toff_t
_tiffosSeekProc(thandle_t fd, toff_t off, int whence)
{
        tiffos_data     *data = (tiffos_data *)fd;
        ostream *os = data->myOS;

        // if the stream has already failed, don't do anything
        if( os->fail() )
                return os->tellp();

        switch(whence) {
        case SEEK_SET:
            os->seekp(data->myStreamStartPos + off, ios::beg);
                break;
        case SEEK_CUR:
                os->seekp(off, ios::cur);
                break;
        case SEEK_END:
                os->seekp(off, ios::end);
                break;
        }

        // Attempt to workaround problems with seeking past the end of the
        // stream.  ofstream doesn't have a problem with this but
        // ostrstream/ostringstream does. In that situation, add intermediate
        // '\0' characters.
        if( os->fail() ) {
                ios_base::iostate   old_state;
                toff_t              origin;

                old_state = os->rdstate();
                // reset the fail bit or else tellp() won't work below
                os->clear(os->rdstate() & ~ios::failbit);
                switch( whence ) {
                        case SEEK_SET:
                                origin = data->myStreamStartPos;
                                break;
                        case SEEK_CUR:
                                origin = os->tellp();
                                break;
                        case SEEK_END:
                                os->seekp(0, ios::end);
                                origin = os->tellp();
                                break;
                }
                // restore original stream state
                os->clear(old_state);

                // only do something if desired seek position is valid
                if( origin + off > data->myStreamStartPos ) {
                        toff_t  num_fill;

                        // clear the fail bit
                        os->clear(os->rdstate() & ~ios::failbit);

                        // fill the intermediate space
                        num_fill = origin + off - (toff_t)os->tellp();
                        for( toff_t i = 0; i < num_fill; i++ )
                                os->put('\0');

                        // retry the seek
                        os->seekp(origin + off, ios::beg);
                }
        }

        return os->tellp();
}

static toff_t
_tiffisSeekProc(thandle_t fd, toff_t off, int whence)
{
        tiffis_data     *data = (tiffis_data *)fd;

        switch(whence) {
        case SEEK_SET:
                data->myIS->seekg(data->myStreamStartPos + off, ios::beg);
                break;
        case SEEK_CUR:
                data->myIS->seekg(off, ios::cur);
                break;
        case SEEK_END:
                data->myIS->seekg(off, ios::end);
                break;
        }

        return ((long)data->myIS->tellg()) - data->myStreamStartPos;
}

static toff_t
_tiffosSizeProc(thandle_t fd)
{
        tiffos_data     *data = (tiffos_data *)fd;
        ostream         *os = data->myOS;
        toff_t          pos = os->tellp();
        toff_t          len;

        os->seekp(0, ios::end);
        len = os->tellp();
        os->seekp(pos);

        return len;
}

static toff_t
_tiffisSizeProc(thandle_t fd)
{
        tiffis_data     *data = (tiffis_data *)fd;
        int             pos = data->myIS->tellg();
        int             len;

        data->myIS->seekg(0, ios::end);
        len = data->myIS->tellg();
        data->myIS->seekg(pos);

        return len;
}

static int
_tiffosCloseProc(thandle_t fd)
{
        // Our stream was not allocated by us, so it shouldn't be closed by us.
        delete (tiffos_data *)fd;
        return 0;
}

static int
_tiffisCloseProc(thandle_t fd)
{
        // Our stream was not allocated by us, so it shouldn't be closed by us.
        delete (tiffis_data *)fd;
        return 0;
}

static int
_tiffDummyMapProc(thandle_t , tdata_t* , toff_t* )
{
        return (0);
}

static void
_tiffDummyUnmapProc(thandle_t , tdata_t , toff_t )
{
}

/*
 * Open a TIFF file descriptor for read/writing.
 */
static TIFF*
_tiffStreamOpen(const char* name, const char* mode, void *fd)
{
        TIFF*   tif;

        if( strchr(mode, 'w') ) {
                tiffos_data     *data = new tiffos_data;
                data->myOS = (ostream *)fd;
                data->myStreamStartPos = data->myOS->tellp();

                // Open for writing.
                tif = TIFFClientOpen(name, mode,
                                (thandle_t) data,
                                _tiffosReadProc, _tiffosWriteProc,
                                _tiffosSeekProc, _tiffosCloseProc,
                                _tiffosSizeProc,
                                _tiffDummyMapProc, _tiffDummyUnmapProc);
        } else {
                tiffis_data     *data = new tiffis_data;
                data->myIS = (istream *)fd;
                data->myStreamStartPos = data->myIS->tellg();
                // Open for reading.
                tif = TIFFClientOpen(name, mode,
                                (thandle_t) data,
                                _tiffisReadProc, _tiffisWriteProc,
                                _tiffisSeekProc, _tiffisCloseProc,
                                _tiffisSizeProc,
                                _tiffDummyMapProc, _tiffDummyUnmapProc);
        }

        return (tif);
}

TIFF*
TIFFStreamOpen(const char* name, ostream *os)
{
        // If os is either a ostrstream or ostringstream, and has no data
        // written to it yet, then tellp() will return -1 which will break us.
        // We workaround this by writing out a dummy character and
        // then seek back to the beginning.
        if( !os->fail() && (int)os->tellp() < 0 ) {
                *os << '\0';
                os->seekp(0);
        }

        // NB: We don't support mapped files with streams so add 'm'
        return _tiffStreamOpen(name, "wm", os);
}

TIFF*
TIFFStreamOpen(const char* name, istream *is)
{
        // NB: We don't support mapped files with streams so add 'm'
        return _tiffStreamOpen(name, "rm", is);
}

/* vim: set ts=8 sts=8 sw=8 noet: */