xref: /haiku/src/bin/unzip/funzip.c (revision 17049c451a91f427aec94b944b75876b611103e7)
1 /*
2   Copyright (c) 1990-2002 Info-ZIP.  All rights reserved.
3 
4   See the accompanying file LICENSE, version 2000-Apr-09 or later
5   (the contents of which are also included in unzip.h) for terms of use.
6   If, for some reason, all these files are missing, the Info-ZIP license
7   also may be found at:  ftp://ftp.info-zip.org/pub/infozip/license.html
8 */
9 /* funzip.c -- by Mark Adler */
10 
11 #define VERSION "3.94 of 20 January 2002"
12 
13 
14 /* Copyright history:
15    - Starting with UnZip 5.41 of 16-April-2000, this source file
16      is covered by the Info-Zip LICENSE cited above.
17    - Prior versions of this source file, found in UnZip source packages
18      up to UnZip 5.40, were put in the public domain.
19      The original copyright note by Mark Adler was:
20          "You can do whatever you like with this source file,
21          though I would prefer that if you modify it and
22          redistribute it that you include comments to that effect
23          with your name and the date.  Thank you."
24 
25    History:
26    vers     date          who           what
27    ----   ---------  --------------  ------------------------------------
28    1.0    13 Aug 92  M. Adler        really simple unzip filter.
29    1.1    13 Aug 92  M. Adler        cleaned up somewhat, give help if
30                                      stdin not redirected, warn if more
31                                      zip file entries after the first.
32    1.2    15 Aug 92  M. Adler        added check of lengths for stored
33                                      entries, added more help.
34    1.3    16 Aug 92  M. Adler        removed redundant #define's, added
35                                      decryption.
36    1.4    27 Aug 92  G. Roelofs      added exit(0).
37    1.5     1 Sep 92  K. U. Rommel    changed read/write modes for OS/2.
38    1.6     6 Sep 92  G. Roelofs      modified to use dummy crypt.c and
39                                      crypt.h instead of -DCRYPT.
40    1.7    23 Sep 92  G. Roelofs      changed to use DOS_OS2; included
41                                      crypt.c under MS-DOS.
42    1.8     9 Oct 92  M. Adler        improved inflation error msgs.
43    1.9    17 Oct 92  G. Roelofs      changed ULONG/UWORD/byte to ulg/ush/uch;
44                                      renamed inflate_entry() to inflate();
45                                      adapted to use new, in-place zdecode.
46    2.0    22 Oct 92  M. Adler        allow filename argument, prompt for
47                                      passwords and don't echo, still allow
48                                      command-line password entry, but as an
49                                      option.
50    2.1    23 Oct 92  J-l. Gailly     fixed crypt/store bug,
51                      G. Roelofs      removed crypt.c under MS-DOS, fixed
52                                      decryption check to compare single byte.
53    2.2    28 Oct 92  G. Roelofs      removed declaration of key.
54    2.3    14 Dec 92  M. Adler        replaced fseek (fails on stdin for SCO
55                                      Unix V.3.2.4).  added quietflg for
56                                      inflate.c.
57    3.0    11 May 93  M. Adler        added gzip support
58    3.1     9 Jul 93  K. U. Rommel    fixed OS/2 pipe bug (PIPE_ERROR)
59    3.2     4 Sep 93  G. Roelofs      moved crc_32_tab[] to tables.h; used FOPx
60                                      from unzip.h; nuked OUTB macro and outbuf;
61                                      replaced flush(); inlined FlushOutput();
62                                      renamed decrypt to encrypted
63    3.3    29 Sep 93  G. Roelofs      replaced ReadByte() with NEXTBYTE macro;
64                                      revised (restored?) flush(); added FUNZIP
65    3.4    21 Oct 93  G. Roelofs      renamed quietflg to qflag; changed outcnt,
66                      H. Gessau       second updcrc() arg and flush() arg to ulg;
67                                      added inflate_free(); added "g =" to null
68                                      getc(in) to avoid compiler warnings
69    3.5    31 Oct 93  H. Gessau       changed DOS_OS2 to DOS_NT_OS2
70    3.6     6 Dec 93  H. Gessau       added "near" to mask_bits[]
71    3.7     9 Dec 93  G. Roelofs      added extent typecasts to fwrite() checks
72    3.8    28 Jan 94  GRR/JlG         initialized g variable in main() for gcc
73    3.81   22 Feb 94  M. Hanning-Lee  corrected usage message
74    3.82   27 Feb 94  G. Roelofs      added some typecasts to avoid warnings
75    3.83   22 Jul 94  G. Roelofs      changed fprintf to macro for DLLs
76     -      2 Aug 94  -               public release with UnZip 5.11
77     -     28 Aug 94  -               public release with UnZip 5.12
78    3.84    1 Oct 94  K. U. Rommel    changes for Metaware High C
79    3.85   29 Oct 94  G. Roelofs      changed fprintf macro to Info
80    3.86    7 May 95  K. Davis        RISCOS patches;
81                      P. Kienitz      Amiga patches
82    3.87   12 Aug 95  G. Roelofs      inflate_free(), DESTROYGLOBALS fixes
83    3.88    4 Sep 95  C. Spieler      reordered macro to work around MSC 5.1 bug
84    3.89   22 Nov 95  PK/CS           ifdef'd out updcrc() for ASM_CRC
85    3.9    17 Dec 95  G. Roelofs      modified for USE_ZLIB (new fillinbuf())
86     -     30 Apr 96  -               public release with UnZip 5.2
87    3.91   17 Aug 96  G. Roelofs      main() -> return int (Peter Seebach)
88    3.92   13 Apr 97  G. Roelofs      minor cosmetic fixes to messages
89     -     22 Apr 97  -               public release with UnZip 5.3
90     -     31 May 97  -               public release with UnZip 5.31
91    3.93   20 Sep 97  G. Roelofs      minor cosmetic fixes to messages
92     -      3 Nov 97  -               public release with UnZip 5.32
93     -     28 Nov 98  -               public release with UnZip 5.4
94     -     16 Apr 00  -               public release with UnZip 5.41
95     -     14 Jan 01  -               public release with UnZip 5.42
96    3.94   20 Feb 01  C. Spieler      added support for Deflate64(tm)
97  */
98 
99 
100 /*
101 
102    All funzip does is take a zipfile from stdin and decompress the
103    first entry to stdout.  The entry has to be either deflated or
104    stored.  If the entry is encrypted, then the decryption password
105    must be supplied on the command line as the first argument.
106 
107    funzip needs to be linked with inflate.o and crypt.o compiled from
108    the unzip source.  If decryption is desired, the full version of
109    crypt.c (and crypt.h) from zcrypt28.zip or later must be used.
110 
111  */
112 
113 #ifndef FUNZIP
114 #  define FUNZIP
115 #endif
116 #define UNZIP_INTERNAL
117 #include "unzip.h"
118 #include "crypt.h"
119 #include "ttyio.h"
120 
121 #ifdef EBCDIC
122 #  undef EBCDIC                 /* don't need ebcdic[] */
123 #endif
124 #include "tables.h"             /* crc_32_tab[] */
125 
126 #ifndef USE_ZLIB  /* zlib's function is called inflate(), too */
127 #  define UZinflate inflate
128 #endif
129 
130 /* PKZIP header definitions */
131 #define ZIPMAG 0x4b50           /* two-byte zip lead-in */
132 #define LOCREM 0x0403           /* remaining two bytes in zip signature */
133 #define LOCSIG 0x04034b50L      /* full signature */
134 #define LOCFLG 4                /* offset of bit flag */
135 #define  CRPFLG 1               /*  bit for encrypted entry */
136 #define  EXTFLG 8               /*  bit for extended local header */
137 #define LOCHOW 6                /* offset of compression method */
138 #define LOCTIM 8                /* file mod time (for decryption) */
139 #define LOCCRC 12               /* offset of crc */
140 #define LOCSIZ 16               /* offset of compressed size */
141 #define LOCLEN 20               /* offset of uncompressed length */
142 #define LOCFIL 24               /* offset of file name field length */
143 #define LOCEXT 26               /* offset of extra field length */
144 #define LOCHDR 28               /* size of local header, including LOCREM */
145 #define EXTHDR 16               /* size of extended local header, inc sig */
146 
147 /* GZIP header definitions */
148 #define GZPMAG 0x8b1f           /* two-byte gzip lead-in */
149 #define GZPHOW 0                /* offset of method number */
150 #define GZPFLG 1                /* offset of gzip flags */
151 #define  GZPMUL 2               /* bit for multiple-part gzip file */
152 #define  GZPISX 4               /* bit for extra field present */
153 #define  GZPISF 8               /* bit for filename present */
154 #define  GZPISC 16              /* bit for comment present */
155 #define  GZPISE 32              /* bit for encryption */
156 #define GZPTIM 2                /* offset of Unix file modification time */
157 #define GZPEXF 6                /* offset of extra flags */
158 #define GZPCOS 7                /* offset of operating system compressed on */
159 #define GZPHDR 8                /* length of minimal gzip header */
160 
161 #ifdef THEOS
162 /* Macros cause stack overflow in compiler */
SH(uch * p)163 ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
LG(uch * p)164 ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
165 #else /* !THEOS */
166 /* Macros for getting two-byte and four-byte header values */
167 #define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8))
168 #define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16))
169 #endif /* ?THEOS */
170 
171 /* Function prototypes */
172 static void err OF((int, char *));
173 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
174 static int partflush OF((uch *rawbuf, unsigned w));
175 #endif
176 int main OF((int, char **));
177 
178 /* Globals */
179 FILE *out;                      /* output file (*in moved to G struct) */
180 ulg outsiz;                     /* total bytes written to out */
181 int encrypted;                  /* flag to turn on decryption */
182 
183 /* Masks for inflate.c */
184 ZCONST ush near mask_bits[] = {
185     0x0000,
186     0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff,
187     0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff
188 };
189 
190 
191 #ifdef USE_ZLIB
192 
fillinbuf(__G)193 int fillinbuf(__G)
194 __GDEF
195 /* Fill input buffer for pull-model inflate() in zlib.  Return the number of
196  * bytes in inbuf. */
197 {
198 /*   GRR: check return value from fread(): same as read()?  check errno? */
199   if ((G.incnt = fread((char *)G.inbuf, 1, INBUFSIZ, G.in)) <= 0)
200     return 0;
201   G.inptr = G.inbuf;
202 
203 #if CRYPT
204   if (encrypted) {
205     uch *p;
206     int n;
207 
208     for (n = G.incnt, p = G.inptr;  n--;  p++)
209       zdecode(*p);
210   }
211 #endif /* CRYPT */
212 
213   return G.incnt;
214 
215 }
216 
217 #endif /* USE_ZLIB */
218 
219 
220 #if (!defined(USE_ZLIB) || defined(USE_OWN_CRCTAB))
221 #ifdef USE_ZLIB
get_crc_table()222 ZCONST uLongf *get_crc_table()
223 {
224   return (ZCONST uLongf *)crc_32_tab;
225 }
226 #else /* !USE_ZLIB */
get_crc_table()227 ZCONST ulg near *get_crc_table()
228 {
229   return crc_32_tab;
230 }
231 #endif /* ?USE_ZLIB */
232 #endif /* !USE_ZLIB || USE_OWN_CRCTAB */
233 
234 
err(n,m)235 static void err(n, m)
236 int n;
237 char *m;
238 /* Exit on error with a message and a code */
239 {
240   Info(slide, 1, ((char *)slide, "funzip error: %s\n", m));
241   DESTROYGLOBALS();
242   EXIT(n);
243 }
244 
245 
246 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
247 
partflush(rawbuf,w)248 static int partflush(rawbuf, w)
249 uch *rawbuf;     /* start of buffer area to flush */
250 extent w;       /* number of bytes to flush */
251 {
252   G.crc32val = crc32(G.crc32val, rawbuf, (extent)w);
253   if (fwrite((char *)rawbuf,1,(extent)w,out) != (extent)w && !PIPE_ERROR)
254     err(9, "out of space on stdout");
255   outsiz += w;
256   return 0;
257 }
258 
259 
flush(w)260 int flush(w)    /* used by inflate.c (FLUSH macro) */
261 ulg w;          /* number of bytes to flush */
262 {
263     uch *rawbuf;
264     int ret;
265 
266     /* On 16-bit systems (MSDOS, OS/2 1.x), the standard C library functions
267      * cannot handle writes of 64k blocks at once.  For these systems, the
268      * blocks to flush are split into pieces of 32k or less.
269      */
270     rawbuf = slide;
271     while (w > 0x8000L) {
272         ret = partflush(rawbuf, 0x8000);
273         if (ret != PK_OK)
274             return ret;
275         w -= 0x8000L;
276         rawbuf += (unsigned)0x8000;
277     }
278     return partflush(rawbuf, (extent)w);
279 } /* end function flush() */
280 
281 #else /* !(USE_DEFLATE64 && __16BIT__) */
282 
flush(w)283 int flush(w)    /* used by inflate.c (FLUSH macro) */
284 ulg w;          /* number of bytes to flush */
285 {
286   G.crc32val = crc32(G.crc32val, slide, (extent)w);
287   if (fwrite((char *)slide,1,(extent)w,out) != (extent)w && !PIPE_ERROR)
288     err(9, "out of space on stdout");
289   outsiz += w;
290   return 0;
291 }
292 
293 #endif /* ?(USE_DEFLATE64 && __16BIT__) */
294 
295 
main(argc,argv)296 int main(argc, argv)
297 int argc;
298 char **argv;
299 /* Given a zipfile on stdin, decompress the first entry to stdout. */
300 {
301   ush n;
302   uch h[LOCHDR];                /* first local header (GZPHDR < LOCHDR) */
303   int g = 0;                    /* true if gzip format */
304   unsigned method = 0;          /* initialized here to shut up gcc warning */
305 #if CRYPT
306   char *s = " [-password]";
307   char *p;                      /* password */
308 #else /* !CRYPT */
309   char *s = "";
310 #endif /* ?CRYPT */
311   CONSTRUCTGLOBALS();
312 
313   /* skip executable name */
314   argc--;
315   argv++;
316 
317 #if CRYPT
318   /* get the command line password, if any */
319   p = (char *)NULL;
320   if (argc && **argv == '-')
321   {
322     argc--;
323     p = 1 + *argv++;
324   }
325 #endif /* CRYPT */
326 
327 #ifdef MALLOC_WORK
328   /* The following expression is a cooked-down simplyfication of the
329      calculation for the work area size of UnZip (see unzip.c).  For
330      fUnZip, the work area does not need to match the granularity
331      of the complex unshrink structures, because it only supports
332      inflation.  But, like in UnZip, the zcalloc() wrapper function
333      is needed for the allocation, to support the 64kByte buffer on
334      16-bit systems.
335    */
336 # define UZ_SLIDE_CHUNK (sizeof(shrint)+sizeof(uch)+sizeof(uch))
337 # define UZ_NUMOF_CHUNKS (unsigned)( (WSIZE+UZ_SLIDE_CHUNK-1)/UZ_SLIDE_CHUNK )
338   G.area.Slide = (uch *)zcalloc(UZ_NUMOF_CHUNKS, UZ_SLIDE_CHUNK);
339 # undef UZ_SLIDE_CHUNK
340 # undef UZ_NUMOF_CHUNKS
341 #endif
342 
343   /* if no file argument and stdin not redirected, give the user help */
344   if (argc == 0 && isatty(0))
345   {
346     Info(slide, 1, ((char *)slide, "fUnZip (filter UnZip), version %s\n",
347       VERSION));
348     Info(slide, 1, ((char *)slide, "usage: ... | funzip%s | ...\n", s));
349     Info(slide, 1, ((char *)slide, "       ... | funzip%s > outfile\n", s));
350     Info(slide, 1, ((char *)slide, "       funzip%s infile.zip > outfile\n",s));
351     Info(slide, 1, ((char *)slide, "       funzip%s infile.gz > outfile\n", s));
352     Info(slide, 1, ((char *)slide, "Extracts to stdout the gzip file or first\
353  zip entry of stdin or the given file.\n"));
354     DESTROYGLOBALS();
355     EXIT(3);
356   }
357 
358   /* prepare to be a binary filter */
359   if (argc)
360   {
361     if ((G.in = fopen(*argv, FOPR)) == (FILE *)NULL)
362       err(2, "cannot find input file");
363   }
364   else
365   {
366 #ifdef DOS_FLX_NLM_OS2_W32
367 #if (defined(__HIGHC__) && !defined(FLEXOS))
368     setmode(stdin, _BINARY);
369 #else
370     setmode(0, O_BINARY);  /* some buggy C libraries require BOTH setmode() */
371 #endif                     /*  call AND the fdopen() in binary mode :-( */
372 #endif /* DOS_FLX_NLM_OS2_W32 */
373 
374 #ifdef RISCOS
375     G.in = stdin;
376 #else
377     if ((G.in = fdopen(0, FOPR)) == (FILE *)NULL)
378       err(2, "cannot find stdin");
379 #endif
380   }
381 
382 #ifdef DOS_FLX_H68_NLM_OS2_W32
383 #if (defined(__HIGHC__) && !defined(FLEXOS))
384   setmode(stdout, _BINARY);
385 #else
386   setmode(1, O_BINARY);
387 #endif
388 #endif /* DOS_FLX_H68_NLM_OS2_W32 */
389 
390 #ifdef RISCOS
391   out = stdout;
392 #else
393   if ((out = fdopen(1, FOPW)) == (FILE *)NULL)
394     err(2, "cannot write to stdout");
395 #endif
396 
397   /* read local header, check validity, and skip name and extra fields */
398   n = getc(G.in);  n |= getc(G.in) << 8;
399   if (n == ZIPMAG)
400   {
401     if (fread((char *)h, 1, LOCHDR, G.in) != LOCHDR || SH(h) != LOCREM)
402       err(3, "invalid zipfile");
403     switch (method = SH(h + LOCHOW)) {
404       case STORED:
405       case DEFLATED:
406 #ifdef USE_DEFLATE64
407       case ENHDEFLATED:
408 #endif
409         break;
410       default:
411         err(3, "first entry not deflated or stored--cannot unpack");
412         break;
413     }
414     for (n = SH(h + LOCFIL); n--; ) g = getc(G.in);
415     for (n = SH(h + LOCEXT); n--; ) g = getc(G.in);
416     g = 0;
417     encrypted = h[LOCFLG] & CRPFLG;
418   }
419   else if (n == GZPMAG)
420   {
421     if (fread((char *)h, 1, GZPHDR, G.in) != GZPHDR)
422       err(3, "invalid gzip file");
423     if ((method = h[GZPHOW]) != DEFLATED && method != ENHDEFLATED)
424       err(3, "gzip file not deflated");
425     if (h[GZPFLG] & GZPMUL)
426       err(3, "cannot handle multi-part gzip files");
427     if (h[GZPFLG] & GZPISX)
428     {
429       n = getc(G.in);  n |= getc(G.in) << 8;
430       while (n--) g = getc(G.in);
431     }
432     if (h[GZPFLG] & GZPISF)
433       while ((g = getc(G.in)) != 0 && g != EOF) ;
434     if (h[GZPFLG] & GZPISC)
435       while ((g = getc(G.in)) != 0 && g != EOF) ;
436     g = 1;
437     encrypted = h[GZPFLG] & GZPISE;
438   }
439   else
440     err(3, "input not a zip or gzip file");
441 
442   /* if entry encrypted, decrypt and validate encryption header */
443   if (encrypted)
444 #if CRYPT
445     {
446       ush i, e;
447 
448       if (p == (char *)NULL) {
449         if ((p = (char *)malloc(IZ_PWLEN+1)) == (char *)NULL)
450           err(1, "out of memory");
451         else if ((p = getp("Enter password: ", p, IZ_PWLEN+1)) == (char *)NULL)
452           err(1, "no tty to prompt for password");
453       }
454 #if (defined(USE_ZLIB) && !defined(USE_OWN_CRCTAB))
455       /* initialize crc_32_tab pointer for decryption */
456       CRC_32_TAB = (ZCONST ulg Far *)get_crc_table();
457 #endif
458       init_keys(p);
459       for (i = 0; i < RAND_HEAD_LEN; i++)
460         e = NEXTBYTE;
461       if (e != (ush)(h[LOCFLG] & EXTFLG ? h[LOCTIM + 1] : h[LOCCRC + 3]))
462         err(3, "incorrect password for first entry");
463     }
464 #else /* !CRYPT */
465     err(3, "cannot decrypt entry (need to recompile with full crypt.c)");
466 #endif /* ?CRYPT */
467 
468   /* prepare output buffer and crc */
469   G.outptr = slide;
470   G.outcnt = 0L;
471   outsiz = 0L;
472   G.crc32val = CRCVAL_INITIAL;
473 
474   /* decompress */
475   if (g || h[LOCHOW])
476   {                             /* deflated entry */
477     int r;
478 
479 #ifdef USE_ZLIB
480     /* need to allocate and prepare input buffer */
481     if ((G.inbuf = (uch *)malloc(INBUFSIZ)) == (uch *)NULL)
482        err(1, "out of memory");
483 #endif /* USE_ZLIB */
484     if ((r = UZinflate(__G__ (method == ENHDEFLATED))) != 0) {
485       if (r == 3)
486         err(1, "out of memory");
487       else
488         err(4, "invalid compressed data--format violated");
489     }
490     inflate_free(__G);
491   }
492   else
493   {                             /* stored entry */
494     register ulg n;
495 
496     n = LG(h + LOCLEN);
497 #if CRYPT
498     if (n != LG(h + LOCSIZ) - (encrypted ? RAND_HEAD_LEN : 0)) {
499 #else
500     if (n != LG(h + LOCSIZ)) {
501 #endif
502       Info(slide, 1, ((char *)slide, "len %ld, siz %ld\n", n, LG(h + LOCSIZ)));
503       err(4, "invalid compressed data--length mismatch");
504     }
505     while (n--) {
506       ush c = getc(G.in);
507 #if CRYPT
508       if (encrypted)
509         zdecode(c);
510 #endif
511       *G.outptr++ = (uch)c;
512 #if (defined(USE_DEFLATE64) && defined(__16BIT__))
513       if (++G.outcnt == (WSIZE>>1))     /* do FlushOutput() */
514 #else
515       if (++G.outcnt == WSIZE)    /* do FlushOutput() */
516 #endif
517       {
518         G.crc32val = crc32(G.crc32val, slide, (extent)G.outcnt);
519         if (fwrite((char *)slide, 1,(extent)G.outcnt,out) != (extent)G.outcnt
520             && !PIPE_ERROR)
521           err(9, "out of space on stdout");
522         outsiz += G.outcnt;
523         G.outptr = slide;
524         G.outcnt = 0L;
525       }
526     }
527   }
528   if (G.outcnt)   /* flush one last time; no need to reset G.outptr/outcnt */
529   {
530     G.crc32val = crc32(G.crc32val, slide, (extent)G.outcnt);
531     if (fwrite((char *)slide, 1,(extent)G.outcnt,out) != (extent)G.outcnt
532         && !PIPE_ERROR)
533       err(9, "out of space on stdout");
534     outsiz += G.outcnt;
535   }
536   fflush(out);
537 
538   /* if extended header, get it */
539   if (g)
540   {
541     if (fread((char *)h + LOCCRC, 1, 8, G.in) != 8)
542       err(3, "gzip file ended prematurely");
543   }
544   else
545     if ((h[LOCFLG] & EXTFLG) &&
546         fread((char *)h + LOCCRC - 4, 1, EXTHDR, G.in) != EXTHDR)
547       err(3, "zipfile ended prematurely");
548 
549   /* validate decompression */
550   if (LG(h + LOCCRC) != G.crc32val)
551     err(4, "invalid compressed data--crc error");
552   if (LG((g ? (h + LOCSIZ) : (h + LOCLEN))) != outsiz)
553     err(4, "invalid compressed data--length error");
554 
555   /* check if there are more entries */
556   if (!g && fread((char *)h, 1, 4, G.in) == 4 && LG(h) == LOCSIG)
557     Info(slide, 1, ((char *)slide,
558       "funzip warning: zipfile has more than one entry--rest ignored\n"));
559 
560   DESTROYGLOBALS();
561   RETURN (0);
562 }
563