mirror of https://github.com/opencv/opencv.git
Open Source Computer Vision Library
https://opencv.org/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
404 lines
13 KiB
404 lines
13 KiB
/* |
|
* 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 "tiffiop.h" |
|
#include <iostream> |
|
|
|
using namespace std; |
|
|
|
/* |
|
ISO C++ uses a 'std::streamsize' type to define counts. This makes |
|
it similar to, (but perhaps not the same as) size_t. |
|
|
|
The std::ios::pos_type is used to represent stream positions as used |
|
by tellg(), tellp(), seekg(), and seekp(). This makes it similar to |
|
(but perhaps not the same as) 'off_t'. The std::ios::streampos type |
|
is used for character streams, but is documented to not be an |
|
integral type anymore, so it should *not* be assigned to an integral |
|
type. |
|
|
|
The std::ios::off_type is used to specify relative offsets needed by |
|
the variants of seekg() and seekp() which accept a relative offset |
|
argument. |
|
|
|
Useful prototype knowledge: |
|
|
|
Obtain read position |
|
ios::pos_type basic_istream::tellg() |
|
|
|
Set read position |
|
basic_istream& basic_istream::seekg(ios::pos_type) |
|
basic_istream& basic_istream::seekg(ios::off_type, ios_base::seekdir) |
|
|
|
Read data |
|
basic_istream& istream::read(char *str, streamsize count) |
|
|
|
Number of characters read in last unformatted read |
|
streamsize istream::gcount(); |
|
|
|
Obtain write position |
|
ios::pos_type basic_ostream::tellp() |
|
|
|
Set write position |
|
basic_ostream& basic_ostream::seekp(ios::pos_type) |
|
basic_ostream& basic_ostream::seekp(ios::off_type, ios_base::seekdir) |
|
|
|
Write data |
|
basic_ostream& ostream::write(const char *str, streamsize count) |
|
*/ |
|
|
|
struct tiffis_data; |
|
struct tiffos_data; |
|
|
|
extern "C" |
|
{ |
|
|
|
static tmsize_t _tiffosReadProc(thandle_t, void *, tmsize_t); |
|
static tmsize_t _tiffisReadProc(thandle_t fd, void *buf, tmsize_t size); |
|
static tmsize_t _tiffosWriteProc(thandle_t fd, void *buf, tmsize_t size); |
|
static tmsize_t _tiffisWriteProc(thandle_t, void *, tmsize_t); |
|
static uint64_t _tiffosSeekProc(thandle_t fd, uint64_t off, int whence); |
|
static uint64_t _tiffisSeekProc(thandle_t fd, uint64_t off, int whence); |
|
static uint64_t _tiffosSizeProc(thandle_t fd); |
|
static uint64_t _tiffisSizeProc(thandle_t fd); |
|
static int _tiffosCloseProc(thandle_t fd); |
|
static int _tiffisCloseProc(thandle_t fd); |
|
static int _tiffDummyMapProc(thandle_t, void **base, toff_t *size); |
|
static void _tiffDummyUnmapProc(thandle_t, void *base, toff_t size); |
|
static TIFF *_tiffStreamOpen(const char *name, const char *mode, void *fd); |
|
|
|
struct tiffis_data |
|
{ |
|
istream *stream; |
|
ios::pos_type start_pos; |
|
}; |
|
|
|
struct tiffos_data |
|
{ |
|
ostream *stream; |
|
ios::pos_type start_pos; |
|
}; |
|
|
|
static tmsize_t _tiffosReadProc(thandle_t, void *, tmsize_t) { return 0; } |
|
|
|
static tmsize_t _tiffisReadProc(thandle_t fd, void *buf, tmsize_t size) |
|
{ |
|
tiffis_data *data = reinterpret_cast<tiffis_data *>(fd); |
|
|
|
// Verify that type does not overflow. |
|
streamsize request_size = size; |
|
if (static_cast<tmsize_t>(request_size) != size) |
|
return static_cast<tmsize_t>(-1); |
|
|
|
data->stream->read((char *)buf, request_size); |
|
|
|
return static_cast<tmsize_t>(data->stream->gcount()); |
|
} |
|
|
|
static tmsize_t _tiffosWriteProc(thandle_t fd, void *buf, tmsize_t size) |
|
{ |
|
tiffos_data *data = reinterpret_cast<tiffos_data *>(fd); |
|
ostream *os = data->stream; |
|
ios::pos_type pos = os->tellp(); |
|
|
|
// Verify that type does not overflow. |
|
streamsize request_size = size; |
|
if (static_cast<tmsize_t>(request_size) != size) |
|
return static_cast<tmsize_t>(-1); |
|
|
|
os->write(reinterpret_cast<const char *>(buf), request_size); |
|
|
|
return static_cast<tmsize_t>(os->tellp() - pos); |
|
} |
|
|
|
static tmsize_t _tiffisWriteProc(thandle_t, void *, tmsize_t) { return 0; } |
|
|
|
static uint64_t _tiffosSeekProc(thandle_t fd, uint64_t off, int whence) |
|
{ |
|
tiffos_data *data = reinterpret_cast<tiffos_data *>(fd); |
|
ostream *os = data->stream; |
|
|
|
// if the stream has already failed, don't do anything |
|
if (os->fail()) |
|
return static_cast<uint64_t>(-1); |
|
|
|
switch (whence) |
|
{ |
|
case SEEK_SET: |
|
{ |
|
// Compute 64-bit offset |
|
uint64_t new_offset = |
|
static_cast<uint64_t>(data->start_pos) + off; |
|
|
|
// Verify that value does not overflow |
|
ios::off_type offset = static_cast<ios::off_type>(new_offset); |
|
if (static_cast<uint64_t>(offset) != new_offset) |
|
return static_cast<uint64_t>(-1); |
|
|
|
os->seekp(offset, ios::beg); |
|
break; |
|
} |
|
case SEEK_CUR: |
|
{ |
|
// Verify that value does not overflow |
|
ios::off_type offset = static_cast<ios::off_type>(off); |
|
if (static_cast<uint64_t>(offset) != off) |
|
return static_cast<uint64_t>(-1); |
|
|
|
os->seekp(offset, ios::cur); |
|
break; |
|
} |
|
case SEEK_END: |
|
{ |
|
// Verify that value does not overflow |
|
ios::off_type offset = static_cast<ios::off_type>(off); |
|
if (static_cast<uint64_t>(offset) != off) |
|
return static_cast<uint64_t>(-1); |
|
|
|
os->seekp(offset, 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::iostate old_state; |
|
ios::pos_type 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: |
|
default: |
|
origin = data->start_pos; |
|
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 ((static_cast<uint64_t>(origin) + off) > |
|
static_cast<uint64_t>(data->start_pos)) |
|
{ |
|
uint64_t num_fill; |
|
|
|
// clear the fail bit |
|
os->clear(os->rdstate() & ~ios::failbit); |
|
|
|
// extend the stream to the expected size |
|
os->seekp(0, ios::end); |
|
num_fill = (static_cast<uint64_t>(origin)) + off - os->tellp(); |
|
for (uint64_t i = 0; i < num_fill; i++) |
|
os->put('\0'); |
|
|
|
// retry the seek |
|
os->seekp(static_cast<ios::off_type>( |
|
static_cast<uint64_t>(origin) + off), |
|
ios::beg); |
|
} |
|
} |
|
|
|
return static_cast<uint64_t>(os->tellp()); |
|
} |
|
|
|
static uint64_t _tiffisSeekProc(thandle_t fd, uint64_t off, int whence) |
|
{ |
|
tiffis_data *data = reinterpret_cast<tiffis_data *>(fd); |
|
|
|
switch (whence) |
|
{ |
|
case SEEK_SET: |
|
{ |
|
// Compute 64-bit offset |
|
uint64_t new_offset = |
|
static_cast<uint64_t>(data->start_pos) + off; |
|
|
|
// Verify that value does not overflow |
|
ios::off_type offset = static_cast<ios::off_type>(new_offset); |
|
if (static_cast<uint64_t>(offset) != new_offset) |
|
return static_cast<uint64_t>(-1); |
|
|
|
data->stream->seekg(offset, ios::beg); |
|
break; |
|
} |
|
case SEEK_CUR: |
|
{ |
|
// Verify that value does not overflow |
|
ios::off_type offset = static_cast<ios::off_type>(off); |
|
if (static_cast<uint64_t>(offset) != off) |
|
return static_cast<uint64_t>(-1); |
|
|
|
data->stream->seekg(offset, ios::cur); |
|
break; |
|
} |
|
case SEEK_END: |
|
{ |
|
// Verify that value does not overflow |
|
ios::off_type offset = static_cast<ios::off_type>(off); |
|
if (static_cast<uint64_t>(offset) != off) |
|
return static_cast<uint64_t>(-1); |
|
|
|
data->stream->seekg(offset, ios::end); |
|
break; |
|
} |
|
} |
|
|
|
return (uint64_t)(data->stream->tellg() - data->start_pos); |
|
} |
|
|
|
static uint64_t _tiffosSizeProc(thandle_t fd) |
|
{ |
|
tiffos_data *data = reinterpret_cast<tiffos_data *>(fd); |
|
ostream *os = data->stream; |
|
ios::pos_type pos = os->tellp(); |
|
ios::pos_type len; |
|
|
|
os->seekp(0, ios::end); |
|
len = os->tellp(); |
|
os->seekp(pos); |
|
|
|
return (uint64_t)len; |
|
} |
|
|
|
static uint64_t _tiffisSizeProc(thandle_t fd) |
|
{ |
|
tiffis_data *data = reinterpret_cast<tiffis_data *>(fd); |
|
ios::pos_type pos = data->stream->tellg(); |
|
ios::pos_type len; |
|
|
|
data->stream->seekg(0, ios::end); |
|
len = data->stream->tellg(); |
|
data->stream->seekg(pos); |
|
|
|
return (uint64_t)len; |
|
} |
|
|
|
static int _tiffosCloseProc(thandle_t fd) |
|
{ |
|
// Our stream was not allocated by us, so it shouldn't be closed by us. |
|
delete reinterpret_cast<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 reinterpret_cast<tiffis_data *>(fd); |
|
return 0; |
|
} |
|
|
|
static int _tiffDummyMapProc(thandle_t, void **base, toff_t *size) |
|
{ |
|
(void)base; |
|
(void)size; |
|
return (0); |
|
} |
|
|
|
static void _tiffDummyUnmapProc(thandle_t, void *base, toff_t size) |
|
{ |
|
(void)base; |
|
(void)size; |
|
} |
|
|
|
/* |
|
* 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->stream = reinterpret_cast<ostream *>(fd); |
|
data->start_pos = data->stream->tellp(); |
|
|
|
// Open for writing. |
|
tif = TIFFClientOpen( |
|
name, mode, reinterpret_cast<thandle_t>(data), _tiffosReadProc, |
|
_tiffosWriteProc, _tiffosSeekProc, _tiffosCloseProc, |
|
_tiffosSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); |
|
if (!tif) |
|
{ |
|
delete data; |
|
} |
|
} |
|
else |
|
{ |
|
tiffis_data *data = new tiffis_data; |
|
data->stream = reinterpret_cast<istream *>(fd); |
|
data->start_pos = data->stream->tellg(); |
|
// Open for reading. |
|
tif = TIFFClientOpen( |
|
name, mode, reinterpret_cast<thandle_t>(data), _tiffisReadProc, |
|
_tiffisWriteProc, _tiffisSeekProc, _tiffisCloseProc, |
|
_tiffisSizeProc, _tiffDummyMapProc, _tiffDummyUnmapProc); |
|
if (!tif) |
|
{ |
|
delete data; |
|
} |
|
} |
|
|
|
return (tif); |
|
} |
|
|
|
} /* extern "C" */ |
|
|
|
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() && static_cast<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); |
|
}
|
|
|