4 * A photo image file handler for GIF files. Reads 87a and 89a GIF
5 * files. At present there is no write function. GIF images may be
6 * read using the -data option of the photo image. The data may be
7 * given as a binary string in a Tcl_Obj or by representing
8 * the data as BASE64 encoded ascii. Derived from the giftoppm code
9 * found in the pbmplus package and tkImgFmtPPM.c in the tk4.0b2
12 * Copyright (c) Reed Wade (wade@cs.utk.edu), University of Tennessee
13 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
14 * Copyright (c) 1997 Australian National University
16 * See the file "license.terms" for information on usage and redistribution
17 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
19 * This file also contains code from the giftoppm program, which is
20 * copyrighted as follows:
22 * +-------------------------------------------------------------------+
23 * | Copyright 1990, David Koblas. |
24 * | Permission to use, copy, modify, and distribute this software |
25 * | and its documentation for any purpose and without fee is hereby |
26 * | granted, provided that the above copyright notice appear in all |
27 * | copies and that both that copyright notice and this permission |
28 * | notice appear in supporting documentation. This software is |
29 * | provided "as is" without express or implied warranty. |
30 * +-------------------------------------------------------------------+
36 * GIF's are represented as data in base64 format.
37 * base64 strings consist of 4 6-bit characters -> 3 8 bit bytes.
38 * A-Z, a-z, 0-9, + and / represent the 64 values (in order).
39 * '=' is a trailing padding char when the un-encoded data is not a
40 * multiple of 3 bytes. We'll ignore white space when encountered.
41 * Any other invalid character is treated as an EOF
44 #define GIF_SPECIAL (256)
45 #define GIF_PAD (GIF_SPECIAL+1)
46 #define GIF_SPACE (GIF_SPECIAL+2)
47 #define GIF_BAD (GIF_SPECIAL+3)
48 #define GIF_DONE (GIF_SPECIAL+4)
51 * structure to "mimic" FILE for Mread, so we can look like fread.
52 * The decoder state keeps track of which byte we are about to read,
56 typedef struct mFile {
57 unsigned char *data; /* mmencoded source string */
58 int c; /* bits left over from previous character */
59 int state; /* decoder state (0-4 or GIF_DONE) */
66 * The format record for the GIF file format:
69 static int FileMatchGIF _ANSI_ARGS_((Tcl_Channel chan, char *fileName,
70 char *formatString, int *widthPtr, int *heightPtr));
71 static int FileReadGIF _ANSI_ARGS_((Tcl_Interp *interp,
72 Tcl_Channel chan, char *fileName, char *formatString,
73 Tk_PhotoHandle imageHandle, int destX, int destY,
74 int width, int height, int srcX, int srcY));
75 static int StringMatchGIF _ANSI_ARGS_(( Tcl_Obj *dataObj,
76 char *formatString, int *widthPtr, int *heightPtr));
77 static int StringReadGIF _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *dataObj,
78 char *formatString, Tk_PhotoHandle imageHandle,
79 int destX, int destY, int width, int height,
82 Tk_PhotoImageFormat tkImgFmtGIF = {
84 FileMatchGIF, /* fileMatchProc */
85 StringMatchGIF, /* stringMatchProc */
86 FileReadGIF, /* fileReadProc */
87 StringReadGIF, /* stringReadProc */
88 NULL, /* fileWriteProc */
89 NULL, /* stringWriteProc */
92 #define INTERLACE 0x40
93 #define LOCALCOLORMAP 0x80
94 #define BitSet(byte, bit) (((byte) & (bit)) == (bit))
95 #define MAXCOLORMAPSIZE 256
100 #define MAX_LWZ_BITS 12
101 #define LM_to_uint(a,b) (((b)<<8)|(a))
102 #define ReadOK(file,buffer,len) (Fread(buffer, len, 1, file) != 0)
105 * HACK ALERT!! HACK ALERT!! HACK ALERT!!
106 * This code is hard-wired for reading from files. In order to read
107 * from a data stream, we'll trick fread so we can reuse the same code.
108 * 0==from file; 1==from base64 encoded data; 2==from binary data
111 static int fromData=0;
114 * Prototypes for local procedures defined in this file:
117 static int DoExtension _ANSI_ARGS_((Tcl_Channel chan, int label,
119 static int GetCode _ANSI_ARGS_((Tcl_Channel chan, int code_size,
121 static int GetDataBlock _ANSI_ARGS_((Tcl_Channel chan,
122 unsigned char *buf));
123 static int LWZReadByte _ANSI_ARGS_((Tcl_Channel chan, int flag,
124 int input_code_size));
125 static int ReadColorMap _ANSI_ARGS_((Tcl_Channel chan, int number,
126 unsigned char buffer[MAXCOLORMAPSIZE][4]));
127 static int ReadGIFHeader _ANSI_ARGS_((Tcl_Channel chan,
128 int *widthPtr, int *heightPtr));
129 static int ReadImage _ANSI_ARGS_((Tcl_Interp *interp,
130 char *imagePtr, Tcl_Channel chan,
132 unsigned char cmap[MAXCOLORMAPSIZE][4],
133 int width, int height, int srcX, int srcY,
134 int interlace, int transparent));
137 * these are for the BASE64 image reader code only
140 static int Fread _ANSI_ARGS_((unsigned char *dst, size_t size,
141 size_t count, Tcl_Channel chan));
142 static int Mread _ANSI_ARGS_((unsigned char *dst, size_t size,
143 size_t count, MFile *handle));
144 static int Mgetc _ANSI_ARGS_((MFile *handle));
145 static int char64 _ANSI_ARGS_((int c));
146 static void mInit _ANSI_ARGS_((unsigned char *string,
150 *----------------------------------------------------------------------
154 * This procedure is invoked by the photo image type to see if
155 * a file contains image data in GIF format.
158 * The return value is 1 if the first characters in file f look
159 * like GIF data, and 0 otherwise.
162 * The access position in f may change.
164 *----------------------------------------------------------------------
168 FileMatchGIF(chan, fileName, formatString, widthPtr, heightPtr)
169 Tcl_Channel chan; /* The image file, open for reading. */
170 char *fileName; /* The name of the image file. */
171 char *formatString; /* User-specified format string, or NULL. */
172 int *widthPtr, *heightPtr; /* The dimensions of the image are
173 * returned here if the file is a valid
176 return ReadGIFHeader(chan, widthPtr, heightPtr);
180 *----------------------------------------------------------------------
184 * This procedure is called by the photo image type to read
185 * GIF format data from a file and write it into a given
189 * A standard TCL completion code. If TCL_ERROR is returned
190 * then an error message is left in interp->result.
193 * The access position in file f is changed, and new data is
194 * added to the image given by imageHandle.
196 *----------------------------------------------------------------------
200 FileReadGIF(interp, chan, fileName, formatString, imageHandle, destX, destY,
201 width, height, srcX, srcY)
202 Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
203 Tcl_Channel chan; /* The image file, open for reading. */
204 char *fileName; /* The name of the image file. */
205 char *formatString; /* User-specified format string, or NULL. */
206 Tk_PhotoHandle imageHandle; /* The photo image to write into. */
207 int destX, destY; /* Coordinates of top-left pixel in
208 * photo image to be written to. */
209 int width, height; /* Dimensions of block of photo image to
211 int srcX, srcY; /* Coordinates of top-left pixel to be used
212 * in image being read. */
214 int fileWidth, fileHeight;
216 Tk_PhotoImageBlock block;
217 unsigned char buf[100];
219 unsigned char colorMap[MAXCOLORMAPSIZE][4];
220 int transparent = -1;
222 if (!ReadGIFHeader(chan, &fileWidth, &fileHeight)) {
223 Tcl_AppendResult(interp, "couldn't read GIF header from file \"",
224 fileName, "\"", NULL);
227 if ((fileWidth <= 0) || (fileHeight <= 0)) {
228 Tcl_AppendResult(interp, "GIF image file \"", fileName,
229 "\" has dimension(s) <= 0", (char *) NULL);
233 if (Fread(buf, 1, 3, chan) != 3) {
236 bitPixel = 2<<(buf[0]&0x07);
238 if (BitSet(buf[0], LOCALCOLORMAP)) { /* Global Colormap */
239 if (!ReadColorMap(chan, bitPixel, colorMap)) {
240 Tcl_AppendResult(interp, "error reading color map",
246 if ((srcX + width) > fileWidth) {
247 width = fileWidth - srcX;
249 if ((srcY + height) > fileHeight) {
250 height = fileHeight - srcY;
252 if ((width <= 0) || (height <= 0)
253 || (srcX >= fileWidth) || (srcY >= fileHeight)) {
257 Tk_PhotoExpand(imageHandle, destX + width, destY + height);
260 block.height = height;
262 block.pitch = block.pixelSize * block.width;
266 nBytes = height * block.pitch;
267 block.pixelPtr = (unsigned char *) ckalloc((unsigned) nBytes);
270 if (Fread(buf, 1, 1, chan) != 1) {
272 * Premature end of image. We should really notify
273 * the user, but for now just show garbage.
289 * This is a GIF extension.
292 if (Fread(buf, 1, 1, chan) != 1) {
294 "error reading extension function code in GIF image";
297 if (DoExtension(chan, buf[0], &transparent) < 0) {
298 interp->result = "error reading extension in GIF image";
306 * Not a valid start character; ignore it.
311 if (Fread(buf, 1, 9, chan) != 9) {
312 interp->result = "couldn't read left/top/width/height in GIF image";
316 bitPixel = 1<<((buf[8]&0x07)+1);
318 if (BitSet(buf[8], LOCALCOLORMAP)) {
319 if (!ReadColorMap(chan, bitPixel, colorMap)) {
320 Tcl_AppendResult(interp, "error reading color map",
325 if (ReadImage(interp, (char *) block.pixelPtr, chan, width,
326 height, colorMap, fileWidth, fileHeight, srcX, srcY,
327 BitSet(buf[8], INTERLACE), transparent) != TCL_OK) {
333 if (transparent == -1) {
334 Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height);
337 unsigned char *imagePtr, *rowPtr, *pixelPtr;
339 imagePtr = rowPtr = block.pixelPtr;
340 for (y = 0; y < height; y++) {
344 /* search for first non-transparent pixel */
345 while ((x < width) && !(pixelPtr[CM_ALPHA])) {
349 /* search for first transparent pixel */
350 while ((end < width) && pixelPtr[CM_ALPHA]) {
351 end++; pixelPtr += 4;
354 block.pixelPtr = rowPtr + 4 * x;
355 Tk_PhotoPutBlock(imageHandle, &block, destX+x,
360 rowPtr += block.pitch;
362 block.pixelPtr = imagePtr;
364 ckfree((char *) block.pixelPtr);
368 ckfree((char *) block.pixelPtr);
374 *----------------------------------------------------------------------
378 * This procedure is invoked by the photo image type to see if
379 * an object contains image data in GIF format.
382 * The return value is 1 if the first characters in the data are
383 * like GIF data, and 0 otherwise.
386 * the size of the image is placed in widthPre and heightPtr.
388 *----------------------------------------------------------------------
392 StringMatchGIF(dataObj, formatString, widthPtr, heightPtr)
393 Tcl_Obj *dataObj; /* the object containing the image data */
394 char *formatString; /* the image format string */
395 int *widthPtr; /* where to put the string width */
396 int *heightPtr; /* where to put the string height */
398 unsigned char *data, header[10];
402 data = Tcl_GetStringFromObj(dataObj, &length);
404 /* Header is a minimum of 10 bytes */
409 /* Check whether the data is Base64 encoded */
411 if ((strncmp("GIF87a", data, 6) != 0) &&
412 (strncmp("GIF89a", data, 6) != 0)) {
413 /* Try interpreting the data as Base64 encoded */
414 mInit((unsigned char *) data, &handle);
415 got = Mread(header, 10, 1, &handle);
417 || ((strncmp("GIF87a", (char *) header, 6) != 0)
418 && (strncmp("GIF89a", (char *) header, 6) != 0))) {
422 memcpy((VOID *) header, (VOID *) data, 10);
424 *widthPtr = LM_to_uint(header[6],header[7]);
425 *heightPtr = LM_to_uint(header[8],header[9]);
430 *----------------------------------------------------------------------
432 * StringReadGif -- --
434 * This procedure is called by the photo image type to read
435 * GIF format data from an object, optionally base64 encoded,
436 * and give it to the photo image.
439 * A standard TCL completion code. If TCL_ERROR is returned
440 * then an error message is left in interp->result.
443 * new data is added to the image given by imageHandle. This
444 * procedure calls FileReadGif by redefining the operation of
445 * fprintf temporarily.
447 *----------------------------------------------------------------------
451 StringReadGIF(interp,dataObj,formatString,imageHandle,
452 destX, destY, width, height, srcX, srcY)
453 Tcl_Interp *interp; /* interpreter for reporting errors in */
454 Tcl_Obj *dataObj; /* object containing the image */
455 char *formatString; /* format string if any */
456 Tk_PhotoHandle imageHandle; /* the image to write this data into */
457 int destX, destY; /* The rectangular region of the */
458 int width, height; /* image to copy */
465 /* Check whether the data is Base64 encoded */
466 data = Tcl_GetStringFromObj(dataObj, NULL);
467 if ((strncmp("GIF87a", data, 6) != 0) &&
468 (strncmp("GIF89a", data, 6) != 0)) {
469 mInit((unsigned char *)data,&handle);
471 dataSrc = (Tcl_Channel) &handle;
474 mInit((unsigned char *)data,&handle);
475 dataSrc = (Tcl_Channel) &handle;
477 result = FileReadGIF(interp, dataSrc, "inline data",
478 formatString, imageHandle, destX, destY, width, height,
485 *----------------------------------------------------------------------
489 * This procedure reads the GIF header from the beginning of a
490 * GIF file and returns the dimensions of the image.
493 * The return value is 1 if file "f" appears to start with
494 * a valid GIF header, 0 otherwise. If the header is valid,
495 * then *widthPtr and *heightPtr are modified to hold the
496 * dimensions of the image.
499 * The access position in f advances.
501 *----------------------------------------------------------------------
505 ReadGIFHeader(chan, widthPtr, heightPtr)
506 Tcl_Channel chan; /* Image file to read the header from */
507 int *widthPtr, *heightPtr; /* The dimensions of the image are
510 unsigned char buf[7];
512 if ((Fread(buf, 1, 6, chan) != 6)
513 || ((strncmp("GIF87a", (char *) buf, 6) != 0)
514 && (strncmp("GIF89a", (char *) buf, 6) != 0))) {
518 if (Fread(buf, 1, 4, chan) != 4) {
522 *widthPtr = LM_to_uint(buf[0],buf[1]);
523 *heightPtr = LM_to_uint(buf[2],buf[3]);
528 *-----------------------------------------------------------------
529 * The code below is copied from the giftoppm program and modified
531 *-----------------------------------------------------------------
535 ReadColorMap(chan, number, buffer)
538 unsigned char buffer[MAXCOLORMAPSIZE][4];
541 unsigned char rgb[3];
543 for (i = 0; i < number; ++i) {
544 if (! ReadOK(chan, rgb, sizeof(rgb))) {
548 buffer[i][CM_RED] = rgb[0] ;
549 buffer[i][CM_GREEN] = rgb[1] ;
550 buffer[i][CM_BLUE] = rgb[2] ;
551 buffer[i][CM_ALPHA] = 255 ;
559 DoExtension(chan, label, transparent)
564 static unsigned char buf[256];
568 case 0x01: /* Plain Text Extension */
571 case 0xff: /* Application Extension */
574 case 0xfe: /* Comment Extension */
576 count = GetDataBlock(chan, (unsigned char*) buf);
580 case 0xf9: /* Graphic Control Extension */
581 count = GetDataBlock(chan, (unsigned char*) buf);
585 if ((buf[0] & 0x1) != 0) {
586 *transparent = buf[3];
590 count = GetDataBlock(chan, (unsigned char*) buf);
596 count = GetDataBlock(chan, (unsigned char*) buf);
601 static int ZeroDataBlock = 0;
604 GetDataBlock(chan, buf)
610 if (! ReadOK(chan, &count,1)) {
614 ZeroDataBlock = count == 0;
616 if ((count != 0) && (! ReadOK(chan, buf, count))) {
625 ReadImage(interp, imagePtr, chan, len, rows, cmap,
626 width, height, srcX, srcY, interlace, transparent)
631 unsigned char cmap[MAXCOLORMAPSIZE][4];
639 int xpos = 0, ypos = 0, pass = 0;
644 * Initialize the Compression routines
646 if (! ReadOK(chan, &c, 1)) {
647 Tcl_AppendResult(interp, "error reading GIF image: ",
648 Tcl_PosixError(interp), (char *) NULL);
652 if (LWZReadByte(chan, 1, c) < 0) {
653 interp->result = "format error in GIF image";
657 if (transparent!=-1) {
658 cmap[transparent][CM_RED] = 0;
659 cmap[transparent][CM_GREEN] = 0;
660 cmap[transparent][CM_BLUE] = 0;
661 cmap[transparent][CM_ALPHA] = 0;
665 while ((v = LWZReadByte(chan, 0, c)) >= 0 ) {
667 if ((xpos>=srcX) && (xpos<srcX+len) &&
668 (ypos>=srcY) && (ypos<srcY+rows)) {
669 *pixelPtr++ = cmap[v][CM_RED];
670 *pixelPtr++ = cmap[v][CM_GREEN];
671 *pixelPtr++ = cmap[v][CM_BLUE];
672 *pixelPtr++ = cmap[v][CM_ALPHA];
689 while (ypos >= height) {
705 pixelPtr = imagePtr + (ypos-srcY) * len * 4;
714 LWZReadByte(chan, flag, input_code_size)
719 static int fresh = 0;
721 static int code_size, set_code_size;
722 static int max_code, max_code_size;
723 static int firstcode, oldcode;
724 static int clear_code, end_code;
725 static int table[2][(1<< MAX_LWZ_BITS)];
726 static int stack[(1<<(MAX_LWZ_BITS))*2], *sp;
730 set_code_size = input_code_size;
731 code_size = set_code_size+1;
732 clear_code = 1 << set_code_size ;
733 end_code = clear_code + 1;
734 max_code_size = 2*clear_code;
735 max_code = clear_code+2;
741 for (i = 0; i < clear_code; ++i) {
745 for (; i < (1<<MAX_LWZ_BITS); ++i) {
746 table[0][i] = table[1][0] = 0;
755 firstcode = oldcode = GetCode(chan, code_size, 0);
756 } while (firstcode == clear_code);
764 while ((code = GetCode(chan, code_size, 0)) >= 0) {
765 if (code == clear_code) {
766 for (i = 0; i < clear_code; ++i) {
771 for (; i < (1<<MAX_LWZ_BITS); ++i) {
772 table[0][i] = table[1][i] = 0;
775 code_size = set_code_size+1;
776 max_code_size = 2*clear_code;
777 max_code = clear_code+2;
779 firstcode = oldcode = GetCode(chan, code_size, 0);
782 } else if (code == end_code) {
784 unsigned char buf[260];
790 while ((count = GetDataBlock(chan, buf)) > 0)
800 if (code >= max_code) {
805 while (code >= clear_code) {
806 *sp++ = table[1][code];
807 if (code == table[0][code]) {
811 * Used to be this instead, Steve Ball suggested
812 * the change to just return.
813 printf("circular table entry BIG ERROR\n");
816 code = table[0][code];
819 *sp++ = firstcode = table[1][code];
821 if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
822 table[0][code] = oldcode;
823 table[1][code] = firstcode;
825 if ((max_code>=max_code_size) && (max_code_size < (1<<MAX_LWZ_BITS))) {
841 GetCode(chan, code_size, flag)
846 static unsigned char buf[280];
847 static int curbit, lastbit, done, last_byte;
859 if ( (curbit+code_size) >= lastbit) {
861 /* ran off the end of my bits */
864 if (last_byte >= 2) {
865 buf[0] = buf[last_byte-2];
867 if (last_byte >= 1) {
868 buf[1] = buf[last_byte-1];
871 if ((count = GetDataBlock(chan, &buf[2])) == 0) {
875 last_byte = 2 + count;
876 curbit = (curbit - lastbit) + 16;
877 lastbit = (2+count)*8 ;
881 for (i = curbit, j = 0; j < code_size; ++i, ++j) {
882 ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
891 *----------------------------------------------------------------------
895 * This procedure initializes a base64 decoder handle
901 * the base64 handle is initialized
903 *----------------------------------------------------------------------
907 mInit(string, handle)
908 unsigned char *string; /* string containing initial mmencoded data */
909 MFile *handle; /* mmdecode "file" handle */
911 handle->data = string;
917 *----------------------------------------------------------------------
921 * This procedure is invoked by the GIF file reader as a
922 * temporary replacement for "fread", to get GIF data out
923 * of a string (using Mgetc).
926 * The return value is the number of characters "read"
929 * The base64 handle will change state.
931 *----------------------------------------------------------------------
935 Mread(dst, chunkSize, numChunks, handle)
936 unsigned char *dst; /* where to put the result */
937 size_t chunkSize; /* size of each transfer */
938 size_t numChunks; /* number of chunks */
939 MFile *handle; /* mmdecode "file" handle */
942 int count = chunkSize * numChunks;
944 for(i=0; i<count && (c=Mgetc(handle)) != GIF_DONE; i++) {
951 * get the next decoded character from an mmencode handle
952 * This causes at least 1 character to be "read" from the encoded string
956 *----------------------------------------------------------------------
960 * This procedure decodes and returns the next byte from a base64
964 * The next byte (or GIF_DONE) is returned.
967 * The base64 handle will change state.
969 *----------------------------------------------------------------------
974 MFile *handle; /* Handle containing decoder data and state. */
977 int result = 0; /* Initialization needed only to prevent
978 * gcc compiler warning. */
980 if (handle->state == GIF_DONE) {
985 c = char64(*handle->data);
987 } while (c==GIF_SPACE);
990 handle->state = GIF_DONE;
991 return(handle->state ? handle->c : GIF_DONE);
994 switch (handle->state++) {
997 result = Mgetc(handle);
1000 result = handle->c | (c>>4);
1001 handle->c = (c&0xF)<<4;
1004 result = handle->c | (c>>2);
1005 handle->c = (c&0x3) << 6;
1008 result = handle->c | c;
1016 *----------------------------------------------------------------------
1020 * This procedure converts a base64 ascii character into its binary
1021 * equivalent. This code is a slightly modified version of the
1022 * char64 proc in N. Borenstein's metamail decoder.
1025 * The binary value, or an error code.
1029 *----------------------------------------------------------------------
1037 case 'A': return(0); case 'B': return(1); case 'C': return(2);
1038 case 'D': return(3); case 'E': return(4); case 'F': return(5);
1039 case 'G': return(6); case 'H': return(7); case 'I': return(8);
1040 case 'J': return(9); case 'K': return(10); case 'L': return(11);
1041 case 'M': return(12); case 'N': return(13); case 'O': return(14);
1042 case 'P': return(15); case 'Q': return(16); case 'R': return(17);
1043 case 'S': return(18); case 'T': return(19); case 'U': return(20);
1044 case 'V': return(21); case 'W': return(22); case 'X': return(23);
1045 case 'Y': return(24); case 'Z': return(25); case 'a': return(26);
1046 case 'b': return(27); case 'c': return(28); case 'd': return(29);
1047 case 'e': return(30); case 'f': return(31); case 'g': return(32);
1048 case 'h': return(33); case 'i': return(34); case 'j': return(35);
1049 case 'k': return(36); case 'l': return(37); case 'm': return(38);
1050 case 'n': return(39); case 'o': return(40); case 'p': return(41);
1051 case 'q': return(42); case 'r': return(43); case 's': return(44);
1052 case 't': return(45); case 'u': return(46); case 'v': return(47);
1053 case 'w': return(48); case 'x': return(49); case 'y': return(50);
1054 case 'z': return(51); case '0': return(52); case '1': return(53);
1055 case '2': return(54); case '3': return(55); case '4': return(56);
1056 case '5': return(57); case '6': return(58); case '7': return(59);
1057 case '8': return(60); case '9': return(61); case '+': return(62);
1058 case '/': return(63);
1060 case ' ': case '\t': case '\n': case '\r': case '\f': return(GIF_SPACE);
1061 case '=': return(GIF_PAD);
1062 case '\0': return(GIF_DONE);
1063 default: return(GIF_BAD);
1068 *----------------------------------------------------------------------
1072 * This procedure calls either fread or Mread to read data
1073 * from a file or a base64 encoded string.
1075 * Results: - same as fread
1077 *----------------------------------------------------------------------
1081 Fread(dst, hunk, count, chan)
1082 unsigned char *dst; /* where to put the result */
1083 size_t hunk,count; /* how many */
1089 return Tcl_Read(chan, (char *) dst, (int) (hunk * count));
1091 return(Mread(dst, hunk, count, (MFile *) chan));
1093 handle = (MFile *) chan;
1094 memcpy((VOID *)dst, (VOID *) handle->data, (int) (hunk * count));
1095 handle->data += hunk * count;
1096 return((int) (hunk * count));