| 1 | /* $Header$ */ |
| 2 | |
| 3 | /* |
| 4 | * Copyright (c) 1988-1997 Sam Leffler |
| 5 | * Copyright (c) 1991-1997 Silicon Graphics, Inc. |
| 6 | * |
| 7 | * Permission to use, copy, modify, distribute, and sell this software and |
| 8 | * its documentation for any purpose is hereby granted without fee, provided |
| 9 | * that (i) the above copyright notices and this permission notice appear in |
| 10 | * all copies of the software and related documentation, and (ii) the names of |
| 11 | * Sam Leffler and Silicon Graphics may not be used in any advertising or |
| 12 | * publicity relating to the software without the specific, prior written |
| 13 | * permission of Sam Leffler and Silicon Graphics. |
| 14 | * |
| 15 | * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, |
| 16 | * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY |
| 17 | * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. |
| 18 | * |
| 19 | * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR |
| 20 | * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, |
| 21 | * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
| 22 | * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF |
| 23 | * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE |
| 24 | * OF THIS SOFTWARE. |
| 25 | */ |
| 26 | |
| 27 | /* |
| 28 | * TIFF Library. |
| 29 | * |
| 30 | * Scanline-oriented Write Support |
| 31 | */ |
| 32 | #include "tiffiop.h" |
| 33 | #include <assert.h> |
| 34 | #include <stdio.h> |
| 35 | |
| 36 | #define STRIPINCR 20 /* expansion factor on strip array */ |
| 37 | |
| 38 | #define WRITECHECKSTRIPS(tif, module) \ |
| 39 | (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),0,module)) |
| 40 | #define WRITECHECKTILES(tif, module) \ |
| 41 | (((tif)->tif_flags&TIFF_BEENWRITING) || TIFFWriteCheck((tif),1,module)) |
| 42 | #define BUFFERCHECK(tif) \ |
| 43 | (((tif)->tif_flags & TIFF_BUFFERSETUP) || \ |
| 44 | TIFFWriteBufferSetup((tif), NULL, (tsize_t) -1)) |
| 45 | |
| 46 | static int TIFFWriteCheck(TIFF*, int, const char*); |
| 47 | static int TIFFGrowStrips(TIFF*, int, const char*); |
| 48 | static int TIFFAppendToStrip(TIFF*, tstrip_t, tidata_t, tsize_t); |
| 49 | static int TIFFSetupStrips(TIFF*); |
| 50 | |
| 51 | int |
| 52 | TIFFWriteScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample) |
| 53 | { |
| 54 | static const char module[] = "TIFFWriteScanline"; |
| 55 | register TIFFDirectory *td; |
| 56 | int status, imagegrew = 0; |
| 57 | tstrip_t strip; |
| 58 | |
| 59 | if (!WRITECHECKSTRIPS(tif, module)) |
| 60 | return (-1); |
| 61 | /* |
| 62 | * Handle delayed allocation of data buffer. This |
| 63 | * permits it to be sized more intelligently (using |
| 64 | * directory information). |
| 65 | */ |
| 66 | if (!BUFFERCHECK(tif)) |
| 67 | return (-1); |
| 68 | td = &tif->tif_dir; |
| 69 | /* |
| 70 | * Extend image length if needed |
| 71 | * (but only for PlanarConfig=1). |
| 72 | */ |
| 73 | if (row >= td->td_imagelength) { /* extend image */ |
| 74 | if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { |
| 75 | TIFFError(tif->tif_name, |
| 76 | "Can not change \"ImageLength\" when using separate planes"); |
| 77 | return (-1); |
| 78 | } |
| 79 | td->td_imagelength = row+1; |
| 80 | imagegrew = 1; |
| 81 | } |
| 82 | /* |
| 83 | * Calculate strip and check for crossings. |
| 84 | */ |
| 85 | if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { |
| 86 | if (sample >= td->td_samplesperpixel) { |
| 87 | TIFFError(tif->tif_name, |
| 88 | "%d: Sample out of range, max %d", |
| 89 | sample, td->td_samplesperpixel); |
| 90 | return (-1); |
| 91 | } |
| 92 | strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip; |
| 93 | } else |
| 94 | strip = row / td->td_rowsperstrip; |
| 95 | if (strip != tif->tif_curstrip) { |
| 96 | /* |
| 97 | * Changing strips -- flush any data present. |
| 98 | */ |
| 99 | if (!TIFFFlushData(tif)) |
| 100 | return (-1); |
| 101 | tif->tif_curstrip = strip; |
| 102 | /* |
| 103 | * Watch out for a growing image. The value of |
| 104 | * strips/image will initially be 1 (since it |
| 105 | * can't be deduced until the imagelength is known). |
| 106 | */ |
| 107 | if (strip >= td->td_stripsperimage && imagegrew) |
| 108 | td->td_stripsperimage = |
| 109 | TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); |
| 110 | tif->tif_row = |
| 111 | (strip % td->td_stripsperimage) * td->td_rowsperstrip; |
| 112 | if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { |
| 113 | if (!(*tif->tif_setupencode)(tif)) |
| 114 | return (-1); |
| 115 | tif->tif_flags |= TIFF_CODERSETUP; |
| 116 | } |
| 117 | if (!(*tif->tif_preencode)(tif, sample)) |
| 118 | return (-1); |
| 119 | tif->tif_flags |= TIFF_POSTENCODE; |
| 120 | } |
| 121 | /* |
| 122 | * Check strip array to make sure there's space. |
| 123 | * We don't support dynamically growing files that |
| 124 | * have data organized in separate bitplanes because |
| 125 | * it's too painful. In that case we require that |
| 126 | * the imagelength be set properly before the first |
| 127 | * write (so that the strips array will be fully |
| 128 | * allocated above). |
| 129 | */ |
| 130 | if (strip >= td->td_nstrips && !TIFFGrowStrips(tif, 1, module)) |
| 131 | return (-1); |
| 132 | /* |
| 133 | * Ensure the write is either sequential or at the |
| 134 | * beginning of a strip (or that we can randomly |
| 135 | * access the data -- i.e. no encoding). |
| 136 | */ |
| 137 | if (row != tif->tif_row) { |
| 138 | if (row < tif->tif_row) { |
| 139 | /* |
| 140 | * Moving backwards within the same strip: |
| 141 | * backup to the start and then decode |
| 142 | * forward (below). |
| 143 | */ |
| 144 | tif->tif_row = (strip % td->td_stripsperimage) * |
| 145 | td->td_rowsperstrip; |
| 146 | tif->tif_rawcp = tif->tif_rawdata; |
| 147 | } |
| 148 | /* |
| 149 | * Seek forward to the desired row. |
| 150 | */ |
| 151 | if (!(*tif->tif_seek)(tif, row - tif->tif_row)) |
| 152 | return (-1); |
| 153 | tif->tif_row = row; |
| 154 | } |
| 155 | status = (*tif->tif_encoderow)(tif, (tidata_t) buf, |
| 156 | tif->tif_scanlinesize, sample); |
| 157 | tif->tif_row++; |
| 158 | return (status); |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | * Encode the supplied data and write it to the |
| 163 | * specified strip. There must be space for the |
| 164 | * data; we don't check if strips overlap! |
| 165 | * |
| 166 | * NB: Image length must be setup before writing. |
| 167 | */ |
| 168 | tsize_t |
| 169 | TIFFWriteEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) |
| 170 | { |
| 171 | static const char module[] = "TIFFWriteEncodedStrip"; |
| 172 | TIFFDirectory *td = &tif->tif_dir; |
| 173 | tsample_t sample; |
| 174 | |
| 175 | if (!WRITECHECKSTRIPS(tif, module)) |
| 176 | return ((tsize_t) -1); |
| 177 | /* |
| 178 | * Check strip array to make sure there's space. |
| 179 | * We don't support dynamically growing files that |
| 180 | * have data organized in separate bitplanes because |
| 181 | * it's too painful. In that case we require that |
| 182 | * the imagelength be set properly before the first |
| 183 | * write (so that the strips array will be fully |
| 184 | * allocated above). |
| 185 | */ |
| 186 | if (strip >= td->td_nstrips) { |
| 187 | if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { |
| 188 | TIFFError(tif->tif_name, |
| 189 | "Can not grow image by strips when using separate planes"); |
| 190 | return ((tsize_t) -1); |
| 191 | } |
| 192 | if (!TIFFGrowStrips(tif, 1, module)) |
| 193 | return ((tsize_t) -1); |
| 194 | td->td_stripsperimage = |
| 195 | TIFFhowmany(td->td_imagelength, td->td_rowsperstrip); |
| 196 | } |
| 197 | /* |
| 198 | * Handle delayed allocation of data buffer. This |
| 199 | * permits it to be sized according to the directory |
| 200 | * info. |
| 201 | */ |
| 202 | if (!BUFFERCHECK(tif)) |
| 203 | return ((tsize_t) -1); |
| 204 | tif->tif_curstrip = strip; |
| 205 | tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; |
| 206 | if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { |
| 207 | if (!(*tif->tif_setupencode)(tif)) |
| 208 | return ((tsize_t) -1); |
| 209 | tif->tif_flags |= TIFF_CODERSETUP; |
| 210 | } |
| 211 | tif->tif_flags &= ~TIFF_POSTENCODE; |
| 212 | sample = (tsample_t)(strip / td->td_stripsperimage); |
| 213 | if (!(*tif->tif_preencode)(tif, sample)) |
| 214 | return ((tsize_t) -1); |
| 215 | if (!(*tif->tif_encodestrip)(tif, (tidata_t) data, cc, sample)) |
| 216 | return ((tsize_t) 0); |
| 217 | if (!(*tif->tif_postencode)(tif)) |
| 218 | return ((tsize_t) -1); |
| 219 | if (!isFillOrder(tif, td->td_fillorder) && |
| 220 | (tif->tif_flags & TIFF_NOBITREV) == 0) |
| 221 | TIFFReverseBits(tif->tif_rawdata, tif->tif_rawcc); |
| 222 | if (tif->tif_rawcc > 0 && |
| 223 | !TIFFAppendToStrip(tif, strip, tif->tif_rawdata, tif->tif_rawcc)) |
| 224 | return ((tsize_t) -1); |
| 225 | tif->tif_rawcc = 0; |
| 226 | tif->tif_rawcp = tif->tif_rawdata; |
| 227 | return (cc); |
| 228 | } |
| 229 | |
| 230 | /* |
| 231 | * Write the supplied data to the specified strip. |
| 232 | * There must be space for the data; we don't check |
| 233 | * if strips overlap! |
| 234 | * |
| 235 | * NB: Image length must be setup before writing. |
| 236 | */ |
| 237 | tsize_t |
| 238 | TIFFWriteRawStrip(TIFF* tif, tstrip_t strip, tdata_t data, tsize_t cc) |
| 239 | { |
| 240 | static const char module[] = "TIFFWriteRawStrip"; |
| 241 | TIFFDirectory *td = &tif->tif_dir; |
| 242 | |
| 243 | if (!WRITECHECKSTRIPS(tif, module)) |
| 244 | return ((tsize_t) -1); |
| 245 | /* |
| 246 | * Check strip array to make sure there's space. |
| 247 | * We don't support dynamically growing files that |
| 248 | * have data organized in separate bitplanes because |
| 249 | * it's too painful. In that case we require that |
| 250 | * the imagelength be set properly before the first |
| 251 | * write (so that the strips array will be fully |
| 252 | * allocated above). |
| 253 | */ |
| 254 | if (strip >= td->td_nstrips) { |
| 255 | if (td->td_planarconfig == PLANARCONFIG_SEPARATE) { |
| 256 | TIFFError(tif->tif_name, |
| 257 | "Can not grow image by strips when using separate planes"); |
| 258 | return ((tsize_t) -1); |
| 259 | } |
| 260 | /* |
| 261 | * Watch out for a growing image. The value of |
| 262 | * strips/image will initially be 1 (since it |
| 263 | * can't be deduced until the imagelength is known). |
| 264 | */ |
| 265 | if (strip >= td->td_stripsperimage) |
| 266 | td->td_stripsperimage = |
| 267 | TIFFhowmany(td->td_imagelength,td->td_rowsperstrip); |
| 268 | if (!TIFFGrowStrips(tif, 1, module)) |
| 269 | return ((tsize_t) -1); |
| 270 | } |
| 271 | tif->tif_curstrip = strip; |
| 272 | tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip; |
| 273 | return (TIFFAppendToStrip(tif, strip, (tidata_t) data, cc) ? |
| 274 | cc : (tsize_t) -1); |
| 275 | } |
| 276 | |
| 277 | /* |
| 278 | * Write and compress a tile of data. The |
| 279 | * tile is selected by the (x,y,z,s) coordinates. |
| 280 | */ |
| 281 | tsize_t |
| 282 | TIFFWriteTile(TIFF* tif, |
| 283 | tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s) |
| 284 | { |
| 285 | if (!TIFFCheckTile(tif, x, y, z, s)) |
| 286 | return (-1); |
| 287 | /* |
| 288 | * NB: A tile size of -1 is used instead of tif_tilesize knowing |
| 289 | * that TIFFWriteEncodedTile will clamp this to the tile size. |
| 290 | * This is done because the tile size may not be defined until |
| 291 | * after the output buffer is setup in TIFFWriteBufferSetup. |
| 292 | */ |
| 293 | return (TIFFWriteEncodedTile(tif, |
| 294 | TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1)); |
| 295 | } |
| 296 | |
| 297 | /* |
| 298 | * Encode the supplied data and write it to the |
| 299 | * specified tile. There must be space for the |
| 300 | * data. The function clamps individual writes |
| 301 | * to a tile to the tile size, but does not (and |
| 302 | * can not) check that multiple writes to the same |
| 303 | * tile do not write more than tile size data. |
| 304 | * |
| 305 | * NB: Image length must be setup before writing; this |
| 306 | * interface does not support automatically growing |
| 307 | * the image on each write (as TIFFWriteScanline does). |
| 308 | */ |
| 309 | tsize_t |
| 310 | TIFFWriteEncodedTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) |
| 311 | { |
| 312 | static const char module[] = "TIFFWriteEncodedTile"; |
| 313 | TIFFDirectory *td; |
| 314 | tsample_t sample; |
| 315 | |
| 316 | if (!WRITECHECKTILES(tif, module)) |
| 317 | return ((tsize_t) -1); |
| 318 | td = &tif->tif_dir; |
| 319 | if (tile >= td->td_nstrips) { |
| 320 | TIFFError(module, "%s: Tile %lu out of range, max %lu", |
| 321 | tif->tif_name, (u_long) tile, (u_long) td->td_nstrips); |
| 322 | return ((tsize_t) -1); |
| 323 | } |
| 324 | /* |
| 325 | * Handle delayed allocation of data buffer. This |
| 326 | * permits it to be sized more intelligently (using |
| 327 | * directory information). |
| 328 | */ |
| 329 | if (!BUFFERCHECK(tif)) |
| 330 | return ((tsize_t) -1); |
| 331 | tif->tif_curtile = tile; |
| 332 | /* |
| 333 | * Compute tiles per row & per column to compute |
| 334 | * current row and column |
| 335 | */ |
| 336 | tif->tif_row = (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) |
| 337 | * td->td_tilelength; |
| 338 | tif->tif_col = (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) |
| 339 | * td->td_tilewidth; |
| 340 | |
| 341 | if ((tif->tif_flags & TIFF_CODERSETUP) == 0) { |
| 342 | if (!(*tif->tif_setupencode)(tif)) |
| 343 | return ((tsize_t) -1); |
| 344 | tif->tif_flags |= TIFF_CODERSETUP; |
| 345 | } |
| 346 | tif->tif_flags &= ~TIFF_POSTENCODE; |
| 347 | sample = (tsample_t)(tile/td->td_stripsperimage); |
| 348 | if (!(*tif->tif_preencode)(tif, sample)) |
| 349 | return ((tsize_t) -1); |
| 350 | /* |
| 351 | * Clamp write amount to the tile size. This is mostly |
| 352 | * done so that callers can pass in some large number |
| 353 | * (e.g. -1) and have the tile size used instead. |
| 354 | */ |
| 355 | if ((uint32) cc > tif->tif_tilesize) |
| 356 | cc = tif->tif_tilesize; |
| 357 | if (!(*tif->tif_encodetile)(tif, (tidata_t) data, cc, sample)) |
| 358 | return ((tsize_t) 0); |
| 359 | if (!(*tif->tif_postencode)(tif)) |
| 360 | return ((tsize_t) -1); |
| 361 | if (!isFillOrder(tif, td->td_fillorder) && |
| 362 | (tif->tif_flags & TIFF_NOBITREV) == 0) |
| 363 | TIFFReverseBits((u_char *)tif->tif_rawdata, tif->tif_rawcc); |
| 364 | if (tif->tif_rawcc > 0 && !TIFFAppendToStrip(tif, tile, |
| 365 | tif->tif_rawdata, tif->tif_rawcc)) |
| 366 | return ((tsize_t) -1); |
| 367 | tif->tif_rawcc = 0; |
| 368 | tif->tif_rawcp = tif->tif_rawdata; |
| 369 | return (cc); |
| 370 | } |
| 371 | |
| 372 | /* |
| 373 | * Write the supplied data to the specified strip. |
| 374 | * There must be space for the data; we don't check |
| 375 | * if strips overlap! |
| 376 | * |
| 377 | * NB: Image length must be setup before writing; this |
| 378 | * interface does not support automatically growing |
| 379 | * the image on each write (as TIFFWriteScanline does). |
| 380 | */ |
| 381 | tsize_t |
| 382 | TIFFWriteRawTile(TIFF* tif, ttile_t tile, tdata_t data, tsize_t cc) |
| 383 | { |
| 384 | static const char module[] = "TIFFWriteRawTile"; |
| 385 | |
| 386 | if (!WRITECHECKTILES(tif, module)) |
| 387 | return ((tsize_t) -1); |
| 388 | if (tile >= tif->tif_dir.td_nstrips) { |
| 389 | TIFFError(module, "%s: Tile %lu out of range, max %lu", |
| 390 | tif->tif_name, (u_long) tile, |
| 391 | (u_long) tif->tif_dir.td_nstrips); |
| 392 | return ((tsize_t) -1); |
| 393 | } |
| 394 | return (TIFFAppendToStrip(tif, tile, (tidata_t) data, cc) ? |
| 395 | cc : (tsize_t) -1); |
| 396 | } |
| 397 | |
| 398 | #define isUnspecified(tif, f) \ |
| 399 | (TIFFFieldSet(tif,f) && (tif)->tif_dir.td_imagelength == 0) |
| 400 | |
| 401 | static int |
| 402 | TIFFSetupStrips(TIFF* tif) |
| 403 | { |
| 404 | TIFFDirectory* td = &tif->tif_dir; |
| 405 | |
| 406 | if (isTiled(tif)) |
| 407 | td->td_stripsperimage = |
| 408 | isUnspecified(tif, FIELD_TILEDIMENSIONS) ? |
| 409 | td->td_samplesperpixel : TIFFNumberOfTiles(tif); |
| 410 | else |
| 411 | td->td_stripsperimage = |
| 412 | isUnspecified(tif, FIELD_ROWSPERSTRIP) ? |
| 413 | td->td_samplesperpixel : TIFFNumberOfStrips(tif); |
| 414 | td->td_nstrips = td->td_stripsperimage; |
| 415 | if (td->td_planarconfig == PLANARCONFIG_SEPARATE) |
| 416 | td->td_stripsperimage /= td->td_samplesperpixel; |
| 417 | td->td_stripoffset = (uint32 *) |
| 418 | _TIFFmalloc(td->td_nstrips * sizeof (uint32)); |
| 419 | td->td_stripbytecount = (uint32 *) |
| 420 | _TIFFmalloc(td->td_nstrips * sizeof (uint32)); |
| 421 | if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) |
| 422 | return (0); |
| 423 | /* |
| 424 | * Place data at the end-of-file |
| 425 | * (by setting offsets to zero). |
| 426 | */ |
| 427 | _TIFFmemset(td->td_stripoffset, 0, td->td_nstrips*sizeof (uint32)); |
| 428 | _TIFFmemset(td->td_stripbytecount, 0, td->td_nstrips*sizeof (uint32)); |
| 429 | TIFFSetFieldBit(tif, FIELD_STRIPOFFSETS); |
| 430 | TIFFSetFieldBit(tif, FIELD_STRIPBYTECOUNTS); |
| 431 | return (1); |
| 432 | } |
| 433 | #undef isUnspecified |
| 434 | |
| 435 | /* |
| 436 | * Verify file is writable and that the directory |
| 437 | * information is setup properly. In doing the latter |
| 438 | * we also "freeze" the state of the directory so |
| 439 | * that important information is not changed. |
| 440 | */ |
| 441 | static int |
| 442 | TIFFWriteCheck(TIFF* tif, int tiles, const char* module) |
| 443 | { |
| 444 | if (tif->tif_mode == O_RDONLY) { |
| 445 | TIFFError(module, "%s: File not open for writing", |
| 446 | tif->tif_name); |
| 447 | return (0); |
| 448 | } |
| 449 | if (tiles ^ isTiled(tif)) { |
| 450 | TIFFError(tif->tif_name, tiles ? |
| 451 | "Can not write tiles to a stripped image" : |
| 452 | "Can not write scanlines to a tiled image"); |
| 453 | return (0); |
| 454 | } |
| 455 | /* |
| 456 | * On the first write verify all the required information |
| 457 | * has been setup and initialize any data structures that |
| 458 | * had to wait until directory information was set. |
| 459 | * Note that a lot of our work is assumed to remain valid |
| 460 | * because we disallow any of the important parameters |
| 461 | * from changing after we start writing (i.e. once |
| 462 | * TIFF_BEENWRITING is set, TIFFSetField will only allow |
| 463 | * the image's length to be changed). |
| 464 | */ |
| 465 | if (!TIFFFieldSet(tif, FIELD_IMAGEDIMENSIONS)) { |
| 466 | TIFFError(module, |
| 467 | "%s: Must set \"ImageWidth\" before writing data", |
| 468 | tif->tif_name); |
| 469 | return (0); |
| 470 | } |
| 471 | if (!TIFFFieldSet(tif, FIELD_PLANARCONFIG)) { |
| 472 | TIFFError(module, |
| 473 | "%s: Must set \"PlanarConfiguration\" before writing data", |
| 474 | tif->tif_name); |
| 475 | return (0); |
| 476 | } |
| 477 | if (tif->tif_dir.td_stripoffset == NULL && !TIFFSetupStrips(tif)) { |
| 478 | tif->tif_dir.td_nstrips = 0; |
| 479 | TIFFError(module, "%s: No space for %s arrays", |
| 480 | tif->tif_name, isTiled(tif) ? "tile" : "strip"); |
| 481 | return (0); |
| 482 | } |
| 483 | tif->tif_tilesize = TIFFTileSize(tif); |
| 484 | tif->tif_scanlinesize = TIFFScanlineSize(tif); |
| 485 | tif->tif_flags |= TIFF_BEENWRITING; |
| 486 | return (1); |
| 487 | } |
| 488 | |
| 489 | /* |
| 490 | * Setup the raw data buffer used for encoding. |
| 491 | */ |
| 492 | int |
| 493 | TIFFWriteBufferSetup(TIFF* tif, tdata_t bp, tsize_t size) |
| 494 | { |
| 495 | static const char module[] = "TIFFWriteBufferSetup"; |
| 496 | |
| 497 | if (tif->tif_rawdata) { |
| 498 | if (tif->tif_flags & TIFF_MYBUFFER) { |
| 499 | _TIFFfree(tif->tif_rawdata); |
| 500 | tif->tif_flags &= ~TIFF_MYBUFFER; |
| 501 | } |
| 502 | tif->tif_rawdata = NULL; |
| 503 | } |
| 504 | if (size == (tsize_t) -1) { |
| 505 | size = (isTiled(tif) ? |
| 506 | tif->tif_tilesize : tif->tif_scanlinesize); |
| 507 | /* |
| 508 | * Make raw data buffer at least 8K |
| 509 | */ |
| 510 | if (size < 8*1024) |
| 511 | size = 8*1024; |
| 512 | bp = NULL; /* NB: force malloc */ |
| 513 | } |
| 514 | if (bp == NULL) { |
| 515 | bp = _TIFFmalloc(size); |
| 516 | if (bp == NULL) { |
| 517 | TIFFError(module, "%s: No space for output buffer", |
| 518 | tif->tif_name); |
| 519 | return (0); |
| 520 | } |
| 521 | tif->tif_flags |= TIFF_MYBUFFER; |
| 522 | } else |
| 523 | tif->tif_flags &= ~TIFF_MYBUFFER; |
| 524 | tif->tif_rawdata = (tidata_t) bp; |
| 525 | tif->tif_rawdatasize = size; |
| 526 | tif->tif_rawcc = 0; |
| 527 | tif->tif_rawcp = tif->tif_rawdata; |
| 528 | tif->tif_flags |= TIFF_BUFFERSETUP; |
| 529 | return (1); |
| 530 | } |
| 531 | |
| 532 | /* |
| 533 | * Grow the strip data structures by delta strips. |
| 534 | */ |
| 535 | static int |
| 536 | TIFFGrowStrips(TIFF* tif, int delta, const char* module) |
| 537 | { |
| 538 | TIFFDirectory *td = &tif->tif_dir; |
| 539 | |
| 540 | assert(td->td_planarconfig == PLANARCONFIG_CONTIG); |
| 541 | td->td_stripoffset = (uint32*)_TIFFrealloc(td->td_stripoffset, |
| 542 | (td->td_nstrips + delta) * sizeof (uint32)); |
| 543 | td->td_stripbytecount = (uint32*)_TIFFrealloc(td->td_stripbytecount, |
| 544 | (td->td_nstrips + delta) * sizeof (uint32)); |
| 545 | if (td->td_stripoffset == NULL || td->td_stripbytecount == NULL) { |
| 546 | td->td_nstrips = 0; |
| 547 | TIFFError(module, "%s: No space to expand strip arrays", |
| 548 | tif->tif_name); |
| 549 | return (0); |
| 550 | } |
| 551 | _TIFFmemset(td->td_stripoffset+td->td_nstrips, 0, delta*sizeof (uint32)); |
| 552 | _TIFFmemset(td->td_stripbytecount+td->td_nstrips, 0, delta*sizeof (uint32)); |
| 553 | td->td_nstrips += delta; |
| 554 | return (1); |
| 555 | } |
| 556 | |
| 557 | /* |
| 558 | * Append the data to the specified strip. |
| 559 | * |
| 560 | * NB: We don't check that there's space in the |
| 561 | * file (i.e. that strips do not overlap). |
| 562 | */ |
| 563 | static int |
| 564 | TIFFAppendToStrip(TIFF* tif, tstrip_t strip, tidata_t data, tsize_t cc) |
| 565 | { |
| 566 | TIFFDirectory *td = &tif->tif_dir; |
| 567 | static const char module[] = "TIFFAppendToStrip"; |
| 568 | |
| 569 | if (td->td_stripoffset[strip] == 0 || tif->tif_curoff == 0) { |
| 570 | /* |
| 571 | * No current offset, set the current strip. |
| 572 | */ |
| 573 | if (td->td_stripoffset[strip] != 0) { |
| 574 | if (!SeekOK(tif, td->td_stripoffset[strip])) { |
| 575 | TIFFError(module, |
| 576 | "%s: Seek error at scanline %lu", |
| 577 | tif->tif_name, (u_long) tif->tif_row); |
| 578 | return (0); |
| 579 | } |
| 580 | } else |
| 581 | td->td_stripoffset[strip] = |
| 582 | TIFFSeekFile(tif, (toff_t) 0, SEEK_END); |
| 583 | tif->tif_curoff = td->td_stripoffset[strip]; |
| 584 | } |
| 585 | if (!WriteOK(tif, data, cc)) { |
| 586 | TIFFError(module, "%s: Write error at scanline %lu", |
| 587 | tif->tif_name, (u_long) tif->tif_row); |
| 588 | return (0); |
| 589 | } |
| 590 | tif->tif_curoff += cc; |
| 591 | td->td_stripbytecount[strip] += cc; |
| 592 | return (1); |
| 593 | } |
| 594 | |
| 595 | /* |
| 596 | * Internal version of TIFFFlushData that can be |
| 597 | * called by ``encodestrip routines'' w/o concern |
| 598 | * for infinite recursion. |
| 599 | */ |
| 600 | int |
| 601 | TIFFFlushData1(TIFF* tif) |
| 602 | { |
| 603 | if (tif->tif_rawcc > 0) { |
| 604 | if (!isFillOrder(tif, tif->tif_dir.td_fillorder) && |
| 605 | (tif->tif_flags & TIFF_NOBITREV) == 0) |
| 606 | TIFFReverseBits((u_char *)tif->tif_rawdata, |
| 607 | tif->tif_rawcc); |
| 608 | if (!TIFFAppendToStrip(tif, |
| 609 | isTiled(tif) ? tif->tif_curtile : tif->tif_curstrip, |
| 610 | tif->tif_rawdata, tif->tif_rawcc)) |
| 611 | return (0); |
| 612 | tif->tif_rawcc = 0; |
| 613 | tif->tif_rawcp = tif->tif_rawdata; |
| 614 | } |
| 615 | return (1); |
| 616 | } |
| 617 | |
| 618 | /* |
| 619 | * Set the current write offset. This should only be |
| 620 | * used to set the offset to a known previous location |
| 621 | * (very carefully), or to 0 so that the next write gets |
| 622 | * appended to the end of the file. |
| 623 | */ |
| 624 | void |
| 625 | TIFFSetWriteOffset(TIFF* tif, toff_t off) |
| 626 | { |
| 627 | tif->tif_curoff = off; |
| 628 | } |