]> git.saurik.com Git - wxWidgets.git/blame - src/tiff/tif_read.c
correct access for virtual
[wxWidgets.git] / src / tiff / tif_read.c
CommitLineData
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 * Scanline-oriented Read Support
30 */
31#include "tiffiop.h"
32#include <stdio.h>
33#include <assert.h>
34
00cb87b4
VZ
35 int TIFFFillStrip(TIFF*, tstrip_t);
36 int TIFFFillTile(TIFF*, ttile_t);
b47c832e
RR
37static int TIFFStartStrip(TIFF*, tstrip_t);
38static int TIFFStartTile(TIFF*, ttile_t);
39static int TIFFCheckRead(TIFF*, int);
40
41#define NOSTRIP ((tstrip_t) -1) /* undefined state */
42#define NOTILE ((ttile_t) -1) /* undefined state */
43
44/*
45 * Seek to a random row+sample in a file.
46 */
47static int
48TIFFSeek(TIFF* tif, uint32 row, tsample_t sample)
49{
50 register TIFFDirectory *td = &tif->tif_dir;
51 tstrip_t strip;
52
53 if (row >= td->td_imagelength) { /* out of range */
54 TIFFError(tif->tif_name, "%lu: Row out of range, max %lu",
55 (u_long) row, (u_long) td->td_imagelength);
56 return (0);
57 }
58 if (td->td_planarconfig == PLANARCONFIG_SEPARATE) {
59 if (sample >= td->td_samplesperpixel) {
60 TIFFError(tif->tif_name,
61 "%lu: Sample out of range, max %lu",
62 (u_long) sample, (u_long) td->td_samplesperpixel);
63 return (0);
64 }
65 strip = sample*td->td_stripsperimage + row/td->td_rowsperstrip;
66 } else
67 strip = row / td->td_rowsperstrip;
68 if (strip != tif->tif_curstrip) { /* different strip, refill */
69 if (!TIFFFillStrip(tif, strip))
70 return (0);
71 } else if (row < tif->tif_row) {
72 /*
73 * Moving backwards within the same strip: backup
74 * to the start and then decode forward (below).
75 *
76 * NB: If you're planning on lots of random access within a
77 * strip, it's better to just read and decode the entire
78 * strip, and then access the decoded data in a random fashion.
79 */
80 if (!TIFFStartStrip(tif, strip))
81 return (0);
82 }
83 if (row != tif->tif_row) {
84 /*
85 * Seek forward to the desired row.
86 */
87 if (!(*tif->tif_seek)(tif, row - tif->tif_row))
88 return (0);
89 tif->tif_row = row;
90 }
91 return (1);
92}
93
94int
95TIFFReadScanline(TIFF* tif, tdata_t buf, uint32 row, tsample_t sample)
96{
97 int e;
98
99 if (!TIFFCheckRead(tif, 0))
100 return (-1);
101 if( (e = TIFFSeek(tif, row, sample)) != 0) {
102 /*
103 * Decompress desired row into user buffer.
104 */
105 e = (*tif->tif_decoderow)
106 (tif, (tidata_t) buf, tif->tif_scanlinesize, sample);
00cb87b4
VZ
107
108 /* we are now poised at the beginning of the next row */
109 tif->tif_row = row + 1;
110
b47c832e
RR
111 if (e)
112 (*tif->tif_postdecode)(tif, (tidata_t) buf,
113 tif->tif_scanlinesize);
114 }
115 return (e > 0 ? 1 : -1);
116}
117
118/*
119 * Read a strip of data and decompress the specified
120 * amount into the user-supplied buffer.
121 */
122tsize_t
123TIFFReadEncodedStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size)
124{
125 TIFFDirectory *td = &tif->tif_dir;
126 uint32 nrows;
127 tsize_t stripsize;
00cb87b4 128 tstrip_t sep_strip, strips_per_sep;
b47c832e
RR
129
130 if (!TIFFCheckRead(tif, 0))
131 return (-1);
132 if (strip >= td->td_nstrips) {
133 TIFFError(tif->tif_name, "%ld: Strip out of range, max %ld",
134 (long) strip, (long) td->td_nstrips);
135 return (-1);
136 }
137 /*
138 * Calculate the strip size according to the number of
00cb87b4
VZ
139 * rows in the strip (check for truncated last strip on any
140 * of the separations).
b47c832e 141 */
00cb87b4
VZ
142 if( td->td_rowsperstrip >= td->td_imagelength )
143 strips_per_sep = 1;
144 else
145 strips_per_sep = (td->td_imagelength+td->td_rowsperstrip-1)
146 / td->td_rowsperstrip;
147
148 sep_strip = strip % strips_per_sep;
149
150 if (sep_strip != strips_per_sep-1 ||
b47c832e
RR
151 (nrows = td->td_imagelength % td->td_rowsperstrip) == 0)
152 nrows = td->td_rowsperstrip;
00cb87b4 153
b47c832e
RR
154 stripsize = TIFFVStripSize(tif, nrows);
155 if (size == (tsize_t) -1)
156 size = stripsize;
157 else if (size > stripsize)
158 size = stripsize;
00cb87b4
VZ
159 if (TIFFFillStrip(tif, strip)
160 && (*tif->tif_decodestrip)(tif, (tidata_t) buf, size,
161 (tsample_t)(strip / td->td_stripsperimage)) > 0 ) {
b47c832e
RR
162 (*tif->tif_postdecode)(tif, (tidata_t) buf, size);
163 return (size);
164 } else
165 return ((tsize_t) -1);
166}
167
168static tsize_t
169TIFFReadRawStrip1(TIFF* tif,
170 tstrip_t strip, tdata_t buf, tsize_t size, const char* module)
171{
172 TIFFDirectory *td = &tif->tif_dir;
173
174 if (!isMapped(tif)) {
175 tsize_t cc;
176
177 if (!SeekOK(tif, td->td_stripoffset[strip])) {
178 TIFFError(module,
179 "%s: Seek error at scanline %lu, strip %lu",
180 tif->tif_name,
181 (u_long) tif->tif_row, (u_long) strip);
182 return (-1);
183 }
184 cc = TIFFReadFile(tif, buf, size);
185 if (cc != size) {
186 TIFFError(module,
187 "%s: Read error at scanline %lu; got %lu bytes, expected %lu",
188 tif->tif_name,
189 (u_long) tif->tif_row,
190 (u_long) cc,
191 (u_long) size);
192 return (-1);
193 }
194 } else {
195 if (td->td_stripoffset[strip] + size > tif->tif_size) {
196 TIFFError(module,
197 "%s: Read error at scanline %lu, strip %lu; got %lu bytes, expected %lu",
198 tif->tif_name,
199 (u_long) tif->tif_row,
200 (u_long) strip,
201 (u_long) tif->tif_size - td->td_stripoffset[strip],
202 (u_long) size);
203 return (-1);
204 }
205 _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[strip], size);
206 }
207 return (size);
208}
209
210/*
211 * Read a strip of data from the file.
212 */
213tsize_t
214TIFFReadRawStrip(TIFF* tif, tstrip_t strip, tdata_t buf, tsize_t size)
215{
216 static const char module[] = "TIFFReadRawStrip";
217 TIFFDirectory *td = &tif->tif_dir;
218 tsize_t bytecount;
219
220 if (!TIFFCheckRead(tif, 0))
221 return ((tsize_t) -1);
222 if (strip >= td->td_nstrips) {
223 TIFFError(tif->tif_name, "%lu: Strip out of range, max %lu",
224 (u_long) strip, (u_long) td->td_nstrips);
225 return ((tsize_t) -1);
226 }
227 bytecount = td->td_stripbytecount[strip];
228 if (bytecount <= 0) {
229 TIFFError(tif->tif_name,
230 "%lu: Invalid strip byte count, strip %lu",
231 (u_long) bytecount, (u_long) strip);
232 return ((tsize_t) -1);
233 }
234 if (size != (tsize_t)-1 && size < bytecount)
235 bytecount = size;
236 return (TIFFReadRawStrip1(tif, strip, buf, bytecount, module));
237}
238
239/*
240 * Read the specified strip and setup for decoding.
241 * The data buffer is expanded, as necessary, to
242 * hold the strip's data.
243 */
00cb87b4 244int
b47c832e
RR
245TIFFFillStrip(TIFF* tif, tstrip_t strip)
246{
247 static const char module[] = "TIFFFillStrip";
248 TIFFDirectory *td = &tif->tif_dir;
249 tsize_t bytecount;
250
251 bytecount = td->td_stripbytecount[strip];
252 if (bytecount <= 0) {
253 TIFFError(tif->tif_name,
254 "%lu: Invalid strip byte count, strip %lu",
255 (u_long) bytecount, (u_long) strip);
256 return (0);
257 }
258 if (isMapped(tif) &&
259 (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) {
260 /*
261 * The image is mapped into memory and we either don't
262 * need to flip bits or the compression routine is going
263 * to handle this operation itself. In this case, avoid
264 * copying the raw data and instead just reference the
265 * data from the memory mapped file image. This assumes
266 * that the decompression routines do not modify the
267 * contents of the raw data buffer (if they try to,
268 * the application will get a fault since the file is
269 * mapped read-only).
270 */
271 if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
272 _TIFFfree(tif->tif_rawdata);
273 tif->tif_flags &= ~TIFF_MYBUFFER;
00cb87b4 274 if ( td->td_stripoffset[strip] + bytecount > tif->tif_size) {
b47c832e
RR
275 /*
276 * This error message might seem strange, but it's
277 * what would happen if a read were done instead.
278 */
279 TIFFError(module,
280 "%s: Read error on strip %lu; got %lu bytes, expected %lu",
281 tif->tif_name,
282 (u_long) strip,
283 (u_long) tif->tif_size - td->td_stripoffset[strip],
284 (u_long) bytecount);
285 tif->tif_curstrip = NOSTRIP;
286 return (0);
287 }
288 tif->tif_rawdatasize = bytecount;
289 tif->tif_rawdata = tif->tif_base + td->td_stripoffset[strip];
290 } else {
291 /*
292 * Expand raw data buffer, if needed, to
293 * hold data strip coming from file
294 * (perhaps should set upper bound on
295 * the size of a buffer we'll use?).
296 */
297 if (bytecount > tif->tif_rawdatasize) {
298 tif->tif_curstrip = NOSTRIP;
299 if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
300 TIFFError(module,
301 "%s: Data buffer too small to hold strip %lu",
302 tif->tif_name, (u_long) strip);
303 return (0);
304 }
305 if (!TIFFReadBufferSetup(tif, 0,
306 TIFFroundup(bytecount, 1024)))
307 return (0);
308 }
309 if (TIFFReadRawStrip1(tif, strip, (u_char *)tif->tif_rawdata,
310 bytecount, module) != bytecount)
311 return (0);
312 if (!isFillOrder(tif, td->td_fillorder) &&
313 (tif->tif_flags & TIFF_NOBITREV) == 0)
314 TIFFReverseBits(tif->tif_rawdata, bytecount);
315 }
316 return (TIFFStartStrip(tif, strip));
317}
318
319/*
320 * Tile-oriented Read Support
321 * Contributed by Nancy Cam (Silicon Graphics).
322 */
323
324/*
325 * Read and decompress a tile of data. The
326 * tile is selected by the (x,y,z,s) coordinates.
327 */
328tsize_t
329TIFFReadTile(TIFF* tif,
330 tdata_t buf, uint32 x, uint32 y, uint32 z, tsample_t s)
331{
332 if (!TIFFCheckRead(tif, 1) || !TIFFCheckTile(tif, x, y, z, s))
333 return (-1);
334 return (TIFFReadEncodedTile(tif,
335 TIFFComputeTile(tif, x, y, z, s), buf, (tsize_t) -1));
336}
337
338/*
339 * Read a tile of data and decompress the specified
340 * amount into the user-supplied buffer.
341 */
342tsize_t
343TIFFReadEncodedTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size)
344{
345 TIFFDirectory *td = &tif->tif_dir;
346 tsize_t tilesize = tif->tif_tilesize;
347
348 if (!TIFFCheckRead(tif, 1))
349 return (-1);
350 if (tile >= td->td_nstrips) {
351 TIFFError(tif->tif_name, "%ld: Tile out of range, max %ld",
352 (long) tile, (u_long) td->td_nstrips);
353 return (-1);
354 }
355 if (size == (tsize_t) -1)
356 size = tilesize;
357 else if (size > tilesize)
358 size = tilesize;
359 if (TIFFFillTile(tif, tile) && (*tif->tif_decodetile)(tif,
360 (tidata_t) buf, size, (tsample_t)(tile/td->td_stripsperimage))) {
361 (*tif->tif_postdecode)(tif, (tidata_t) buf, size);
362 return (size);
363 } else
364 return (-1);
365}
366
367static tsize_t
368TIFFReadRawTile1(TIFF* tif,
369 ttile_t tile, tdata_t buf, tsize_t size, const char* module)
370{
371 TIFFDirectory *td = &tif->tif_dir;
372
373 if (!isMapped(tif)) {
374 tsize_t cc;
375
376 if (!SeekOK(tif, td->td_stripoffset[tile])) {
377 TIFFError(module,
378 "%s: Seek error at row %ld, col %ld, tile %ld",
379 tif->tif_name,
380 (long) tif->tif_row,
381 (long) tif->tif_col,
382 (long) tile);
383 return ((tsize_t) -1);
384 }
385 cc = TIFFReadFile(tif, buf, size);
386 if (cc != size) {
387 TIFFError(module,
388 "%s: Read error at row %ld, col %ld; got %lu bytes, expected %lu",
389 tif->tif_name,
390 (long) tif->tif_row,
391 (long) tif->tif_col,
392 (u_long) cc,
393 (u_long) size);
394 return ((tsize_t) -1);
395 }
396 } else {
397 if (td->td_stripoffset[tile] + size > tif->tif_size) {
398 TIFFError(module,
399 "%s: Read error at row %ld, col %ld, tile %ld; got %lu bytes, expected %lu",
400 tif->tif_name,
401 (long) tif->tif_row,
402 (long) tif->tif_col,
403 (long) tile,
404 (u_long) tif->tif_size - td->td_stripoffset[tile],
405 (u_long) size);
406 return ((tsize_t) -1);
407 }
408 _TIFFmemcpy(buf, tif->tif_base + td->td_stripoffset[tile], size);
409 }
410 return (size);
411}
412
413/*
414 * Read a tile of data from the file.
415 */
416tsize_t
417TIFFReadRawTile(TIFF* tif, ttile_t tile, tdata_t buf, tsize_t size)
418{
419 static const char module[] = "TIFFReadRawTile";
420 TIFFDirectory *td = &tif->tif_dir;
421 tsize_t bytecount;
422
423 if (!TIFFCheckRead(tif, 1))
424 return ((tsize_t) -1);
425 if (tile >= td->td_nstrips) {
426 TIFFError(tif->tif_name, "%lu: Tile out of range, max %lu",
427 (u_long) tile, (u_long) td->td_nstrips);
428 return ((tsize_t) -1);
429 }
430 bytecount = td->td_stripbytecount[tile];
431 if (size != (tsize_t) -1 && size < bytecount)
432 bytecount = size;
433 return (TIFFReadRawTile1(tif, tile, buf, bytecount, module));
434}
435
436/*
437 * Read the specified tile and setup for decoding.
438 * The data buffer is expanded, as necessary, to
439 * hold the tile's data.
440 */
00cb87b4 441int
b47c832e
RR
442TIFFFillTile(TIFF* tif, ttile_t tile)
443{
444 static const char module[] = "TIFFFillTile";
445 TIFFDirectory *td = &tif->tif_dir;
446 tsize_t bytecount;
447
448 bytecount = td->td_stripbytecount[tile];
449 if (bytecount <= 0) {
450 TIFFError(tif->tif_name,
451 "%lu: Invalid tile byte count, tile %lu",
452 (u_long) bytecount, (u_long) tile);
453 return (0);
454 }
455 if (isMapped(tif) &&
456 (isFillOrder(tif, td->td_fillorder) || (tif->tif_flags & TIFF_NOBITREV))) {
457 /*
458 * The image is mapped into memory and we either don't
459 * need to flip bits or the compression routine is going
460 * to handle this operation itself. In this case, avoid
461 * copying the raw data and instead just reference the
462 * data from the memory mapped file image. This assumes
463 * that the decompression routines do not modify the
464 * contents of the raw data buffer (if they try to,
465 * the application will get a fault since the file is
466 * mapped read-only).
467 */
468 if ((tif->tif_flags & TIFF_MYBUFFER) && tif->tif_rawdata)
469 _TIFFfree(tif->tif_rawdata);
470 tif->tif_flags &= ~TIFF_MYBUFFER;
00cb87b4 471 if ( td->td_stripoffset[tile] + bytecount > tif->tif_size) {
b47c832e
RR
472 tif->tif_curtile = NOTILE;
473 return (0);
474 }
475 tif->tif_rawdatasize = bytecount;
476 tif->tif_rawdata = tif->tif_base + td->td_stripoffset[tile];
477 } else {
478 /*
479 * Expand raw data buffer, if needed, to
480 * hold data tile coming from file
481 * (perhaps should set upper bound on
482 * the size of a buffer we'll use?).
483 */
484 if (bytecount > tif->tif_rawdatasize) {
485 tif->tif_curtile = NOTILE;
486 if ((tif->tif_flags & TIFF_MYBUFFER) == 0) {
487 TIFFError(module,
488 "%s: Data buffer too small to hold tile %ld",
489 tif->tif_name, (long) tile);
490 return (0);
491 }
492 if (!TIFFReadBufferSetup(tif, 0,
493 TIFFroundup(bytecount, 1024)))
494 return (0);
495 }
496 if (TIFFReadRawTile1(tif, tile, (u_char *)tif->tif_rawdata,
497 bytecount, module) != bytecount)
498 return (0);
499 if (!isFillOrder(tif, td->td_fillorder) &&
500 (tif->tif_flags & TIFF_NOBITREV) == 0)
501 TIFFReverseBits(tif->tif_rawdata, bytecount);
502 }
503 return (TIFFStartTile(tif, tile));
504}
505
506/*
507 * Setup the raw data buffer in preparation for
508 * reading a strip of raw data. If the buffer
509 * is specified as zero, then a buffer of appropriate
510 * size is allocated by the library. Otherwise,
511 * the client must guarantee that the buffer is
512 * large enough to hold any individual strip of
513 * raw data.
514 */
515int
516TIFFReadBufferSetup(TIFF* tif, tdata_t bp, tsize_t size)
517{
518 static const char module[] = "TIFFReadBufferSetup";
519
520 if (tif->tif_rawdata) {
521 if (tif->tif_flags & TIFF_MYBUFFER)
522 _TIFFfree(tif->tif_rawdata);
523 tif->tif_rawdata = NULL;
524 }
525 if (bp) {
526 tif->tif_rawdatasize = size;
527 tif->tif_rawdata = (tidata_t) bp;
528 tif->tif_flags &= ~TIFF_MYBUFFER;
529 } else {
530 tif->tif_rawdatasize = TIFFroundup(size, 1024);
531 tif->tif_rawdata = (tidata_t) _TIFFmalloc(tif->tif_rawdatasize);
532 tif->tif_flags |= TIFF_MYBUFFER;
533 }
534 if (tif->tif_rawdata == NULL) {
535 TIFFError(module,
536 "%s: No space for data buffer at scanline %ld",
537 tif->tif_name, (long) tif->tif_row);
538 tif->tif_rawdatasize = 0;
539 return (0);
540 }
541 return (1);
542}
543
544/*
545 * Set state to appear as if a
546 * strip has just been read in.
547 */
548static int
549TIFFStartStrip(TIFF* tif, tstrip_t strip)
550{
551 TIFFDirectory *td = &tif->tif_dir;
552
553 if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
554 if (!(*tif->tif_setupdecode)(tif))
555 return (0);
556 tif->tif_flags |= TIFF_CODERSETUP;
557 }
558 tif->tif_curstrip = strip;
559 tif->tif_row = (strip % td->td_stripsperimage) * td->td_rowsperstrip;
560 tif->tif_rawcp = tif->tif_rawdata;
561 tif->tif_rawcc = td->td_stripbytecount[strip];
562 return ((*tif->tif_predecode)(tif,
563 (tsample_t)(strip / td->td_stripsperimage)));
564}
565
566/*
567 * Set state to appear as if a
568 * tile has just been read in.
569 */
570static int
571TIFFStartTile(TIFF* tif, ttile_t tile)
572{
573 TIFFDirectory *td = &tif->tif_dir;
574
575 if ((tif->tif_flags & TIFF_CODERSETUP) == 0) {
576 if (!(*tif->tif_setupdecode)(tif))
577 return (0);
578 tif->tif_flags |= TIFF_CODERSETUP;
579 }
580 tif->tif_curtile = tile;
581 tif->tif_row =
582 (tile % TIFFhowmany(td->td_imagewidth, td->td_tilewidth)) *
583 td->td_tilelength;
584 tif->tif_col =
585 (tile % TIFFhowmany(td->td_imagelength, td->td_tilelength)) *
586 td->td_tilewidth;
587 tif->tif_rawcp = tif->tif_rawdata;
588 tif->tif_rawcc = td->td_stripbytecount[tile];
589 return ((*tif->tif_predecode)(tif,
590 (tsample_t)(tile/td->td_stripsperimage)));
591}
592
593static int
594TIFFCheckRead(TIFF* tif, int tiles)
595{
596 if (tif->tif_mode == O_WRONLY) {
597 TIFFError(tif->tif_name, "File not open for reading");
598 return (0);
599 }
600 if (tiles ^ isTiled(tif)) {
601 TIFFError(tif->tif_name, tiles ?
602 "Can not read tiles from a stripped image" :
603 "Can not read scanlines from a tiled image");
604 return (0);
605 }
606 return (1);
607}
608
609void
610_TIFFNoPostDecode(TIFF* tif, tidata_t buf, tsize_t cc)
611{
612 (void) tif; (void) buf; (void) cc;
613}
614
615void
616_TIFFSwab16BitData(TIFF* tif, tidata_t buf, tsize_t cc)
617{
618 (void) tif;
619 assert((cc & 1) == 0);
620 TIFFSwabArrayOfShort((uint16*) buf, cc/2);
621}
622
623void
624_TIFFSwab32BitData(TIFF* tif, tidata_t buf, tsize_t cc)
625{
626 (void) tif;
627 assert((cc & 3) == 0);
628 TIFFSwabArrayOfLong((uint32*) buf, cc/4);
629}
630
631void
632_TIFFSwab64BitData(TIFF* tif, tidata_t buf, tsize_t cc)
633{
634 (void) tif;
635 assert((cc & 7) == 0);
636 TIFFSwabArrayOfDouble((double*) buf, cc/8);
637}