123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960 |
- /*
- * Copyright (c) 1988-1997 Sam Leffler
- * Copyright (c) 1991-1997 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.
- *
- * Scanline-oriented Write Support
- */
- #include "tiffiop.h"
- #include <stdio.h>
- #define STRIPINCR 20 /* expansion factor on strip array */
- #define WRITECHECKSTRIPS(tif, module) \
- (((tif)->tif_flags & TIFF_BEENWRITING) || TIFFWriteCheck((tif), 0, module))
- #define WRITECHECKTILES(tif, module) \
- (((tif)->tif_flags & TIFF_BEENWRITING) || TIFFWriteCheck((tif), 1, module))
- #define BUFFERCHECK(tif) \
- ((((tif)->tif_flags & TIFF_BUFFERSETUP) && tif->tif_rawdata) || \
- TIFFWriteBufferSetup((tif), NULL, (tmsize_t)-1))
- static int TIFFGrowStrips(TIFF *tif, uint32_t delta, const char *module);
- static int TIFFAppendToStrip(TIFF *tif, uint32_t strip, uint8_t *data,
- tmsize_t cc);
- int TIFFWriteScanline(TIFF *tif, void *buf, uint32_t row, uint16_t sample)
- {
- static const char module[] = "TIFFWriteScanline";
- register TIFFDirectory *td;
- int status, imagegrew = 0;
- uint32_t strip;
- if (!WRITECHECKSTRIPS(tif, module))
- return (-1);
- /*
- * Handle delayed allocation of data buffer. This
- * permits it to be sized more intelligently (using
- * directory information).
- */
- if (!BUFFERCHECK(tif))
- return (-1);
- tif->tif_flags |= TIFF_BUF4WRITE; /* not strictly sure this is right*/
- td = &tif->tif_dir;
- /*
- * Extend image length if needed
- * (but only for PlanarConfig=1).
- */
- if (row >= td->td_imagelength)
- { /* extend image */
- if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
- {
- TIFFErrorExtR(
- tif, module,
- "Can not change \"ImageLength\" when using separate planes");
- return (-1);
- }
- td->td_imagelength = row + 1;
- imagegrew = 1;
- }
- /*
- * Calculate strip and check for crossings.
- */
- if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
- {
- if (sample >= td->td_samplesperpixel)
- {
- TIFFErrorExtR(tif, module, "%lu: Sample out of range, max %lu",
- (unsigned long)sample,
- (unsigned long)td->td_samplesperpixel);
- return (-1);
- }
- strip = sample * td->td_stripsperimage + row / td->td_rowsperstrip;
- }
- else
- strip = row / td->td_rowsperstrip;
- /*
- * Check strip array to make sure there's space. We don't support
- * dynamically growing files that have data organized in separate
- * bitplanes because it's too painful. In that case we require that
- * the imagelength be set properly before the first write (so that the
- * strips array will be fully allocated above).
- */
- if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module))
- return (-1);
- if (strip != tif->tif_curstrip)
- {
- /*
- * Changing strips -- flush any data present.
- */
- if (!TIFFFlushData(tif))
- return (-1);
- tif->tif_curstrip = strip;
- /*
- * Watch out for a growing image. The value of strips/image
- * will initially be 1 (since it can't be deduced until the
- * imagelength is known).
- */
- if (strip >= td->td_stripsperimage && imagegrew)
- td->td_stripsperimage =
- TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip);
- if (td->td_stripsperimage == 0)
- {
- TIFFErrorExtR(tif, module, "Zero strips per image");
- return (-1);
- }
- tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
- if ((tif->tif_flags & TIFF_CODERSETUP) == 0)
- {
- if (!(*tif->tif_setupencode)(tif))
- return (-1);
- tif->tif_flags |= TIFF_CODERSETUP;
- }
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- /* this informs TIFFAppendToStrip() we have changed strip */
- tif->tif_curoff = 0;
- if (!(*tif->tif_preencode)(tif, sample))
- return (-1);
- tif->tif_flags |= TIFF_POSTENCODE;
- }
- /*
- * Ensure the write is either sequential or at the
- * beginning of a strip (or that we can randomly
- * access the data -- i.e. no encoding).
- */
- if (row != tif->tif_row)
- {
- if (row < tif->tif_row)
- {
- /*
- * Moving backwards within the same strip:
- * backup to the start and then decode
- * forward (below).
- */
- tif->tif_row =
- (strip % td->td_stripsperimage) * td->td_rowsperstrip;
- tif->tif_rawcp = tif->tif_rawdata;
- }
- /*
- * Seek forward to the desired row.
- */
- if (!(*tif->tif_seek)(tif, row - tif->tif_row))
- return (-1);
- tif->tif_row = row;
- }
- /* swab if needed - note that source buffer will be altered */
- tif->tif_postdecode(tif, (uint8_t *)buf, tif->tif_scanlinesize);
- status = (*tif->tif_encoderow)(tif, (uint8_t *)buf, tif->tif_scanlinesize,
- sample);
- /* we are now poised at the beginning of the next row */
- tif->tif_row = row + 1;
- return (status);
- }
- /* Make sure that at the first attempt of rewriting a tile/strip, we will have
- */
- /* more bytes available in the output buffer than the previous byte count, */
- /* so that TIFFAppendToStrip() will detect the overflow when it is called the
- * first */
- /* time if the new compressed tile is bigger than the older one. (GDAL #4771) */
- static int _TIFFReserveLargeEnoughWriteBuffer(TIFF *tif, uint32_t strip_or_tile)
- {
- TIFFDirectory *td = &tif->tif_dir;
- if (td->td_stripbytecount_p[strip_or_tile] > 0)
- {
- /* The +1 is to ensure at least one extra bytes */
- /* The +4 is because the LZW encoder flushes 4 bytes before the limit */
- uint64_t safe_buffer_size =
- (uint64_t)(td->td_stripbytecount_p[strip_or_tile] + 1 + 4);
- if (tif->tif_rawdatasize <= (tmsize_t)safe_buffer_size)
- {
- if (!(TIFFWriteBufferSetup(
- tif, NULL,
- (tmsize_t)TIFFroundup_64(safe_buffer_size, 1024))))
- return 0;
- }
- }
- return 1;
- }
- /*
- * Encode the supplied data and write it to the
- * specified strip.
- *
- * NB: Image length must be setup before writing.
- */
- tmsize_t TIFFWriteEncodedStrip(TIFF *tif, uint32_t strip, void *data,
- tmsize_t cc)
- {
- static const char module[] = "TIFFWriteEncodedStrip";
- TIFFDirectory *td = &tif->tif_dir;
- uint16_t sample;
- if (!WRITECHECKSTRIPS(tif, module))
- return ((tmsize_t)-1);
- /*
- * Check strip array to make sure there's space.
- * We don't support dynamically growing files that
- * have data organized in separate bitplanes because
- * it's too painful. In that case we require that
- * the imagelength be set properly before the first
- * write (so that the strips array will be fully
- * allocated above).
- */
- if (strip >= td->td_nstrips)
- {
- if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
- {
- TIFFErrorExtR(
- tif, module,
- "Can not grow image by strips when using separate planes");
- return ((tmsize_t)-1);
- }
- if (!TIFFGrowStrips(tif, 1, module))
- return ((tmsize_t)-1);
- td->td_stripsperimage =
- TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip);
- }
- /*
- * Handle delayed allocation of data buffer. This
- * permits it to be sized according to the directory
- * info.
- */
- if (!BUFFERCHECK(tif))
- return ((tmsize_t)-1);
- tif->tif_flags |= TIFF_BUF4WRITE;
- tif->tif_curstrip = strip;
- /* this informs TIFFAppendToStrip() we have changed or reset strip */
- tif->tif_curoff = 0;
- if (!_TIFFReserveLargeEnoughWriteBuffer(tif, strip))
- {
- return ((tmsize_t)(-1));
- }
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- if (td->td_stripsperimage == 0)
- {
- TIFFErrorExtR(tif, module, "Zero strips per image");
- return ((tmsize_t)-1);
- }
- tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
- if ((tif->tif_flags & TIFF_CODERSETUP) == 0)
- {
- if (!(*tif->tif_setupencode)(tif))
- return ((tmsize_t)-1);
- tif->tif_flags |= TIFF_CODERSETUP;
- }
- tif->tif_flags &= ~TIFF_POSTENCODE;
- /* shortcut to avoid an extra memcpy() */
- if (td->td_compression == COMPRESSION_NONE)
- {
- /* swab if needed - note that source buffer will be altered */
- tif->tif_postdecode(tif, (uint8_t *)data, cc);
- if (!isFillOrder(tif, td->td_fillorder) &&
- (tif->tif_flags & TIFF_NOBITREV) == 0)
- TIFFReverseBits((uint8_t *)data, cc);
- if (cc > 0 && !TIFFAppendToStrip(tif, strip, (uint8_t *)data, cc))
- return ((tmsize_t)-1);
- return (cc);
- }
- sample = (uint16_t)(strip / td->td_stripsperimage);
- if (!(*tif->tif_preencode)(tif, sample))
- return ((tmsize_t)-1);
- /* swab if needed - note that source buffer will be altered */
- tif->tif_postdecode(tif, (uint8_t *)data, cc);
- if (!(*tif->tif_encodestrip)(tif, (uint8_t *)data, cc, sample))
- return ((tmsize_t)-1);
- if (!(*tif->tif_postencode)(tif))
- return ((tmsize_t)-1);
- if (!isFillOrder(tif, td->td_fillorder) &&
- (tif->tif_flags & TIFF_NOBITREV) == 0)
- TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc);
- if (tif->tif_rawcc > 0 &&
- !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc))
- return ((tmsize_t)-1);
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- return (cc);
- }
- /*
- * Write the supplied data to the specified strip.
- *
- * NB: Image length must be setup before writing.
- */
- tmsize_t TIFFWriteRawStrip(TIFF *tif, uint32_t strip, void *data, tmsize_t cc)
- {
- static const char module[] = "TIFFWriteRawStrip";
- TIFFDirectory *td = &tif->tif_dir;
- if (!WRITECHECKSTRIPS(tif, module))
- return ((tmsize_t)-1);
- /*
- * Check strip array to make sure there's space.
- * We don't support dynamically growing files that
- * have data organized in separate bitplanes because
- * it's too painful. In that case we require that
- * the imagelength be set properly before the first
- * write (so that the strips array will be fully
- * allocated above).
- */
- if (strip >= td->td_nstrips)
- {
- if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
- {
- TIFFErrorExtR(
- tif, module,
- "Can not grow image by strips when using separate planes");
- return ((tmsize_t)-1);
- }
- /*
- * Watch out for a growing image. The value of
- * strips/image will initially be 1 (since it
- * can't be deduced until the imagelength is known).
- */
- if (strip >= td->td_stripsperimage)
- td->td_stripsperimage =
- TIFFhowmany_32(td->td_imagelength, td->td_rowsperstrip);
- if (!TIFFGrowStrips(tif, 1, module))
- return ((tmsize_t)-1);
- }
- if (tif->tif_curstrip != strip)
- {
- tif->tif_curstrip = strip;
- /* this informs TIFFAppendToStrip() we have changed or reset strip */
- tif->tif_curoff = 0;
- }
- if (td->td_stripsperimage == 0)
- {
- TIFFErrorExtR(tif, module, "Zero strips per image");
- return ((tmsize_t)-1);
- }
- tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
- return (TIFFAppendToStrip(tif, strip, (uint8_t *)data, cc) ? cc
- : (tmsize_t)-1);
- }
- /*
- * Write and compress a tile of data. The
- * tile is selected by the (x,y,z,s) coordinates.
- */
- tmsize_t TIFFWriteTile(TIFF *tif, void *buf, uint32_t x, uint32_t y, uint32_t z,
- uint16_t s)
- {
- if (!TIFFCheckTile(tif, x, y, z, s))
- return ((tmsize_t)(-1));
- /*
- * NB: A tile size of -1 is used instead of tif_tilesize knowing
- * that TIFFWriteEncodedTile will clamp this to the tile size.
- * This is done because the tile size may not be defined until
- * after the output buffer is setup in TIFFWriteBufferSetup.
- */
- return (TIFFWriteEncodedTile(tif, TIFFComputeTile(tif, x, y, z, s), buf,
- (tmsize_t)(-1)));
- }
- /*
- * Encode the supplied data and write it to the
- * specified tile. There must be space for the
- * data. The function clamps individual writes
- * to a tile to the tile size, but does not (and
- * can not) check that multiple writes to the same
- * tile do not write more than tile size data.
- *
- * NB: Image length must be setup before writing; this
- * interface does not support automatically growing
- * the image on each write (as TIFFWriteScanline does).
- */
- tmsize_t TIFFWriteEncodedTile(TIFF *tif, uint32_t tile, void *data, tmsize_t cc)
- {
- static const char module[] = "TIFFWriteEncodedTile";
- TIFFDirectory *td;
- uint16_t sample;
- uint32_t howmany32;
- if (!WRITECHECKTILES(tif, module))
- return ((tmsize_t)(-1));
- td = &tif->tif_dir;
- if (tile >= td->td_nstrips)
- {
- TIFFErrorExtR(tif, module, "Tile %lu out of range, max %lu",
- (unsigned long)tile, (unsigned long)td->td_nstrips);
- return ((tmsize_t)(-1));
- }
- /*
- * Handle delayed allocation of data buffer. This
- * permits it to be sized more intelligently (using
- * directory information).
- */
- if (!BUFFERCHECK(tif))
- return ((tmsize_t)(-1));
- tif->tif_flags |= TIFF_BUF4WRITE;
- tif->tif_curtile = tile;
- /* this informs TIFFAppendToStrip() we have changed or reset tile */
- tif->tif_curoff = 0;
- if (!_TIFFReserveLargeEnoughWriteBuffer(tif, tile))
- {
- return ((tmsize_t)(-1));
- }
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- /*
- * Compute tiles per row & per column to compute
- * current row and column
- */
- howmany32 = TIFFhowmany_32(td->td_imagelength, td->td_tilelength);
- if (howmany32 == 0)
- {
- TIFFErrorExtR(tif, module, "Zero tiles");
- return ((tmsize_t)(-1));
- }
- tif->tif_row = (tile % howmany32) * td->td_tilelength;
- howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
- if (howmany32 == 0)
- {
- TIFFErrorExtR(tif, module, "Zero tiles");
- return ((tmsize_t)(-1));
- }
- tif->tif_col = (tile % howmany32) * td->td_tilewidth;
- if ((tif->tif_flags & TIFF_CODERSETUP) == 0)
- {
- if (!(*tif->tif_setupencode)(tif))
- return ((tmsize_t)(-1));
- tif->tif_flags |= TIFF_CODERSETUP;
- }
- tif->tif_flags &= ~TIFF_POSTENCODE;
- /*
- * Clamp write amount to the tile size. This is mostly
- * done so that callers can pass in some large number
- * (e.g. -1) and have the tile size used instead.
- */
- if (cc < 1 || cc > tif->tif_tilesize)
- cc = tif->tif_tilesize;
- /* shortcut to avoid an extra memcpy() */
- if (td->td_compression == COMPRESSION_NONE)
- {
- /* swab if needed - note that source buffer will be altered */
- tif->tif_postdecode(tif, (uint8_t *)data, cc);
- if (!isFillOrder(tif, td->td_fillorder) &&
- (tif->tif_flags & TIFF_NOBITREV) == 0)
- TIFFReverseBits((uint8_t *)data, cc);
- if (cc > 0 && !TIFFAppendToStrip(tif, tile, (uint8_t *)data, cc))
- return ((tmsize_t)-1);
- return (cc);
- }
- sample = (uint16_t)(tile / td->td_stripsperimage);
- if (!(*tif->tif_preencode)(tif, sample))
- return ((tmsize_t)(-1));
- /* swab if needed - note that source buffer will be altered */
- tif->tif_postdecode(tif, (uint8_t *)data, cc);
- if (!(*tif->tif_encodetile)(tif, (uint8_t *)data, cc, sample))
- return ((tmsize_t)-1);
- if (!(*tif->tif_postencode)(tif))
- return ((tmsize_t)(-1));
- if (!isFillOrder(tif, td->td_fillorder) &&
- (tif->tif_flags & TIFF_NOBITREV) == 0)
- TIFFReverseBits((uint8_t *)tif->tif_rawdata, tif->tif_rawcc);
- if (tif->tif_rawcc > 0 &&
- !TIFFAppendToStrip(tif, tile, tif->tif_rawdata, tif->tif_rawcc))
- return ((tmsize_t)(-1));
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- return (cc);
- }
- /*
- * Write the supplied data to the specified strip.
- * There must be space for the data; we don't check
- * if strips overlap!
- *
- * NB: Image length must be setup before writing; this
- * interface does not support automatically growing
- * the image on each write (as TIFFWriteScanline does).
- */
- tmsize_t TIFFWriteRawTile(TIFF *tif, uint32_t tile, void *data, tmsize_t cc)
- {
- static const char module[] = "TIFFWriteRawTile";
- if (!WRITECHECKTILES(tif, module))
- return ((tmsize_t)(-1));
- if (tile >= tif->tif_dir.td_nstrips)
- {
- TIFFErrorExtR(tif, module, "Tile %lu out of range, max %lu",
- (unsigned long)tile,
- (unsigned long)tif->tif_dir.td_nstrips);
- return ((tmsize_t)(-1));
- }
- return (TIFFAppendToStrip(tif, tile, (uint8_t *)data, cc) ? cc
- : (tmsize_t)(-1));
- }
- #define isUnspecified(tif, f) \
- (TIFFFieldSet(tif, f) && (tif)->tif_dir.td_imagelength == 0)
- int TIFFSetupStrips(TIFF *tif)
- {
- TIFFDirectory *td = &tif->tif_dir;
- if (isTiled(tif))
- td->td_stripsperimage = isUnspecified(tif, FIELD_TILEDIMENSIONS)
- ? td->td_samplesperpixel
- : TIFFNumberOfTiles(tif);
- else
- td->td_stripsperimage = isUnspecified(tif, FIELD_ROWSPERSTRIP)
- ? td->td_samplesperpixel
- : TIFFNumberOfStrips(tif);
- td->td_nstrips = td->td_stripsperimage;
- /* TIFFWriteDirectoryTagData has a limitation to 0x80000000U bytes */
- if (td->td_nstrips >=
- 0x80000000U / ((tif->tif_flags & TIFF_BIGTIFF) ? 0x8U : 0x4U))
- {
- TIFFErrorExtR(tif, "TIFFSetupStrips",
- "Too large Strip/Tile Offsets/ByteCounts arrays");
- return 0;
- }
- if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
- td->td_stripsperimage /= td->td_samplesperpixel;
- td->td_stripoffset_p = (uint64_t *)_TIFFCheckMalloc(
- tif, td->td_nstrips, sizeof(uint64_t), "for \"StripOffsets\" array");
- td->td_stripbytecount_p = (uint64_t *)_TIFFCheckMalloc(
- tif, td->td_nstrips, sizeof(uint64_t), "for \"StripByteCounts\" array");
- if (td->td_stripoffset_p == NULL || td->td_stripbytecount_p == NULL)
- return (0);
- /*
- * Place data at the end-of-file
- * (by setting offsets to zero).
- */
- _TIFFmemset(td->td_stripoffset_p, 0, td->td_nstrips * sizeof(uint64_t));
- _TIFFmemset(td->td_stripbytecount_p, 0, td->td_nstrips * sizeof(uint64_t));
- TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS);
- TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS);
- return (1);
- }
- #undef isUnspecified
- /*
- * Verify file is writable and that the directory
- * information is setup properly. In doing the latter
- * we also "freeze" the state of the directory so
- * that important information is not changed.
- */
- int TIFFWriteCheck(TIFF *tif, int tiles, const char *module)
- {
- if (tif->tif_mode == O_RDONLY)
- {
- TIFFErrorExtR(tif, module, "File not open for writing");
- return (0);
- }
- if (tiles ^ isTiled(tif))
- {
- TIFFErrorExtR(tif, module,
- tiles ? "Can not write tiles to a striped image"
- : "Can not write scanlines to a tiled image");
- return (0);
- }
- _TIFFFillStriles(tif);
- /*
- * On the first write verify all the required information
- * has been setup and initialize any data structures that
- * had to wait until directory information was set.
- * Note that a lot of our work is assumed to remain valid
- * because we disallow any of the important parameters
- * from changing after we start writing (i.e. once
- * TIFF_BEENWRITING is set, TIFFSetField will only allow
- * the image's length to be changed).
- */
- if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS))
- {
- TIFFErrorExtR(tif, module,
- "Must set \"ImageWidth\" before writing data");
- return (0);
- }
- if (tif->tif_dir.td_stripoffset_p == NULL && !TIFFSetupStrips(tif))
- {
- tif->tif_dir.td_nstrips = 0;
- TIFFErrorExtR(tif, module, "No space for %s arrays",
- isTiled(tif) ? "tile" : "strip");
- return (0);
- }
- if (isTiled(tif))
- {
- tif->tif_tilesize = TIFFTileSize(tif);
- if (tif->tif_tilesize == 0)
- return (0);
- }
- else
- tif->tif_tilesize = (tmsize_t)(-1);
- tif->tif_scanlinesize = TIFFScanlineSize(tif);
- if (tif->tif_scanlinesize == 0)
- return (0);
- tif->tif_flags |= TIFF_BEENWRITING;
- if (tif->tif_dir.td_stripoffset_entry.tdir_tag != 0 &&
- tif->tif_dir.td_stripoffset_entry.tdir_count == 0 &&
- tif->tif_dir.td_stripoffset_entry.tdir_type == 0 &&
- tif->tif_dir.td_stripoffset_entry.tdir_offset.toff_long8 == 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_tag != 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_count == 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_type == 0 &&
- tif->tif_dir.td_stripbytecount_entry.tdir_offset.toff_long8 == 0 &&
- !(tif->tif_flags & TIFF_DIRTYDIRECT))
- {
- TIFFForceStrileArrayWriting(tif);
- }
- return (1);
- }
- /*
- * Setup the raw data buffer used for encoding.
- */
- int TIFFWriteBufferSetup(TIFF *tif, void *bp, tmsize_t size)
- {
- static const char module[] = "TIFFWriteBufferSetup";
- if (tif->tif_rawdata)
- {
- if (tif->tif_flags & TIFF_MYBUFFER)
- {
- _TIFFfreeExt(tif, tif->tif_rawdata);
- tif->tif_flags &= ~TIFF_MYBUFFER;
- }
- tif->tif_rawdata = NULL;
- }
- if (size == (tmsize_t)(-1))
- {
- size = (isTiled(tif) ? tif->tif_tilesize : TIFFStripSize(tif));
- /* Adds 10% margin for cases where compression would expand a bit */
- if (size < TIFF_TMSIZE_T_MAX - size / 10)
- size += size / 10;
- /*
- * Make raw data buffer at least 8K
- */
- if (size < 8 * 1024)
- size = 8 * 1024;
- bp = NULL; /* NB: force malloc */
- }
- if (bp == NULL)
- {
- bp = _TIFFmallocExt(tif, size);
- if (bp == NULL)
- {
- TIFFErrorExtR(tif, module, "No space for output buffer");
- return (0);
- }
- tif->tif_flags |= TIFF_MYBUFFER;
- }
- else
- tif->tif_flags &= ~TIFF_MYBUFFER;
- tif->tif_rawdata = (uint8_t *)bp;
- tif->tif_rawdatasize = size;
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- tif->tif_flags |= TIFF_BUFFERSETUP;
- return (1);
- }
- /*
- * Grow the strip data structures by delta strips.
- */
- static int TIFFGrowStrips(TIFF *tif, uint32_t delta, const char *module)
- {
- TIFFDirectory *td = &tif->tif_dir;
- uint64_t *new_stripoffset;
- uint64_t *new_stripbytecount;
- assert(td->td_planarconfig == PLANARCONFIG_CONTIG);
- new_stripoffset = (uint64_t *)_TIFFreallocExt(
- tif, td->td_stripoffset_p, (td->td_nstrips + delta) * sizeof(uint64_t));
- new_stripbytecount = (uint64_t *)_TIFFreallocExt(
- tif, td->td_stripbytecount_p,
- (td->td_nstrips + delta) * sizeof(uint64_t));
- if (new_stripoffset == NULL || new_stripbytecount == NULL)
- {
- if (new_stripoffset)
- _TIFFfreeExt(tif, new_stripoffset);
- if (new_stripbytecount)
- _TIFFfreeExt(tif, new_stripbytecount);
- td->td_nstrips = 0;
- TIFFErrorExtR(tif, module, "No space to expand strip arrays");
- return (0);
- }
- td->td_stripoffset_p = new_stripoffset;
- td->td_stripbytecount_p = new_stripbytecount;
- _TIFFmemset(td->td_stripoffset_p + td->td_nstrips, 0,
- delta * sizeof(uint64_t));
- _TIFFmemset(td->td_stripbytecount_p + td->td_nstrips, 0,
- delta * sizeof(uint64_t));
- td->td_nstrips += delta;
- tif->tif_flags |= TIFF_DIRTYDIRECT;
- return (1);
- }
- /*
- * Append the data to the specified strip.
- */
- static int TIFFAppendToStrip(TIFF *tif, uint32_t strip, uint8_t *data,
- tmsize_t cc)
- {
- static const char module[] = "TIFFAppendToStrip";
- TIFFDirectory *td = &tif->tif_dir;
- uint64_t m;
- int64_t old_byte_count = -1;
- if (tif->tif_curoff == 0)
- tif->tif_lastvalidoff = 0;
- if (td->td_stripoffset_p[strip] == 0 || tif->tif_curoff == 0)
- {
- assert(td->td_nstrips > 0);
- if (td->td_stripbytecount_p[strip] != 0 &&
- td->td_stripoffset_p[strip] != 0 &&
- td->td_stripbytecount_p[strip] >= (uint64_t)cc)
- {
- /*
- * There is already tile data on disk, and the new tile
- * data we have will fit in the same space. The only
- * aspect of this that is risky is that there could be
- * more data to append to this strip before we are done
- * depending on how we are getting called.
- */
- if (!SeekOK(tif, td->td_stripoffset_p[strip]))
- {
- TIFFErrorExtR(tif, module, "Seek error at scanline %lu",
- (unsigned long)tif->tif_row);
- return (0);
- }
- tif->tif_lastvalidoff =
- td->td_stripoffset_p[strip] + td->td_stripbytecount_p[strip];
- }
- else
- {
- /*
- * Seek to end of file, and set that as our location to
- * write this strip.
- */
- td->td_stripoffset_p[strip] = TIFFSeekFile(tif, 0, SEEK_END);
- tif->tif_flags |= TIFF_DIRTYSTRIP;
- }
- tif->tif_curoff = td->td_stripoffset_p[strip];
- /*
- * We are starting a fresh strip/tile, so set the size to zero.
- */
- old_byte_count = td->td_stripbytecount_p[strip];
- td->td_stripbytecount_p[strip] = 0;
- }
- m = tif->tif_curoff + cc;
- if (!(tif->tif_flags & TIFF_BIGTIFF))
- m = (uint32_t)m;
- if ((m < tif->tif_curoff) || (m < (uint64_t)cc))
- {
- TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded");
- return (0);
- }
- if (tif->tif_lastvalidoff != 0 && m > tif->tif_lastvalidoff &&
- td->td_stripbytecount_p[strip] > 0)
- {
- /* Ouch: we have detected that we are rewriting in place a strip/tile */
- /* with several calls to TIFFAppendToStrip(). The first call was with */
- /* a size smaller than the previous size of the strip/tile, so we */
- /* opted to rewrite in place, but a following call causes us to go */
- /* outsize of the strip/tile area, so we have to finally go for a */
- /* append-at-end-of-file strategy, and start by moving what we already
- */
- /* wrote. */
- tmsize_t tempSize;
- void *temp;
- uint64_t offsetRead;
- uint64_t offsetWrite;
- uint64_t toCopy = td->td_stripbytecount_p[strip];
- if (toCopy < 1024 * 1024)
- tempSize = (tmsize_t)toCopy;
- else
- tempSize = 1024 * 1024;
- offsetRead = td->td_stripoffset_p[strip];
- offsetWrite = TIFFSeekFile(tif, 0, SEEK_END);
- m = offsetWrite + toCopy + cc;
- if (!(tif->tif_flags & TIFF_BIGTIFF) && m != (uint32_t)m)
- {
- TIFFErrorExtR(tif, module, "Maximum TIFF file size exceeded");
- return (0);
- }
- temp = _TIFFmallocExt(tif, tempSize);
- if (temp == NULL)
- {
- TIFFErrorExtR(tif, module, "No space for output buffer");
- return (0);
- }
- tif->tif_flags |= TIFF_DIRTYSTRIP;
- td->td_stripoffset_p[strip] = offsetWrite;
- td->td_stripbytecount_p[strip] = 0;
- /* Move data written by previous calls to us at end of file */
- while (toCopy > 0)
- {
- if (!SeekOK(tif, offsetRead))
- {
- TIFFErrorExtR(tif, module, "Seek error");
- _TIFFfreeExt(tif, temp);
- return (0);
- }
- if (!ReadOK(tif, temp, tempSize))
- {
- TIFFErrorExtR(tif, module, "Cannot read");
- _TIFFfreeExt(tif, temp);
- return (0);
- }
- if (!SeekOK(tif, offsetWrite))
- {
- TIFFErrorExtR(tif, module, "Seek error");
- _TIFFfreeExt(tif, temp);
- return (0);
- }
- if (!WriteOK(tif, temp, tempSize))
- {
- TIFFErrorExtR(tif, module, "Cannot write");
- _TIFFfreeExt(tif, temp);
- return (0);
- }
- offsetRead += tempSize;
- offsetWrite += tempSize;
- td->td_stripbytecount_p[strip] += tempSize;
- toCopy -= tempSize;
- }
- _TIFFfreeExt(tif, temp);
- /* Append the data of this call */
- offsetWrite += cc;
- m = offsetWrite;
- }
- if (!WriteOK(tif, data, cc))
- {
- TIFFErrorExtR(tif, module, "Write error at scanline %lu",
- (unsigned long)tif->tif_row);
- return (0);
- }
- tif->tif_curoff = m;
- td->td_stripbytecount_p[strip] += cc;
- if ((int64_t)td->td_stripbytecount_p[strip] != old_byte_count)
- tif->tif_flags |= TIFF_DIRTYSTRIP;
- return (1);
- }
- /*
- * Internal version of TIFFFlushData that can be
- * called by ``encodestrip routines'' w/o concern
- * for infinite recursion.
- */
- int TIFFFlushData1(TIFF *tif)
- {
- if (tif->tif_rawcc > 0 && tif->tif_flags & TIFF_BUF4WRITE)
- {
- if (!isFillOrder(tif, tif->tif_dir.td_fillorder) &&
- (tif->tif_flags & TIFF_NOBITREV) == 0)
- TIFFReverseBits((uint8_t *)tif->tif_rawdata, tif->tif_rawcc);
- if (!TIFFAppendToStrip(
- tif, isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip,
- tif->tif_rawdata, tif->tif_rawcc))
- {
- /* We update those variables even in case of error since there's */
- /* code that doesn't really check the return code of this */
- /* function */
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- return (0);
- }
- tif->tif_rawcc = 0;
- tif->tif_rawcp = tif->tif_rawdata;
- }
- return (1);
- }
- /*
- * Set the current write offset. This should only be
- * used to set the offset to a known previous location
- * (very carefully), or to 0 so that the next write gets
- * appended to the end of the file.
- */
- void TIFFSetWriteOffset(TIFF *tif, toff_t off)
- {
- tif->tif_curoff = off;
- tif->tif_lastvalidoff = 0;
- }
|