]>
Commit | Line | Data |
---|---|---|
b47c832e RR |
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 | } |