static Tiff ClientOpen(string name, string mode, Stream clientData, TiffStream stream, TiffErrorHandler errorHandler, TiffExtendProc extender)
{
const string module = "ClientOpen";
if (mode == null || mode.Length == 0)
{
ErrorExt(null, clientData, module, "{0}: mode string should contain at least one char", name);
return(null);
}
int m = getMode(mode, module);
Tiff tif = new Tiff();
#if THREAD_SAFE_LIBTIFF
if (errorHandler != null)
{
tif.m_errorHandler = errorHandler;
}
if (extender != null)
{
tif.m_extender = extender;
}
#endif
tif.m_name = name;
tif.m_mode = m & ~(O_CREAT | O_TRUNC);
tif.m_curdir = -1; // non-existent directory
tif.m_curoff = 0;
tif.m_curstrip = -1; // invalid strip
tif.m_row = -1; // read/write pre-increment
tif.m_clientdata = clientData;
if (stream == null)
{
ErrorExt(tif, clientData, module, "TiffStream is null pointer.");
return(null);
}
tif.m_stream = stream;
// setup default state
tif.m_currentCodec = tif.m_builtInCodecs[0];
// Default is to return data MSB2LSB and enable the use of
// strip chopping when a file is opened read-only.
tif.m_flags = TiffFlags.MSB2LSB;
if (m == O_RDONLY || m == O_RDWR)
{
tif.m_flags |= STRIPCHOP_DEFAULT;
}
// Process library-specific flags in the open mode string.
// See remarks for Open method for the list of supported flags.
int modelength = mode.Length;
for (int i = 0; i < modelength; i++)
{
switch (mode[i])
{
case 'b':
if ((m & O_CREAT) != 0)
{
tif.m_flags |= TiffFlags.SWAB;
}
break;
case 'l':
break;
case 'B':
tif.m_flags = (tif.m_flags & ~TiffFlags.FILLORDER) | TiffFlags.MSB2LSB;
break;
case 'L':
tif.m_flags = (tif.m_flags & ~TiffFlags.FILLORDER) | TiffFlags.LSB2MSB;
break;
case 'H':
tif.m_flags = (tif.m_flags & ~TiffFlags.FILLORDER) | TiffFlags.LSB2MSB;
break;
case 'C':
if (m == O_RDONLY)
{
tif.m_flags |= TiffFlags.STRIPCHOP;
}
break;
case 'c':
if (m == O_RDONLY)
{
tif.m_flags &= ~TiffFlags.STRIPCHOP;
}
break;
case 'h':
tif.m_flags |= TiffFlags.HEADERONLY;
break;
case '4':
tif.m_flags |= TiffFlags.NOBIGTIFF;
break;
case '8':
tif.m_flags |= TiffFlags.ISBIGTIFF;
break;
}
}
// Read in TIFF header.
if ((tif.m_mode & O_TRUNC) != 0 || !tif.readHeaderOk(ref tif.m_header))
{
if (tif.m_mode == O_RDONLY)
{
ErrorExt(tif, tif.m_clientdata, name, "Cannot read TIFF header");
return(null);
}
// Setup header and write.
if ((tif.m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
{
tif.m_header.tiff_magic = TIFF_BIGENDIAN;
}
else
{
tif.m_header.tiff_magic = TIFF_LITTLEENDIAN;
}
if ((tif.m_flags & TiffFlags.ISBIGTIFF) == TiffFlags.ISBIGTIFF)
{
tif.m_header.tiff_version = TIFF_BIGTIFF_VERSION;
tif.m_header.tiff_diroff = 0; //filled in later
tif.m_header.tiff_fill = 0;
tif.m_header.tiff_offsize = sizeof(long);
if ((tif.m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
{
SwabShort(ref tif.m_header.tiff_version);
SwabShort(ref tif.m_header.tiff_offsize);
}
}
else
{
tif.m_header.tiff_version = TIFF_VERSION;
tif.m_header.tiff_diroff = 0; //filled in later
tif.m_header.tiff_fill = sizeof(long);
if ((tif.m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
{
SwabShort(ref tif.m_header.tiff_version);
}
}
tif.seekFile(0, SeekOrigin.Begin);
if (!tif.writeHeaderOK(tif.m_header))
{
ErrorExt(tif, tif.m_clientdata, name, "Error writing TIFF header");
tif.m_mode = O_RDONLY;
return(null);
}
// Setup the byte order handling.
tif.initOrder(tif.m_header.tiff_magic);
// Setup default directory.
tif.setupDefaultDirectory();
tif.m_diroff = 0;
tif.m_dirlist = null;
tif.m_dirlistsize = 0;
tif.m_dirnumber = 0;
return(tif);
}
// Setup the byte order handling.
if (tif.m_header.tiff_magic != TIFF_BIGENDIAN &&
tif.m_header.tiff_magic != TIFF_LITTLEENDIAN &&
tif.m_header.tiff_magic != MDI_LITTLEENDIAN)
{
ErrorExt(tif, tif.m_clientdata, name,
"Not a TIFF or MDI file, bad magic number {0} (0x{1:x})",
tif.m_header.tiff_magic, tif.m_header.tiff_magic);
tif.m_mode = O_RDONLY;
return(null);
}
tif.initOrder(tif.m_header.tiff_magic);
// Swap header if required.
if ((tif.m_flags & TiffFlags.SWAB) == TiffFlags.SWAB)
{
SwabShort(ref tif.m_header.tiff_version);
SwabBigTiffValue(ref tif.m_header.tiff_diroff, tif.m_header.tiff_version == TIFF_BIGTIFF_VERSION, false);
}
// Now check version (if needed, it's been byte-swapped).
// Note that this isn't actually a version number, it's a
// magic number that doesn't change (stupid).
if (tif.m_header.tiff_version == TIFF_BIGTIFF_VERSION)
{
if ((tif.m_flags & TiffFlags.NOBIGTIFF) == TiffFlags.NOBIGTIFF)
{
ErrorExt(tif, tif.m_clientdata, name,
"This is a BigTIFF file. Non-BigTIFF mode '32' is forced");
tif.m_mode = O_RDONLY;
return(null);
}
}
if (tif.m_header.tiff_version == TIFF_VERSION)
{
if ((tif.m_flags & TiffFlags.ISBIGTIFF) == TiffFlags.ISBIGTIFF)
{
ErrorExt(tif, tif.m_clientdata, name,
"This is a non-BigTIFF file. BigTIFF mode '64' is forced");
tif.m_mode = O_RDONLY;
return(null);
}
}
if (tif.m_header.tiff_version != TIFF_VERSION && tif.m_header.tiff_version != TIFF_BIGTIFF_VERSION)
{
ErrorExt(tif, tif.m_clientdata, name,
"Not a TIFF file, bad version number {0} (0x{1:x})",
tif.m_header.tiff_version, tif.m_header.tiff_version);
tif.m_mode = O_RDONLY;
return(null);
}
tif.m_flags |= TiffFlags.MYBUFFER;
tif.m_rawcp = 0;
tif.m_rawdata = null;
tif.m_rawdatasize = 0;
// Sometimes we do not want to read the first directory (for example,
// it may be broken) and want to proceed to other directories. I this
// case we use the HEADERONLY flag to open file and return
// immediately after reading TIFF header.
if ((tif.m_flags & TiffFlags.HEADERONLY) == TiffFlags.HEADERONLY)
{
return(tif);
}
// Setup initial directory.
switch (mode[0])
{
case 'r':
tif.m_nextdiroff = tif.m_header.tiff_diroff;
if (tif.ReadDirectory())
{
tif.m_rawcc = -1;
tif.m_flags |= TiffFlags.BUFFERSETUP;
return(tif);
}
break;
case 'a':
// New directories are automatically append to the end of
// the directory chain when they are written out (see WriteDirectory).
tif.setupDefaultDirectory();
return(tif);
}
tif.m_mode = O_RDONLY;
return(null);
}