Line data Source code
1 : /*
2 : * Copyright (c) 1988-1997 Sam Leffler
3 : * Copyright (c) 1991-1997 Silicon Graphics, Inc.
4 : *
5 : * Permission to use, copy, modify, distribute, and sell this software and
6 : * its documentation for any purpose is hereby granted without fee, provided
7 : * that (i) the above copyright notices and this permission notice appear in
8 : * all copies of the software and related documentation, and (ii) the names of
9 : * Sam Leffler and Silicon Graphics may not be used in any advertising or
10 : * publicity relating to the software without the specific, prior written
11 : * permission of Sam Leffler and Silicon Graphics.
12 : *
13 : * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
14 : * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
15 : * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
16 : *
17 : * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
18 : * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
19 : * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20 : * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF
21 : * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
22 : * OF THIS SOFTWARE.
23 : */
24 :
25 : /*
26 : * TIFF Library.
27 : * Scanline-oriented Read Support
28 : */
29 : #include "tiffiop.h"
30 : #include <limits.h>
31 : #include <stdio.h>
32 :
33 : int TIFFFillStrip(TIFF *tif, uint32_t strip);
34 : int TIFFFillTile(TIFF *tif, uint32_t tile);
35 : static int TIFFStartStrip(TIFF *tif, uint32_t strip);
36 : static int TIFFStartTile(TIFF *tif, uint32_t tile);
37 : static int TIFFCheckRead(TIFF *, int);
38 : static tmsize_t TIFFReadRawStrip1(TIFF *tif, uint32_t strip, void *buf,
39 : tmsize_t size, const char *module);
40 : static tmsize_t TIFFReadRawTile1(TIFF *tif, uint32_t tile, void *buf,
41 : tmsize_t size, const char *module);
42 :
43 : #define NOSTRIP ((uint32_t)(-1)) /* undefined state */
44 : #define NOTILE ((uint32_t)(-1)) /* undefined state */
45 :
46 : #define INITIAL_THRESHOLD (1024 * 1024)
47 : #define THRESHOLD_MULTIPLIER 10
48 : #define MAX_THRESHOLD \
49 : (THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * THRESHOLD_MULTIPLIER * \
50 : INITIAL_THRESHOLD)
51 :
52 : #define TIFF_INT64_MAX ((((int64_t)0x7FFFFFFF) << 32) | 0xFFFFFFFF)
53 :
54 : /* Read 'size' bytes in tif_rawdata buffer starting at offset 'rawdata_offset'
55 : * Returns 1 in case of success, 0 otherwise. */
56 23096 : static int TIFFReadAndRealloc(TIFF *tif, tmsize_t size, tmsize_t rawdata_offset,
57 : int is_strip, uint32_t strip_or_tile,
58 : const char *module)
59 : {
60 : #if SIZEOF_SIZE_T == 8
61 23096 : tmsize_t threshold = INITIAL_THRESHOLD;
62 : #endif
63 23096 : tmsize_t already_read = 0;
64 :
65 : #if SIZEOF_SIZE_T != 8
66 : /* On 32 bit processes, if the request is large enough, check against */
67 : /* file size */
68 : if (size > 1000 * 1000 * 1000)
69 : {
70 : uint64_t filesize = TIFFGetFileSize(tif);
71 : if ((uint64_t)size >= filesize)
72 : {
73 : TIFFErrorExtR(tif, module,
74 : "Chunk size requested is larger than file size.");
75 : return 0;
76 : }
77 : }
78 : #endif
79 :
80 : /* On 64 bit processes, read first a maximum of 1 MB, then 10 MB, etc */
81 : /* so as to avoid allocating too much memory in case the file is too */
82 : /* short. We could ask for the file size, but this might be */
83 : /* expensive with some I/O layers (think of reading a gzipped file) */
84 : /* Restrict to 64 bit processes, so as to avoid reallocs() */
85 : /* on 32 bit processes where virtual memory is scarce. */
86 46168 : while (already_read < size)
87 : {
88 : tmsize_t bytes_read;
89 23099 : tmsize_t to_read = size - already_read;
90 : #if SIZEOF_SIZE_T == 8
91 23099 : if (to_read >= threshold && threshold < MAX_THRESHOLD &&
92 4 : already_read + to_read + rawdata_offset > tif->tif_rawdatasize)
93 : {
94 4 : to_read = threshold;
95 4 : threshold *= THRESHOLD_MULTIPLIER;
96 : }
97 : #endif
98 23099 : if (already_read + to_read + rawdata_offset > tif->tif_rawdatasize)
99 : {
100 : uint8_t *new_rawdata;
101 1936 : assert((tif->tif_flags & TIFF_MYBUFFER) != 0);
102 1936 : tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64(
103 : (uint64_t)already_read + to_read + rawdata_offset, 1024);
104 1936 : if (tif->tif_rawdatasize == 0)
105 : {
106 0 : TIFFErrorExtR(tif, module, "Invalid buffer size");
107 0 : return 0;
108 : }
109 1936 : new_rawdata = (uint8_t *)_TIFFreallocExt(tif, tif->tif_rawdata,
110 : tif->tif_rawdatasize);
111 1936 : if (new_rawdata == 0)
112 : {
113 0 : TIFFErrorExtR(tif, module,
114 : "No space for data buffer at scanline %" PRIu32,
115 : tif->tif_row);
116 0 : _TIFFfreeExt(tif, tif->tif_rawdata);
117 0 : tif->tif_rawdata = 0;
118 0 : tif->tif_rawdatasize = 0;
119 0 : return 0;
120 : }
121 1936 : tif->tif_rawdata = new_rawdata;
122 : }
123 23099 : if (tif->tif_rawdata == NULL)
124 : {
125 : /* should not happen in practice but helps CoverityScan */
126 0 : return 0;
127 : }
128 :
129 23099 : bytes_read = TIFFReadFile(
130 : tif, tif->tif_rawdata + rawdata_offset + already_read, to_read);
131 23099 : already_read += bytes_read;
132 23099 : if (bytes_read != to_read)
133 : {
134 27 : memset(tif->tif_rawdata + rawdata_offset + already_read, 0,
135 27 : tif->tif_rawdatasize - rawdata_offset - already_read);
136 27 : if (is_strip)
137 : {
138 4 : TIFFErrorExtR(tif, module,
139 : "Read error at scanline %" PRIu32
140 : "; got %" TIFF_SSIZE_FORMAT " bytes, "
141 : "expected %" TIFF_SSIZE_FORMAT,
142 : tif->tif_row, already_read, size);
143 : }
144 : else
145 : {
146 23 : TIFFErrorExtR(tif, module,
147 : "Read error at row %" PRIu32 ", col %" PRIu32
148 : ", tile %" PRIu32 "; "
149 : "got %" TIFF_SSIZE_FORMAT
150 : " bytes, expected %" TIFF_SSIZE_FORMAT "",
151 : tif->tif_row, tif->tif_col, strip_or_tile,
152 : already_read, size);
153 : }
154 27 : return 0;
155 : }
156 : }
157 23069 : return 1;
158 : }
159 :
160 59 : static int TIFFFillStripPartial(TIFF *tif, int strip, tmsize_t read_ahead,
161 : int restart)
162 : {
163 : static const char module[] = "TIFFFillStripPartial";
164 59 : TIFFDirectory *td = &tif->tif_dir;
165 : tmsize_t unused_data;
166 : uint64_t read_offset;
167 : tmsize_t to_read;
168 : tmsize_t read_ahead_mod;
169 : /* tmsize_t bytecountm; */
170 :
171 : /*
172 : * Expand raw data buffer, if needed, to hold data
173 : * strip coming from file (perhaps should set upper
174 : * bound on the size of a buffer we'll use?).
175 : */
176 :
177 : /* bytecountm=(tmsize_t) TIFFGetStrileByteCount(tif, strip); */
178 :
179 : /* Not completely sure where the * 2 comes from, but probably for */
180 : /* an exponentional growth strategy of tif_rawdatasize */
181 59 : if (read_ahead < TIFF_TMSIZE_T_MAX / 2)
182 59 : read_ahead_mod = read_ahead * 2;
183 : else
184 0 : read_ahead_mod = read_ahead;
185 59 : if (read_ahead_mod > tif->tif_rawdatasize)
186 : {
187 34 : assert(restart);
188 :
189 34 : tif->tif_curstrip = NOSTRIP;
190 34 : if ((tif->tif_flags & TIFF_MYBUFFER) == 0)
191 : {
192 0 : TIFFErrorExtR(tif, module,
193 : "Data buffer too small to hold part of strip %d",
194 : strip);
195 0 : return (0);
196 : }
197 : }
198 :
199 59 : if (restart)
200 : {
201 34 : tif->tif_rawdataloaded = 0;
202 34 : tif->tif_rawdataoff = 0;
203 : }
204 :
205 : /*
206 : ** If we are reading more data, move any unused data to the
207 : ** start of the buffer.
208 : */
209 59 : if (tif->tif_rawdataloaded > 0)
210 23 : unused_data =
211 23 : tif->tif_rawdataloaded - (tif->tif_rawcp - tif->tif_rawdata);
212 : else
213 36 : unused_data = 0;
214 :
215 59 : if (unused_data > 0)
216 : {
217 23 : assert((tif->tif_flags & TIFF_BUFFERMMAP) == 0);
218 23 : memmove(tif->tif_rawdata, tif->tif_rawcp, unused_data);
219 : }
220 :
221 : /*
222 : ** Seek to the point in the file where more data should be read.
223 : */
224 59 : read_offset = TIFFGetStrileOffset(tif, strip);
225 59 : if (read_offset > UINT64_MAX - tif->tif_rawdataoff ||
226 59 : read_offset + tif->tif_rawdataoff > UINT64_MAX - tif->tif_rawdataloaded)
227 : {
228 0 : TIFFErrorExtR(tif, module,
229 : "Seek error at scanline %" PRIu32 ", strip %d",
230 : tif->tif_row, strip);
231 0 : return 0;
232 : }
233 59 : read_offset += tif->tif_rawdataoff + tif->tif_rawdataloaded;
234 :
235 59 : if (!SeekOK(tif, read_offset))
236 : {
237 0 : TIFFErrorExtR(tif, module,
238 : "Seek error at scanline %" PRIu32 ", strip %d",
239 : tif->tif_row, strip);
240 0 : return 0;
241 : }
242 :
243 : /*
244 : ** How much do we want to read?
245 : */
246 59 : if (read_ahead_mod > tif->tif_rawdatasize)
247 34 : to_read = read_ahead_mod - unused_data;
248 : else
249 25 : to_read = tif->tif_rawdatasize - unused_data;
250 59 : if ((uint64_t)to_read > TIFFGetStrileByteCount(tif, strip) -
251 59 : tif->tif_rawdataoff - tif->tif_rawdataloaded)
252 : {
253 33 : to_read = (tmsize_t)TIFFGetStrileByteCount(tif, strip) -
254 33 : tif->tif_rawdataoff - tif->tif_rawdataloaded;
255 : }
256 :
257 59 : assert((tif->tif_flags & TIFF_BUFFERMMAP) == 0);
258 59 : if (!TIFFReadAndRealloc(tif, to_read, unused_data, 1, /* is_strip */
259 : 0, /* strip_or_tile */
260 : module))
261 : {
262 0 : return 0;
263 : }
264 :
265 59 : tif->tif_rawdataoff =
266 59 : tif->tif_rawdataoff + tif->tif_rawdataloaded - unused_data;
267 59 : tif->tif_rawdataloaded = unused_data + to_read;
268 :
269 59 : tif->tif_rawcc = tif->tif_rawdataloaded;
270 59 : tif->tif_rawcp = tif->tif_rawdata;
271 :
272 59 : if (!isFillOrder(tif, td->td_fillorder) &&
273 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
274 : {
275 0 : assert((tif->tif_flags & TIFF_BUFFERMMAP) == 0);
276 0 : TIFFReverseBits(tif->tif_rawdata + unused_data, to_read);
277 : }
278 :
279 : /*
280 : ** When starting a strip from the beginning we need to
281 : ** restart the decoder.
282 : */
283 59 : if (restart)
284 : {
285 :
286 : #ifdef JPEG_SUPPORT
287 : /* A bit messy since breaks the codec abstraction. Ultimately */
288 : /* there should be a function pointer for that, but it seems */
289 : /* only JPEG is affected. */
290 : /* For JPEG, if there are multiple scans (can generally be known */
291 : /* with the read_ahead used), we need to read the whole strip */
292 36 : if (tif->tif_dir.td_compression == COMPRESSION_JPEG &&
293 2 : (uint64_t)tif->tif_rawcc < TIFFGetStrileByteCount(tif, strip))
294 : {
295 2 : if (TIFFJPEGIsFullStripRequired(tif))
296 : {
297 2 : return TIFFFillStrip(tif, strip);
298 : }
299 : }
300 : #endif
301 :
302 32 : return TIFFStartStrip(tif, strip);
303 : }
304 : else
305 : {
306 25 : return 1;
307 : }
308 : }
309 :
310 : /*
311 : * Seek to a random row+sample in a file.
312 : *
313 : * Only used by TIFFReadScanline, and is only used on
314 : * strip organized files. We do some tricky stuff to try
315 : * and avoid reading the whole compressed raw data for big
316 : * strips.
317 : */
318 153235 : static int TIFFSeek(TIFF *tif, uint32_t row, uint16_t sample)
319 : {
320 153235 : TIFFDirectory *td = &tif->tif_dir;
321 : uint32_t strip;
322 : int whole_strip;
323 153235 : tmsize_t read_ahead = 0;
324 :
325 : /*
326 : ** Establish what strip we are working from.
327 : */
328 153235 : if (row >= td->td_imagelength)
329 : { /* out of range */
330 0 : TIFFErrorExtR(tif, tif->tif_name,
331 : "%" PRIu32 ": Row out of range, max %" PRIu32 "", row,
332 : td->td_imagelength);
333 0 : return (0);
334 : }
335 153235 : if (td->td_planarconfig == PLANARCONFIG_SEPARATE)
336 : {
337 64244 : if (sample >= td->td_samplesperpixel)
338 : {
339 0 : TIFFErrorExtR(tif, tif->tif_name,
340 : "%" PRIu16 ": Sample out of range, max %" PRIu16 "",
341 0 : sample, td->td_samplesperpixel);
342 0 : return (0);
343 : }
344 64244 : strip = (uint32_t)sample * td->td_stripsperimage +
345 64244 : row / td->td_rowsperstrip;
346 : }
347 : else
348 88991 : strip = row / td->td_rowsperstrip;
349 :
350 : /*
351 : * Do we want to treat this strip as one whole chunk or
352 : * read it a few lines at a time?
353 : */
354 : #if defined(CHUNKY_STRIP_READ_SUPPORT)
355 153235 : whole_strip = TIFFGetStrileByteCount(tif, strip) < 10 || isMapped(tif);
356 153235 : if (td->td_compression == COMPRESSION_LERC ||
357 153235 : td->td_compression == COMPRESSION_JBIG)
358 : {
359 : /* Ideally plugins should have a way to declare they don't support
360 : * chunk strip */
361 0 : whole_strip = 1;
362 : }
363 :
364 153235 : if (!whole_strip)
365 : {
366 : /* 16 is for YCbCr mode where we may need to read 16 */
367 : /* lines at a time to get a decompressed line, and 5000 */
368 : /* is some constant value, for example for JPEG tables */
369 :
370 : /* coverity[dead_error_line:SUPPRESS] */
371 153233 : if (tif->tif_scanlinesize < TIFF_TMSIZE_T_MAX / 16 &&
372 153233 : tif->tif_scanlinesize * 16 < TIFF_TMSIZE_T_MAX - 5000)
373 : {
374 153233 : read_ahead = tif->tif_scanlinesize * 16 + 5000;
375 : }
376 : else
377 : {
378 0 : read_ahead = tif->tif_scanlinesize;
379 : }
380 : }
381 : #else
382 : whole_strip = 1;
383 : #endif
384 :
385 : /*
386 : * If we haven't loaded this strip, do so now, possibly
387 : * only reading the first part.
388 : */
389 153235 : if (strip != tif->tif_curstrip)
390 : { /* different strip, refill */
391 :
392 36 : if (whole_strip)
393 : {
394 2 : if (!TIFFFillStrip(tif, strip))
395 2 : return (0);
396 : }
397 : #if defined(CHUNKY_STRIP_READ_SUPPORT)
398 : else
399 : {
400 34 : if (!TIFFFillStripPartial(tif, strip, read_ahead, 1))
401 2 : return 0;
402 : }
403 : #endif
404 : }
405 :
406 : #if defined(CHUNKY_STRIP_READ_SUPPORT)
407 : /*
408 : ** If we already have some data loaded, do we need to read some more?
409 : */
410 153199 : else if (!whole_strip)
411 : {
412 : /* coverity[dead_error_line:SUPPRESS] */
413 153199 : if (((tif->tif_rawdata + tif->tif_rawdataloaded) - tif->tif_rawcp) <
414 148298 : read_ahead &&
415 148298 : (uint64_t)tif->tif_rawdataoff + tif->tif_rawdataloaded <
416 148298 : TIFFGetStrileByteCount(tif, strip))
417 : {
418 25 : if (!TIFFFillStripPartial(tif, strip, read_ahead, 0))
419 0 : return 0;
420 : }
421 : }
422 : #endif
423 :
424 153231 : if (row < tif->tif_row)
425 : {
426 : /*
427 : * Moving backwards within the same strip: backup
428 : * to the start and then decode forward (below).
429 : *
430 : * NB: If you're planning on lots of random access within a
431 : * strip, it's better to just read and decode the entire
432 : * strip, and then access the decoded data in a random fashion.
433 : */
434 :
435 25 : if (tif->tif_rawdataoff != 0)
436 : {
437 0 : if (!TIFFFillStripPartial(tif, strip, read_ahead, 1))
438 0 : return 0;
439 : }
440 : else
441 : {
442 25 : if (!TIFFStartStrip(tif, strip))
443 0 : return (0);
444 : }
445 : }
446 :
447 153231 : if (row != tif->tif_row)
448 : {
449 : /*
450 : * Seek forward to the desired row.
451 : */
452 :
453 : /* TODO: Will this really work with partial buffers? */
454 :
455 0 : if (!(*tif->tif_seek)(tif, row - tif->tif_row))
456 0 : return (0);
457 0 : tif->tif_row = row;
458 : }
459 :
460 153231 : return (1);
461 : }
462 :
463 153235 : int TIFFReadScanline(TIFF *tif, void *buf, uint32_t row, uint16_t sample)
464 : {
465 : int e;
466 :
467 153235 : if (!TIFFCheckRead(tif, 0))
468 0 : return (-1);
469 153235 : if ((e = TIFFSeek(tif, row, sample)) != 0)
470 : {
471 : /*
472 : * Decompress desired row into user buffer.
473 : */
474 153231 : e = (*tif->tif_decoderow)(tif, (uint8_t *)buf, tif->tif_scanlinesize,
475 : sample);
476 :
477 : /* we are now poised at the beginning of the next row */
478 153231 : tif->tif_row = row + 1;
479 :
480 153231 : if (e)
481 153229 : (*tif->tif_postdecode)(tif, (uint8_t *)buf, tif->tif_scanlinesize);
482 : }
483 : else
484 : {
485 : /* See TIFFReadEncodedStrip comment regarding TIFFTAG_FAXFILLFUNC. */
486 4 : if (buf)
487 4 : memset(buf, 0, (size_t)tif->tif_scanlinesize);
488 : }
489 153235 : return (e > 0 ? 1 : -1);
490 : }
491 :
492 : /*
493 : * Calculate the strip size according to the number of
494 : * rows in the strip (check for truncated last strip on any
495 : * of the separations).
496 : */
497 2100360 : static tmsize_t TIFFReadEncodedStripGetStripSize(TIFF *tif, uint32_t strip,
498 : uint16_t *pplane)
499 : {
500 : static const char module[] = "TIFFReadEncodedStrip";
501 2100360 : TIFFDirectory *td = &tif->tif_dir;
502 : uint32_t rowsperstrip;
503 : uint32_t stripsperplane;
504 : uint32_t stripinplane;
505 : uint32_t rows;
506 : tmsize_t stripsize;
507 2100360 : if (!TIFFCheckRead(tif, 0))
508 0 : return ((tmsize_t)(-1));
509 2100360 : if (strip >= td->td_nstrips)
510 : {
511 0 : TIFFErrorExtR(tif, module,
512 : "%" PRIu32 ": Strip out of range, max %" PRIu32, strip,
513 : td->td_nstrips);
514 0 : return ((tmsize_t)(-1));
515 : }
516 :
517 2100360 : rowsperstrip = td->td_rowsperstrip;
518 2100360 : if (rowsperstrip > td->td_imagelength)
519 16 : rowsperstrip = td->td_imagelength;
520 2100360 : if (rowsperstrip == 0)
521 : {
522 0 : TIFFErrorExtR(tif, module, "rowsperstrip is zero");
523 0 : return ((tmsize_t)(-1));
524 : }
525 2100360 : stripsperplane =
526 2100360 : TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
527 2100360 : stripinplane = (strip % stripsperplane);
528 2100360 : if (pplane)
529 2100350 : *pplane = (uint16_t)(strip / stripsperplane);
530 2100360 : rows = td->td_imagelength - stripinplane * rowsperstrip;
531 2100360 : if (rows > rowsperstrip)
532 2083670 : rows = rowsperstrip;
533 2100360 : stripsize = TIFFVStripSize(tif, rows);
534 2100360 : if (stripsize == 0)
535 0 : return ((tmsize_t)(-1));
536 2100360 : return stripsize;
537 : }
538 :
539 : /*
540 : * Read a strip of data and decompress the specified
541 : * amount into the user-supplied buffer.
542 : */
543 2100310 : tmsize_t TIFFReadEncodedStrip(TIFF *tif, uint32_t strip, void *buf,
544 : tmsize_t size)
545 : {
546 : static const char module[] = "TIFFReadEncodedStrip";
547 2100310 : TIFFDirectory *td = &tif->tif_dir;
548 : tmsize_t stripsize;
549 : uint16_t plane;
550 :
551 2100310 : stripsize = TIFFReadEncodedStripGetStripSize(tif, strip, &plane);
552 2100300 : if (stripsize == ((tmsize_t)(-1)))
553 0 : return ((tmsize_t)(-1));
554 :
555 : /* shortcut to avoid an extra memcpy() */
556 2100300 : if (td->td_compression == COMPRESSION_NONE && size != (tmsize_t)(-1) &&
557 2083840 : size >= stripsize && !isMapped(tif) &&
558 2083840 : ((tif->tif_flags & TIFF_NOREADRAW) == 0))
559 : {
560 2083840 : if (TIFFReadRawStrip1(tif, strip, buf, stripsize, module) != stripsize)
561 65 : return ((tmsize_t)(-1));
562 :
563 2083770 : if (!isFillOrder(tif, td->td_fillorder) &&
564 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
565 0 : TIFFReverseBits((uint8_t *)buf, stripsize);
566 :
567 2083770 : (*tif->tif_postdecode)(tif, (uint8_t *)buf, stripsize);
568 2083780 : return (stripsize);
569 : }
570 :
571 16458 : if ((size != (tmsize_t)(-1)) && (size < stripsize))
572 0 : stripsize = size;
573 16458 : if (!TIFFFillStrip(tif, strip))
574 : {
575 : /* The output buf may be NULL, in particular if TIFFTAG_FAXFILLFUNC
576 : is being used. Thus, memset must be conditional on buf not NULL. */
577 7 : if (buf)
578 7 : memset(buf, 0, (size_t)stripsize);
579 7 : return ((tmsize_t)(-1));
580 : }
581 16450 : if ((*tif->tif_decodestrip)(tif, (uint8_t *)buf, stripsize, plane) <= 0)
582 5 : return ((tmsize_t)(-1));
583 16445 : (*tif->tif_postdecode)(tif, (uint8_t *)buf, stripsize);
584 16445 : return (stripsize);
585 : }
586 :
587 : /* Variant of TIFFReadEncodedStrip() that does
588 : * * if *buf == NULL, *buf = _TIFFmallocExt(tif, bufsizetoalloc) only after
589 : * TIFFFillStrip() has succeeded. This avoid excessive memory allocation in case
590 : * of truncated file.
591 : * * calls regular TIFFReadEncodedStrip() if *buf != NULL
592 : */
593 53 : tmsize_t _TIFFReadEncodedStripAndAllocBuffer(TIFF *tif, uint32_t strip,
594 : void **buf,
595 : tmsize_t bufsizetoalloc,
596 : tmsize_t size_to_read)
597 : {
598 : tmsize_t this_stripsize;
599 : uint16_t plane;
600 :
601 53 : if (*buf != NULL)
602 : {
603 0 : return TIFFReadEncodedStrip(tif, strip, *buf, size_to_read);
604 : }
605 :
606 53 : this_stripsize = TIFFReadEncodedStripGetStripSize(tif, strip, &plane);
607 53 : if (this_stripsize == ((tmsize_t)(-1)))
608 0 : return ((tmsize_t)(-1));
609 :
610 53 : if ((size_to_read != (tmsize_t)(-1)) && (size_to_read < this_stripsize))
611 0 : this_stripsize = size_to_read;
612 53 : if (!TIFFFillStrip(tif, strip))
613 0 : return ((tmsize_t)(-1));
614 :
615 53 : *buf = _TIFFmallocExt(tif, bufsizetoalloc);
616 53 : if (*buf == NULL)
617 : {
618 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "No space for strip buffer");
619 0 : return ((tmsize_t)(-1));
620 : }
621 53 : _TIFFmemset(*buf, 0, bufsizetoalloc);
622 :
623 53 : if ((*tif->tif_decodestrip)(tif, (uint8_t *)*buf, this_stripsize, plane) <=
624 : 0)
625 0 : return ((tmsize_t)(-1));
626 53 : (*tif->tif_postdecode)(tif, (uint8_t *)*buf, this_stripsize);
627 53 : return (this_stripsize);
628 : }
629 :
630 2083860 : static tmsize_t TIFFReadRawStrip1(TIFF *tif, uint32_t strip, void *buf,
631 : tmsize_t size, const char *module)
632 : {
633 2083860 : assert((tif->tif_flags & TIFF_NOREADRAW) == 0);
634 2083860 : if (!isMapped(tif))
635 : {
636 : tmsize_t cc;
637 :
638 2083840 : if (!SeekOK(tif, TIFFGetStrileOffset(tif, strip)))
639 : {
640 0 : TIFFErrorExtR(tif, module,
641 : "Seek error at scanline %" PRIu32 ", strip %" PRIu32,
642 : tif->tif_row, strip);
643 0 : return ((tmsize_t)(-1));
644 : }
645 2083850 : cc = TIFFReadFile(tif, buf, size);
646 2083850 : if (cc != size)
647 : {
648 65 : TIFFErrorExtR(tif, module,
649 : "Read error at scanline %" PRIu32
650 : "; got %" TIFF_SSIZE_FORMAT
651 : " bytes, expected %" TIFF_SSIZE_FORMAT,
652 : tif->tif_row, cc, size);
653 65 : return ((tmsize_t)(-1));
654 : }
655 : }
656 : else
657 : {
658 16 : tmsize_t ma = 0;
659 : tmsize_t n;
660 16 : if ((TIFFGetStrileOffset(tif, strip) > (uint64_t)TIFF_TMSIZE_T_MAX) ||
661 0 : ((ma = (tmsize_t)TIFFGetStrileOffset(tif, strip)) > tif->tif_size))
662 : {
663 0 : n = 0;
664 : }
665 0 : else if (ma > TIFF_TMSIZE_T_MAX - size)
666 : {
667 0 : n = 0;
668 : }
669 : else
670 : {
671 0 : tmsize_t mb = ma + size;
672 0 : if (mb > tif->tif_size)
673 0 : n = tif->tif_size - ma;
674 : else
675 0 : n = size;
676 : }
677 0 : if (n != size)
678 : {
679 0 : TIFFErrorExtR(tif, module,
680 : "Read error at scanline %" PRIu32 ", strip %" PRIu32
681 : "; got %" TIFF_SSIZE_FORMAT
682 : " bytes, expected %" TIFF_SSIZE_FORMAT,
683 : tif->tif_row, strip, n, size);
684 0 : return ((tmsize_t)(-1));
685 : }
686 0 : _TIFFmemcpy(buf, tif->tif_base + ma, size);
687 : }
688 2083790 : return (size);
689 : }
690 :
691 23037 : static tmsize_t TIFFReadRawStripOrTile2(TIFF *tif, uint32_t strip_or_tile,
692 : int is_strip, tmsize_t size,
693 : const char *module)
694 : {
695 23037 : assert(!isMapped(tif));
696 23037 : assert((tif->tif_flags & TIFF_NOREADRAW) == 0);
697 :
698 23037 : if (!SeekOK(tif, TIFFGetStrileOffset(tif, strip_or_tile)))
699 : {
700 0 : if (is_strip)
701 : {
702 0 : TIFFErrorExtR(tif, module,
703 : "Seek error at scanline %" PRIu32 ", strip %" PRIu32,
704 : tif->tif_row, strip_or_tile);
705 : }
706 : else
707 : {
708 0 : TIFFErrorExtR(tif, module,
709 : "Seek error at row %" PRIu32 ", col %" PRIu32
710 : ", tile %" PRIu32,
711 : tif->tif_row, tif->tif_col, strip_or_tile);
712 : }
713 0 : return ((tmsize_t)(-1));
714 : }
715 :
716 23037 : if (!TIFFReadAndRealloc(tif, size, 0, is_strip, strip_or_tile, module))
717 : {
718 27 : return ((tmsize_t)(-1));
719 : }
720 :
721 23010 : return (size);
722 : }
723 :
724 : /*
725 : * Read a strip of data from the file.
726 : */
727 4 : tmsize_t TIFFReadRawStrip(TIFF *tif, uint32_t strip, void *buf, tmsize_t size)
728 : {
729 : static const char module[] = "TIFFReadRawStrip";
730 4 : TIFFDirectory *td = &tif->tif_dir;
731 : uint64_t bytecount64;
732 : tmsize_t bytecountm;
733 :
734 4 : if (!TIFFCheckRead(tif, 0))
735 0 : return ((tmsize_t)(-1));
736 4 : if (strip >= td->td_nstrips)
737 : {
738 0 : TIFFErrorExtR(tif, module,
739 : "%" PRIu32 ": Strip out of range, max %" PRIu32, strip,
740 : td->td_nstrips);
741 0 : return ((tmsize_t)(-1));
742 : }
743 4 : if (tif->tif_flags & TIFF_NOREADRAW)
744 : {
745 0 : TIFFErrorExtR(tif, module,
746 : "Compression scheme does not support access to raw "
747 : "uncompressed data");
748 0 : return ((tmsize_t)(-1));
749 : }
750 4 : bytecount64 = TIFFGetStrileByteCount(tif, strip);
751 4 : if (size != (tmsize_t)(-1) && (uint64_t)size <= bytecount64)
752 4 : bytecountm = size;
753 : else
754 0 : bytecountm = _TIFFCastUInt64ToSSize(tif, bytecount64, module);
755 4 : if (bytecountm == 0)
756 : {
757 0 : return ((tmsize_t)(-1));
758 : }
759 4 : return (TIFFReadRawStrip1(tif, strip, buf, bytecountm, module));
760 : }
761 :
762 : TIFF_NOSANITIZE_UNSIGNED_INT_OVERFLOW
763 2 : static uint64_t NoSanitizeSubUInt64(uint64_t a, uint64_t b) { return a - b; }
764 :
765 : /*
766 : * Read the specified strip and setup for decoding. The data buffer is
767 : * expanded, as necessary, to hold the strip's data.
768 : */
769 16514 : int TIFFFillStrip(TIFF *tif, uint32_t strip)
770 : {
771 : static const char module[] = "TIFFFillStrip";
772 16514 : TIFFDirectory *td = &tif->tif_dir;
773 :
774 16514 : if ((tif->tif_flags & TIFF_NOREADRAW) == 0)
775 : {
776 16514 : uint64_t bytecount = TIFFGetStrileByteCount(tif, strip);
777 16514 : if (bytecount == 0 || bytecount > (uint64_t)TIFF_INT64_MAX)
778 : {
779 2 : TIFFErrorExtR(tif, module,
780 : "Invalid strip byte count %" PRIu64
781 : ", strip %" PRIu32,
782 : bytecount, strip);
783 2 : return (0);
784 : }
785 :
786 : /* To avoid excessive memory allocations: */
787 : /* Byte count should normally not be larger than a number of */
788 : /* times the uncompressed size plus some margin */
789 16512 : if (bytecount > 1024 * 1024)
790 : {
791 : /* 10 and 4096 are just values that could be adjusted. */
792 : /* Hopefully they are safe enough for all codecs */
793 3 : tmsize_t stripsize = TIFFStripSize(tif);
794 3 : if (stripsize != 0 && (bytecount - 4096) / 10 > (uint64_t)stripsize)
795 : {
796 1 : uint64_t newbytecount = (uint64_t)stripsize * 10 + 4096;
797 1 : TIFFErrorExtR(tif, module,
798 : "Too large strip byte count %" PRIu64
799 : ", strip %" PRIu32 ". Limiting to %" PRIu64,
800 : bytecount, strip, newbytecount);
801 1 : bytecount = newbytecount;
802 : }
803 : }
804 :
805 16512 : if (isMapped(tif))
806 : {
807 : /*
808 : * We must check for overflow, potentially causing
809 : * an OOB read. Instead of simple
810 : *
811 : * TIFFGetStrileOffset(tif, strip)+bytecount > tif->tif_size
812 : *
813 : * comparison (which can overflow) we do the following
814 : * two comparisons:
815 : */
816 4 : if (bytecount > (uint64_t)tif->tif_size ||
817 4 : TIFFGetStrileOffset(tif, strip) >
818 4 : (uint64_t)tif->tif_size - bytecount)
819 : {
820 : /*
821 : * This error message might seem strange, but
822 : * it's what would happen if a read were done
823 : * instead.
824 : */
825 4 : TIFFErrorExtR(
826 : tif, module,
827 :
828 : "Read error on strip %" PRIu32 "; "
829 : "got %" PRIu64 " bytes, expected %" PRIu64,
830 : strip,
831 2 : NoSanitizeSubUInt64(tif->tif_size,
832 : TIFFGetStrileOffset(tif, strip)),
833 : bytecount);
834 2 : tif->tif_curstrip = NOSTRIP;
835 2 : return (0);
836 : }
837 : }
838 :
839 16510 : if (isMapped(tif) && (isFillOrder(tif, td->td_fillorder) ||
840 0 : (tif->tif_flags & TIFF_NOBITREV)))
841 : {
842 : /*
843 : * The image is mapped into memory and we either don't
844 : * need to flip bits or the compression routine is
845 : * going to handle this operation itself. In this
846 : * case, avoid copying the raw data and instead just
847 : * reference the data from the memory mapped file
848 : * image. This assumes that the decompression
849 : * routines do not modify the contents of the raw data
850 : * buffer (if they try to, the application will get a
851 : * fault since the file is mapped read-only).
852 : */
853 2 : if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
854 : {
855 0 : _TIFFfreeExt(tif, tif->tif_rawdata);
856 0 : tif->tif_rawdata = NULL;
857 0 : tif->tif_rawdatasize = 0;
858 : }
859 2 : tif->tif_flags &= ~TIFF_MYBUFFER;
860 2 : tif->tif_rawdatasize = (tmsize_t)bytecount;
861 2 : tif->tif_rawdata =
862 2 : tif->tif_base + (tmsize_t)TIFFGetStrileOffset(tif, strip);
863 2 : tif->tif_rawdataoff = 0;
864 2 : tif->tif_rawdataloaded = (tmsize_t)bytecount;
865 :
866 : /*
867 : * When we have tif_rawdata reference directly into the memory
868 : * mapped file we need to be pretty careful about how we use the
869 : * rawdata. It is not a general purpose working buffer as it
870 : * normally otherwise is. So we keep track of this fact to avoid
871 : * using it improperly.
872 : */
873 2 : tif->tif_flags |= TIFF_BUFFERMMAP;
874 : }
875 : else
876 : {
877 : /*
878 : * Expand raw data buffer, if needed, to hold data
879 : * strip coming from file (perhaps should set upper
880 : * bound on the size of a buffer we'll use?).
881 : */
882 : tmsize_t bytecountm;
883 16508 : bytecountm = (tmsize_t)bytecount;
884 16508 : if ((uint64_t)bytecountm != bytecount)
885 : {
886 0 : TIFFErrorExtR(tif, module, "Integer overflow");
887 0 : return (0);
888 : }
889 16508 : if (bytecountm > tif->tif_rawdatasize)
890 : {
891 1025 : tif->tif_curstrip = NOSTRIP;
892 1025 : if ((tif->tif_flags & TIFF_MYBUFFER) == 0)
893 : {
894 0 : TIFFErrorExtR(
895 : tif, module,
896 : "Data buffer too small to hold strip %" PRIu32, strip);
897 0 : return (0);
898 : }
899 : }
900 16508 : if (tif->tif_flags & TIFF_BUFFERMMAP)
901 : {
902 0 : tif->tif_curstrip = NOSTRIP;
903 0 : tif->tif_rawdata = NULL;
904 0 : tif->tif_rawdatasize = 0;
905 0 : tif->tif_flags &= ~TIFF_BUFFERMMAP;
906 : }
907 :
908 16508 : if (isMapped(tif))
909 : {
910 0 : if (bytecountm > tif->tif_rawdatasize &&
911 0 : !TIFFReadBufferSetup(tif, 0, bytecountm))
912 : {
913 0 : return (0);
914 : }
915 0 : if (TIFFReadRawStrip1(tif, strip, tif->tif_rawdata, bytecountm,
916 : module) != bytecountm)
917 : {
918 0 : return (0);
919 : }
920 : }
921 : else
922 : {
923 16508 : if (TIFFReadRawStripOrTile2(tif, strip, 1, bytecountm,
924 : module) != bytecountm)
925 : {
926 4 : return (0);
927 : }
928 : }
929 :
930 16504 : tif->tif_rawdataoff = 0;
931 16504 : tif->tif_rawdataloaded = bytecountm;
932 :
933 16504 : if (!isFillOrder(tif, td->td_fillorder) &&
934 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
935 0 : TIFFReverseBits(tif->tif_rawdata, bytecountm);
936 : }
937 : }
938 16506 : return (TIFFStartStrip(tif, strip));
939 : }
940 :
941 : /*
942 : * Tile-oriented Read Support
943 : * Contributed by Nancy Cam (Silicon Graphics).
944 : */
945 :
946 : /*
947 : * Read and decompress a tile of data. The
948 : * tile is selected by the (x,y,z,s) coordinates.
949 : */
950 2 : tmsize_t TIFFReadTile(TIFF *tif, void *buf, uint32_t x, uint32_t y, uint32_t z,
951 : uint16_t s)
952 : {
953 2 : if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s))
954 0 : return ((tmsize_t)(-1));
955 2 : return (TIFFReadEncodedTile(tif, TIFFComputeTile(tif, x, y, z, s), buf,
956 : (tmsize_t)(-1)));
957 : }
958 :
959 : /*
960 : * Read a tile of data and decompress the specified
961 : * amount into the user-supplied buffer.
962 : */
963 30036 : tmsize_t TIFFReadEncodedTile(TIFF *tif, uint32_t tile, void *buf, tmsize_t size)
964 : {
965 : static const char module[] = "TIFFReadEncodedTile";
966 30036 : TIFFDirectory *td = &tif->tif_dir;
967 30036 : tmsize_t tilesize = tif->tif_tilesize;
968 :
969 30036 : if (!TIFFCheckRead(tif, 1))
970 0 : return ((tmsize_t)(-1));
971 30036 : if (tile >= td->td_nstrips)
972 : {
973 0 : TIFFErrorExtR(tif, module,
974 : "%" PRIu32 ": Tile out of range, max %" PRIu32, tile,
975 : td->td_nstrips);
976 0 : return ((tmsize_t)(-1));
977 : }
978 :
979 : /* shortcut to avoid an extra memcpy() */
980 30036 : if (td->td_compression == COMPRESSION_NONE && size != (tmsize_t)(-1) &&
981 23505 : size >= tilesize && !isMapped(tif) &&
982 23505 : ((tif->tif_flags & TIFF_NOREADRAW) == 0))
983 : {
984 23505 : if (TIFFReadRawTile1(tif, tile, buf, tilesize, module) != tilesize)
985 4 : return ((tmsize_t)(-1));
986 :
987 23501 : if (!isFillOrder(tif, td->td_fillorder) &&
988 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
989 0 : TIFFReverseBits((uint8_t *)buf, tilesize);
990 :
991 23501 : (*tif->tif_postdecode)(tif, (uint8_t *)buf, tilesize);
992 23501 : return (tilesize);
993 : }
994 :
995 6531 : if (size == (tmsize_t)(-1))
996 2 : size = tilesize;
997 6529 : else if (size > tilesize)
998 0 : size = tilesize;
999 6531 : if (!TIFFFillTile(tif, tile))
1000 : {
1001 : /* See TIFFReadEncodedStrip comment regarding TIFFTAG_FAXFILLFUNC. */
1002 26 : if (buf)
1003 26 : memset(buf, 0, (size_t)size);
1004 26 : return ((tmsize_t)(-1));
1005 : }
1006 6505 : else if ((*tif->tif_decodetile)(tif, (uint8_t *)buf, size,
1007 6505 : (uint16_t)(tile / td->td_stripsperimage)))
1008 : {
1009 6505 : (*tif->tif_postdecode)(tif, (uint8_t *)buf, size);
1010 6505 : return (size);
1011 : }
1012 : else
1013 0 : return ((tmsize_t)(-1));
1014 : }
1015 :
1016 : /* Variant of TIFFReadTile() that does
1017 : * * if *buf == NULL, *buf = _TIFFmallocExt(tif, bufsizetoalloc) only after
1018 : * TIFFFillTile() has succeeded. This avoid excessive memory allocation in case
1019 : * of truncated file.
1020 : * * calls regular TIFFReadEncodedTile() if *buf != NULL
1021 : */
1022 4 : tmsize_t _TIFFReadTileAndAllocBuffer(TIFF *tif, void **buf,
1023 : tmsize_t bufsizetoalloc, uint32_t x,
1024 : uint32_t y, uint32_t z, uint16_t s)
1025 : {
1026 4 : if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s))
1027 0 : return ((tmsize_t)(-1));
1028 4 : return (_TIFFReadEncodedTileAndAllocBuffer(
1029 : tif, TIFFComputeTile(tif, x, y, z, s), buf, bufsizetoalloc,
1030 : (tmsize_t)(-1)));
1031 : }
1032 :
1033 : /* Variant of TIFFReadEncodedTile() that does
1034 : * * if *buf == NULL, *buf = _TIFFmallocExt(tif, bufsizetoalloc) only after
1035 : * TIFFFillTile() has succeeded. This avoid excessive memory allocation in case
1036 : * of truncated file.
1037 : * * calls regular TIFFReadEncodedTile() if *buf != NULL
1038 : */
1039 4 : tmsize_t _TIFFReadEncodedTileAndAllocBuffer(TIFF *tif, uint32_t tile,
1040 : void **buf, tmsize_t bufsizetoalloc,
1041 : tmsize_t size_to_read)
1042 : {
1043 : static const char module[] = "_TIFFReadEncodedTileAndAllocBuffer";
1044 4 : TIFFDirectory *td = &tif->tif_dir;
1045 4 : tmsize_t tilesize = tif->tif_tilesize;
1046 :
1047 4 : if (*buf != NULL)
1048 : {
1049 0 : return TIFFReadEncodedTile(tif, tile, *buf, size_to_read);
1050 : }
1051 :
1052 4 : if (!TIFFCheckRead(tif, 1))
1053 0 : return ((tmsize_t)(-1));
1054 4 : if (tile >= td->td_nstrips)
1055 : {
1056 0 : TIFFErrorExtR(tif, module,
1057 : "%" PRIu32 ": Tile out of range, max %" PRIu32, tile,
1058 : td->td_nstrips);
1059 0 : return ((tmsize_t)(-1));
1060 : }
1061 :
1062 4 : if (!TIFFFillTile(tif, tile))
1063 1 : return ((tmsize_t)(-1));
1064 :
1065 : /* Sanity checks to avoid excessive memory allocation */
1066 : /* Cf https://gitlab.com/libtiff/libtiff/-/issues/479 */
1067 3 : if (td->td_compression == COMPRESSION_NONE)
1068 : {
1069 2 : if (tif->tif_rawdatasize != tilesize)
1070 : {
1071 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1072 : "Invalid tile byte count for tile %u. "
1073 : "Expected %" PRIu64 ", got %" PRIu64,
1074 : tile, (uint64_t)tilesize,
1075 0 : (uint64_t)tif->tif_rawdatasize);
1076 0 : return ((tmsize_t)(-1));
1077 : }
1078 : }
1079 : else
1080 : {
1081 : /* Max compression ratio experimentally determined. Might be fragile...
1082 : * Only apply this heuristics to situations where the memory allocation
1083 : * would be big, to avoid breaking nominal use cases.
1084 : */
1085 1 : const int maxCompressionRatio =
1086 1 : td->td_compression == COMPRESSION_ZSTD ? 33000
1087 2 : : td->td_compression == COMPRESSION_JXL
1088 : ?
1089 : /* Evaluated on a 8000x8000 tile */
1090 0 : 25000 * (td->td_planarconfig == PLANARCONFIG_CONTIG
1091 0 : ? td->td_samplesperpixel
1092 0 : : 1)
1093 1 : : td->td_compression == COMPRESSION_LZMA ? 7000 : 1000;
1094 1 : if (bufsizetoalloc > 100 * 1000 * 1000 &&
1095 0 : tif->tif_rawdatasize < tilesize / maxCompressionRatio)
1096 : {
1097 0 : TIFFErrorExtR(tif, TIFFFileName(tif),
1098 : "Likely invalid tile byte count for tile %u. "
1099 : "Uncompressed tile size is %" PRIu64 ", "
1100 : "compressed one is %" PRIu64,
1101 : tile, (uint64_t)tilesize,
1102 0 : (uint64_t)tif->tif_rawdatasize);
1103 0 : return ((tmsize_t)(-1));
1104 : }
1105 : }
1106 :
1107 3 : *buf = _TIFFmallocExt(tif, bufsizetoalloc);
1108 3 : if (*buf == NULL)
1109 : {
1110 0 : TIFFErrorExtR(tif, TIFFFileName(tif), "No space for tile buffer");
1111 0 : return ((tmsize_t)(-1));
1112 : }
1113 3 : _TIFFmemset(*buf, 0, bufsizetoalloc);
1114 :
1115 3 : if (size_to_read == (tmsize_t)(-1))
1116 3 : size_to_read = tilesize;
1117 0 : else if (size_to_read > tilesize)
1118 0 : size_to_read = tilesize;
1119 3 : if ((*tif->tif_decodetile)(tif, (uint8_t *)*buf, size_to_read,
1120 3 : (uint16_t)(tile / td->td_stripsperimage)))
1121 : {
1122 3 : (*tif->tif_postdecode)(tif, (uint8_t *)*buf, size_to_read);
1123 3 : return (size_to_read);
1124 : }
1125 : else
1126 0 : return ((tmsize_t)(-1));
1127 : }
1128 :
1129 23508 : static tmsize_t TIFFReadRawTile1(TIFF *tif, uint32_t tile, void *buf,
1130 : tmsize_t size, const char *module)
1131 : {
1132 23508 : assert((tif->tif_flags & TIFF_NOREADRAW) == 0);
1133 23508 : if (!isMapped(tif))
1134 : {
1135 : tmsize_t cc;
1136 :
1137 23508 : if (!SeekOK(tif, TIFFGetStrileOffset(tif, tile)))
1138 : {
1139 0 : TIFFErrorExtR(tif, module,
1140 : "Seek error at row %" PRIu32 ", col %" PRIu32
1141 : ", tile %" PRIu32,
1142 : tif->tif_row, tif->tif_col, tile);
1143 0 : return ((tmsize_t)(-1));
1144 : }
1145 23508 : cc = TIFFReadFile(tif, buf, size);
1146 23508 : if (cc != size)
1147 : {
1148 4 : TIFFErrorExtR(tif, module,
1149 : "Read error at row %" PRIu32 ", col %" PRIu32
1150 : "; got %" TIFF_SSIZE_FORMAT
1151 : " bytes, expected %" TIFF_SSIZE_FORMAT,
1152 : tif->tif_row, tif->tif_col, cc, size);
1153 4 : return ((tmsize_t)(-1));
1154 : }
1155 : }
1156 : else
1157 : {
1158 : tmsize_t ma, mb;
1159 : tmsize_t n;
1160 0 : ma = (tmsize_t)TIFFGetStrileOffset(tif, tile);
1161 0 : mb = ma + size;
1162 0 : if ((TIFFGetStrileOffset(tif, tile) > (uint64_t)TIFF_TMSIZE_T_MAX) ||
1163 0 : (ma > tif->tif_size))
1164 0 : n = 0;
1165 0 : else if ((mb < ma) || (mb < size) || (mb > tif->tif_size))
1166 0 : n = tif->tif_size - ma;
1167 : else
1168 0 : n = size;
1169 0 : if (n != size)
1170 : {
1171 0 : TIFFErrorExtR(tif, module,
1172 : "Read error at row %" PRIu32 ", col %" PRIu32
1173 : ", tile %" PRIu32 "; got %" TIFF_SSIZE_FORMAT
1174 : " bytes, expected %" TIFF_SSIZE_FORMAT,
1175 : tif->tif_row, tif->tif_col, tile, n, size);
1176 0 : return ((tmsize_t)(-1));
1177 : }
1178 0 : _TIFFmemcpy(buf, tif->tif_base + ma, size);
1179 : }
1180 23504 : return (size);
1181 : }
1182 :
1183 : /*
1184 : * Read a tile of data from the file.
1185 : */
1186 3 : tmsize_t TIFFReadRawTile(TIFF *tif, uint32_t tile, void *buf, tmsize_t size)
1187 : {
1188 : static const char module[] = "TIFFReadRawTile";
1189 3 : TIFFDirectory *td = &tif->tif_dir;
1190 : uint64_t bytecount64;
1191 : tmsize_t bytecountm;
1192 :
1193 3 : if (!TIFFCheckRead(tif, 1))
1194 0 : return ((tmsize_t)(-1));
1195 3 : if (tile >= td->td_nstrips)
1196 : {
1197 0 : TIFFErrorExtR(tif, module,
1198 : "%" PRIu32 ": Tile out of range, max %" PRIu32, tile,
1199 : td->td_nstrips);
1200 0 : return ((tmsize_t)(-1));
1201 : }
1202 3 : if (tif->tif_flags & TIFF_NOREADRAW)
1203 : {
1204 0 : TIFFErrorExtR(tif, module,
1205 : "Compression scheme does not support access to raw "
1206 : "uncompressed data");
1207 0 : return ((tmsize_t)(-1));
1208 : }
1209 3 : bytecount64 = TIFFGetStrileByteCount(tif, tile);
1210 3 : if (size != (tmsize_t)(-1) && (uint64_t)size <= bytecount64)
1211 3 : bytecountm = size;
1212 : else
1213 0 : bytecountm = _TIFFCastUInt64ToSSize(tif, bytecount64, module);
1214 3 : if (bytecountm == 0)
1215 : {
1216 0 : return ((tmsize_t)(-1));
1217 : }
1218 3 : return (TIFFReadRawTile1(tif, tile, buf, bytecountm, module));
1219 : }
1220 :
1221 : /*
1222 : * Read the specified tile and setup for decoding. The data buffer is
1223 : * expanded, as necessary, to hold the tile's data.
1224 : */
1225 6535 : int TIFFFillTile(TIFF *tif, uint32_t tile)
1226 : {
1227 : static const char module[] = "TIFFFillTile";
1228 6535 : TIFFDirectory *td = &tif->tif_dir;
1229 :
1230 6535 : if ((tif->tif_flags & TIFF_NOREADRAW) == 0)
1231 : {
1232 6533 : uint64_t bytecount = TIFFGetStrileByteCount(tif, tile);
1233 6533 : if (bytecount == 0 || bytecount > (uint64_t)TIFF_INT64_MAX)
1234 : {
1235 0 : TIFFErrorExtR(tif, module,
1236 : "%" PRIu64 ": Invalid tile byte count, tile %" PRIu32,
1237 : bytecount, tile);
1238 0 : return (0);
1239 : }
1240 :
1241 : /* To avoid excessive memory allocations: */
1242 : /* Byte count should normally not be larger than a number of */
1243 : /* times the uncompressed size plus some margin */
1244 6533 : if (bytecount > 1024 * 1024)
1245 : {
1246 : /* 10 and 4096 are just values that could be adjusted. */
1247 : /* Hopefully they are safe enough for all codecs */
1248 3 : tmsize_t stripsize = TIFFTileSize(tif);
1249 3 : if (stripsize != 0 && (bytecount - 4096) / 10 > (uint64_t)stripsize)
1250 : {
1251 1 : uint64_t newbytecount = (uint64_t)stripsize * 10 + 4096;
1252 1 : TIFFErrorExtR(tif, module,
1253 : "Too large tile byte count %" PRIu64
1254 : ", tile %" PRIu32 ". Limiting to %" PRIu64,
1255 : bytecount, tile, newbytecount);
1256 1 : bytecount = newbytecount;
1257 : }
1258 : }
1259 :
1260 6533 : if (isMapped(tif))
1261 : {
1262 : /*
1263 : * We must check for overflow, potentially causing
1264 : * an OOB read. Instead of simple
1265 : *
1266 : * TIFFGetStrileOffset(tif, tile)+bytecount > tif->tif_size
1267 : *
1268 : * comparison (which can overflow) we do the following
1269 : * two comparisons:
1270 : */
1271 4 : if (bytecount > (uint64_t)tif->tif_size ||
1272 4 : TIFFGetStrileOffset(tif, tile) >
1273 4 : (uint64_t)tif->tif_size - bytecount)
1274 : {
1275 2 : tif->tif_curtile = NOTILE;
1276 2 : return (0);
1277 : }
1278 : }
1279 :
1280 6531 : if (isMapped(tif) && (isFillOrder(tif, td->td_fillorder) ||
1281 0 : (tif->tif_flags & TIFF_NOBITREV)))
1282 : {
1283 : /*
1284 : * The image is mapped into memory and we either don't
1285 : * need to flip bits or the compression routine is
1286 : * going to handle this operation itself. In this
1287 : * case, avoid copying the raw data and instead just
1288 : * reference the data from the memory mapped file
1289 : * image. This assumes that the decompression
1290 : * routines do not modify the contents of the raw data
1291 : * buffer (if they try to, the application will get a
1292 : * fault since the file is mapped read-only).
1293 : */
1294 2 : if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
1295 : {
1296 0 : _TIFFfreeExt(tif, tif->tif_rawdata);
1297 0 : tif->tif_rawdata = NULL;
1298 0 : tif->tif_rawdatasize = 0;
1299 : }
1300 2 : tif->tif_flags &= ~TIFF_MYBUFFER;
1301 :
1302 2 : tif->tif_rawdatasize = (tmsize_t)bytecount;
1303 2 : tif->tif_rawdata =
1304 2 : tif->tif_base + (tmsize_t)TIFFGetStrileOffset(tif, tile);
1305 2 : tif->tif_rawdataoff = 0;
1306 2 : tif->tif_rawdataloaded = (tmsize_t)bytecount;
1307 2 : tif->tif_flags |= TIFF_BUFFERMMAP;
1308 : }
1309 : else
1310 : {
1311 : /*
1312 : * Expand raw data buffer, if needed, to hold data
1313 : * tile coming from file (perhaps should set upper
1314 : * bound on the size of a buffer we'll use?).
1315 : */
1316 : tmsize_t bytecountm;
1317 6529 : bytecountm = (tmsize_t)bytecount;
1318 6529 : if ((uint64_t)bytecountm != bytecount)
1319 : {
1320 0 : TIFFErrorExtR(tif, module, "Integer overflow");
1321 0 : return (0);
1322 : }
1323 6529 : if (bytecountm > tif->tif_rawdatasize)
1324 : {
1325 893 : tif->tif_curtile = NOTILE;
1326 893 : if ((tif->tif_flags & TIFF_MYBUFFER) == 0)
1327 : {
1328 0 : TIFFErrorExtR(tif, module,
1329 : "Data buffer too small to hold tile %" PRIu32,
1330 : tile);
1331 0 : return (0);
1332 : }
1333 : }
1334 6529 : if (tif->tif_flags & TIFF_BUFFERMMAP)
1335 : {
1336 0 : tif->tif_curtile = NOTILE;
1337 0 : tif->tif_rawdata = NULL;
1338 0 : tif->tif_rawdatasize = 0;
1339 0 : tif->tif_flags &= ~TIFF_BUFFERMMAP;
1340 : }
1341 :
1342 6529 : if (isMapped(tif))
1343 : {
1344 0 : if (bytecountm > tif->tif_rawdatasize &&
1345 0 : !TIFFReadBufferSetup(tif, 0, bytecountm))
1346 : {
1347 0 : return (0);
1348 : }
1349 0 : if (TIFFReadRawTile1(tif, tile, tif->tif_rawdata, bytecountm,
1350 : module) != bytecountm)
1351 : {
1352 0 : return (0);
1353 : }
1354 : }
1355 : else
1356 : {
1357 6529 : if (TIFFReadRawStripOrTile2(tif, tile, 0, bytecountm, module) !=
1358 : bytecountm)
1359 : {
1360 23 : return (0);
1361 : }
1362 : }
1363 :
1364 6506 : tif->tif_rawdataoff = 0;
1365 6506 : tif->tif_rawdataloaded = bytecountm;
1366 :
1367 6506 : if (tif->tif_rawdata != NULL &&
1368 6506 : !isFillOrder(tif, td->td_fillorder) &&
1369 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
1370 0 : TIFFReverseBits(tif->tif_rawdata, tif->tif_rawdataloaded);
1371 : }
1372 : }
1373 6510 : return (TIFFStartTile(tif, tile));
1374 : }
1375 :
1376 : /*
1377 : * Setup the raw data buffer in preparation for
1378 : * reading a strip of raw data. If the buffer
1379 : * is specified as zero, then a buffer of appropriate
1380 : * size is allocated by the library. Otherwise,
1381 : * the client must guarantee that the buffer is
1382 : * large enough to hold any individual strip of
1383 : * raw data.
1384 : */
1385 0 : int TIFFReadBufferSetup(TIFF *tif, void *bp, tmsize_t size)
1386 : {
1387 : static const char module[] = "TIFFReadBufferSetup";
1388 :
1389 0 : assert((tif->tif_flags & TIFF_NOREADRAW) == 0);
1390 0 : tif->tif_flags &= ~TIFF_BUFFERMMAP;
1391 :
1392 0 : if (tif->tif_rawdata)
1393 : {
1394 0 : if (tif->tif_flags & TIFF_MYBUFFER)
1395 0 : _TIFFfreeExt(tif, tif->tif_rawdata);
1396 0 : tif->tif_rawdata = NULL;
1397 0 : tif->tif_rawdatasize = 0;
1398 : }
1399 0 : if (bp)
1400 : {
1401 0 : tif->tif_rawdatasize = size;
1402 0 : tif->tif_rawdata = (uint8_t *)bp;
1403 0 : tif->tif_flags &= ~TIFF_MYBUFFER;
1404 : }
1405 : else
1406 : {
1407 0 : tif->tif_rawdatasize = (tmsize_t)TIFFroundup_64((uint64_t)size, 1024);
1408 0 : if (tif->tif_rawdatasize == 0)
1409 : {
1410 0 : TIFFErrorExtR(tif, module, "Invalid buffer size");
1411 0 : return (0);
1412 : }
1413 : /* Initialize to zero to avoid uninitialized buffers in case of */
1414 : /* short reads (http://bugzilla.maptools.org/show_bug.cgi?id=2651) */
1415 0 : tif->tif_rawdata =
1416 0 : (uint8_t *)_TIFFcallocExt(tif, 1, tif->tif_rawdatasize);
1417 0 : tif->tif_flags |= TIFF_MYBUFFER;
1418 : }
1419 0 : if (tif->tif_rawdata == NULL)
1420 : {
1421 0 : TIFFErrorExtR(tif, module,
1422 : "No space for data buffer at scanline %" PRIu32,
1423 : tif->tif_row);
1424 0 : tif->tif_rawdatasize = 0;
1425 0 : return (0);
1426 : }
1427 0 : return (1);
1428 : }
1429 :
1430 : /*
1431 : * Set state to appear as if a
1432 : * strip has just been read in.
1433 : */
1434 18928 : static int TIFFStartStrip(TIFF *tif, uint32_t strip)
1435 : {
1436 18928 : TIFFDirectory *td = &tif->tif_dir;
1437 :
1438 18928 : if ((tif->tif_flags & TIFF_CODERSETUP) == 0)
1439 : {
1440 3316 : if (!(*tif->tif_setupdecode)(tif))
1441 1 : return (0);
1442 3318 : tif->tif_flags |= TIFF_CODERSETUP;
1443 : }
1444 18930 : tif->tif_curstrip = strip;
1445 18930 : tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
1446 18930 : tif->tif_flags &= ~TIFF_BUF4WRITE;
1447 :
1448 18930 : if (tif->tif_flags & TIFF_NOREADRAW)
1449 : {
1450 0 : tif->tif_rawcp = NULL;
1451 0 : tif->tif_rawcc = 0;
1452 : }
1453 : else
1454 : {
1455 18930 : tif->tif_rawcp = tif->tif_rawdata;
1456 18930 : if (tif->tif_rawdataloaded > 0)
1457 18928 : tif->tif_rawcc = tif->tif_rawdataloaded;
1458 : else
1459 2 : tif->tif_rawcc = (tmsize_t)TIFFGetStrileByteCount(tif, strip);
1460 : }
1461 18928 : if ((*tif->tif_predecode)(tif, (uint16_t)(strip / td->td_stripsperimage)) ==
1462 : 0)
1463 : {
1464 : /* Needed for example for scanline access, if tif_predecode */
1465 : /* fails, and we try to read the same strip again. Without invalidating
1466 : */
1467 : /* tif_curstrip, we'd call tif_decoderow() on a possibly invalid */
1468 : /* codec state. */
1469 2 : tif->tif_curstrip = NOSTRIP;
1470 2 : return 0;
1471 : }
1472 18926 : return 1;
1473 : }
1474 :
1475 : /*
1476 : * Set state to appear as if a
1477 : * tile has just been read in.
1478 : */
1479 6750 : static int TIFFStartTile(TIFF *tif, uint32_t tile)
1480 : {
1481 : static const char module[] = "TIFFStartTile";
1482 6750 : TIFFDirectory *td = &tif->tif_dir;
1483 : uint32_t howmany32;
1484 :
1485 6750 : if ((tif->tif_flags & TIFF_CODERSETUP) == 0)
1486 : {
1487 922 : if (!(*tif->tif_setupdecode)(tif))
1488 0 : return (0);
1489 922 : tif->tif_flags |= TIFF_CODERSETUP;
1490 : }
1491 6750 : tif->tif_curtile = tile;
1492 6750 : if (td->td_tilewidth == 0)
1493 : {
1494 0 : TIFFErrorExtR(tif, module, "Zero tilewidth");
1495 0 : return 0;
1496 : }
1497 6750 : howmany32 = TIFFhowmany_32(td->td_imagewidth, td->td_tilewidth);
1498 6750 : if (howmany32 == 0)
1499 : {
1500 0 : TIFFErrorExtR(tif, module, "Zero tiles");
1501 0 : return 0;
1502 : }
1503 6750 : tif->tif_row = (tile % howmany32) * td->td_tilelength;
1504 6750 : howmany32 = TIFFhowmany_32(td->td_imagelength, td->td_tilelength);
1505 6750 : if (howmany32 == 0)
1506 : {
1507 0 : TIFFErrorExtR(tif, module, "Zero tiles");
1508 0 : return 0;
1509 : }
1510 6750 : tif->tif_col = (tile % howmany32) * td->td_tilewidth;
1511 6750 : tif->tif_flags &= ~TIFF_BUF4WRITE;
1512 6750 : if (tif->tif_flags & TIFF_NOREADRAW)
1513 : {
1514 2 : tif->tif_rawcp = NULL;
1515 2 : tif->tif_rawcc = 0;
1516 : }
1517 : else
1518 : {
1519 6748 : tif->tif_rawcp = tif->tif_rawdata;
1520 6748 : if (tif->tif_rawdataloaded > 0)
1521 6748 : tif->tif_rawcc = tif->tif_rawdataloaded;
1522 : else
1523 0 : tif->tif_rawcc = (tmsize_t)TIFFGetStrileByteCount(tif, tile);
1524 : }
1525 : return (
1526 6750 : (*tif->tif_predecode)(tif, (uint16_t)(tile / td->td_stripsperimage)));
1527 : }
1528 :
1529 2283640 : static int TIFFCheckRead(TIFF *tif, int tiles)
1530 : {
1531 2283640 : if (tif->tif_mode == O_WRONLY)
1532 : {
1533 0 : TIFFErrorExtR(tif, tif->tif_name, "File not open for reading");
1534 0 : return (0);
1535 : }
1536 2283640 : if (tiles ^ isTiled(tif))
1537 : {
1538 0 : TIFFErrorExtR(tif, tif->tif_name,
1539 : tiles ? "Can not read tiles from a striped image"
1540 : : "Can not read scanlines from a tiled image");
1541 0 : return (0);
1542 : }
1543 2283640 : return (1);
1544 : }
1545 :
1546 : /* Use the provided input buffer (inbuf, insize) and decompress it into
1547 : * (outbuf, outsize).
1548 : * This function replaces the use of
1549 : * TIFFReadEncodedStrip()/TIFFReadEncodedTile() when the user can provide the
1550 : * buffer for the input data, for example when he wants to avoid libtiff to read
1551 : * the strile offset/count values from the [Strip|Tile][Offsets/ByteCounts]
1552 : * array. inbuf content must be writable (if bit reversal is needed) Returns 1
1553 : * in case of success, 0 otherwise.
1554 : */
1555 2603 : int TIFFReadFromUserBuffer(TIFF *tif, uint32_t strile, void *inbuf,
1556 : tmsize_t insize, void *outbuf, tmsize_t outsize)
1557 : {
1558 : static const char module[] = "TIFFReadFromUserBuffer";
1559 2603 : TIFFDirectory *td = &tif->tif_dir;
1560 2603 : int ret = 1;
1561 2603 : uint32_t old_tif_flags = tif->tif_flags;
1562 2603 : tmsize_t old_rawdatasize = tif->tif_rawdatasize;
1563 2603 : void *old_rawdata = tif->tif_rawdata;
1564 :
1565 2603 : if (tif->tif_mode == O_WRONLY)
1566 : {
1567 0 : TIFFErrorExtR(tif, tif->tif_name, "File not open for reading");
1568 0 : return 0;
1569 : }
1570 2603 : if (tif->tif_flags & TIFF_NOREADRAW)
1571 : {
1572 0 : TIFFErrorExtR(tif, module,
1573 : "Compression scheme does not support access to raw "
1574 : "uncompressed data");
1575 0 : return 0;
1576 : }
1577 :
1578 2603 : tif->tif_flags &= ~TIFF_MYBUFFER;
1579 2603 : tif->tif_flags |= TIFF_BUFFERMMAP;
1580 2603 : tif->tif_rawdatasize = insize;
1581 2603 : tif->tif_rawdata = (uint8_t *)inbuf;
1582 2603 : tif->tif_rawdataoff = 0;
1583 2603 : tif->tif_rawdataloaded = insize;
1584 :
1585 2603 : if (!isFillOrder(tif, td->td_fillorder) &&
1586 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
1587 : {
1588 0 : TIFFReverseBits((uint8_t *)inbuf, insize);
1589 : }
1590 :
1591 2603 : if (TIFFIsTiled(tif))
1592 : {
1593 238 : if (!TIFFStartTile(tif, strile))
1594 : {
1595 0 : ret = 0;
1596 : /* See related TIFFReadEncodedStrip comment. */
1597 0 : if (outbuf)
1598 0 : memset(outbuf, 0, (size_t)outsize);
1599 : }
1600 240 : else if (!(*tif->tif_decodetile)(
1601 : tif, (uint8_t *)outbuf, outsize,
1602 240 : (uint16_t)(strile / td->td_stripsperimage)))
1603 : {
1604 0 : ret = 0;
1605 : }
1606 : }
1607 : else
1608 : {
1609 2362 : uint32_t rowsperstrip = td->td_rowsperstrip;
1610 : uint32_t stripsperplane;
1611 2362 : if (rowsperstrip > td->td_imagelength)
1612 0 : rowsperstrip = td->td_imagelength;
1613 2362 : if (rowsperstrip == 0)
1614 : {
1615 0 : TIFFErrorExtR(tif, module, "rowsperstrip is zero");
1616 0 : ret = 0;
1617 : }
1618 : else
1619 : {
1620 2362 : stripsperplane =
1621 2362 : TIFFhowmany_32_maxuint_compat(td->td_imagelength, rowsperstrip);
1622 2362 : if (!TIFFStartStrip(tif, strile))
1623 : {
1624 0 : ret = 0;
1625 : /* See related TIFFReadEncodedStrip comment. */
1626 0 : if (outbuf)
1627 0 : memset(outbuf, 0, (size_t)outsize);
1628 : }
1629 2366 : else if (!(*tif->tif_decodestrip)(
1630 : tif, (uint8_t *)outbuf, outsize,
1631 2365 : (uint16_t)(strile / stripsperplane)))
1632 : {
1633 0 : ret = 0;
1634 : }
1635 : }
1636 : }
1637 2606 : if (ret)
1638 : {
1639 2606 : (*tif->tif_postdecode)(tif, (uint8_t *)outbuf, outsize);
1640 : }
1641 :
1642 2606 : if (!isFillOrder(tif, td->td_fillorder) &&
1643 0 : (tif->tif_flags & TIFF_NOBITREV) == 0)
1644 : {
1645 0 : TIFFReverseBits((uint8_t *)inbuf, insize);
1646 : }
1647 :
1648 2606 : tif->tif_flags = (old_tif_flags & (TIFF_MYBUFFER | TIFF_BUFFERMMAP)) |
1649 2606 : (tif->tif_flags & ~(TIFF_MYBUFFER | TIFF_BUFFERMMAP));
1650 2606 : tif->tif_rawdatasize = old_rawdatasize;
1651 2606 : tif->tif_rawdata = (uint8_t *)old_rawdata;
1652 2606 : tif->tif_rawdataoff = 0;
1653 2606 : tif->tif_rawdataloaded = 0;
1654 :
1655 2606 : return ret;
1656 : }
1657 :
1658 2536980 : void _TIFFNoPostDecode(TIFF *tif, uint8_t *buf, tmsize_t cc)
1659 : {
1660 : (void)tif;
1661 : (void)buf;
1662 : (void)cc;
1663 2536980 : }
1664 :
1665 5073 : void _TIFFSwab16BitData(TIFF *tif, uint8_t *buf, tmsize_t cc)
1666 : {
1667 : (void)tif;
1668 5073 : assert((cc & 1) == 0);
1669 5073 : TIFFSwabArrayOfShort((uint16_t *)buf, cc / 2);
1670 5073 : }
1671 :
1672 0 : void _TIFFSwab24BitData(TIFF *tif, uint8_t *buf, tmsize_t cc)
1673 : {
1674 : (void)tif;
1675 0 : assert((cc % 3) == 0);
1676 0 : TIFFSwabArrayOfTriples((uint8_t *)buf, cc / 3);
1677 0 : }
1678 :
1679 188 : void _TIFFSwab32BitData(TIFF *tif, uint8_t *buf, tmsize_t cc)
1680 : {
1681 : (void)tif;
1682 188 : assert((cc & 3) == 0);
1683 188 : TIFFSwabArrayOfLong((uint32_t *)buf, cc / 4);
1684 188 : }
1685 :
1686 4 : void _TIFFSwab64BitData(TIFF *tif, uint8_t *buf, tmsize_t cc)
1687 : {
1688 : (void)tif;
1689 4 : assert((cc & 7) == 0);
1690 4 : TIFFSwabArrayOfDouble((double *)buf, cc / 8);
1691 4 : }
|