]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/extra/qe4/lbmlib.c
Merge branch 'master' into divVerent/farplanedist-sky-fix
[xonotic/netradiant.git] / tools / quake2 / extra / qe4 / lbmlib.c
1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4
5 This file is part of Quake 2 Tools source code.
6
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22
23 // lbmlib.c
24
25 #include "cmdlib.h"
26 #include "lbmlib.h"
27
28
29
30 /*
31 ============================================================================
32
33                                                 LBM STUFF
34
35 ============================================================================
36 */
37
38
39 typedef unsigned char   UBYTE;
40 //conflicts with windows typedef short                  WORD;
41 typedef unsigned short  UWORD;
42 typedef long                    LONG;
43
44 typedef enum
45 {
46         ms_none,
47         ms_mask,
48         ms_transcolor,
49         ms_lasso
50 } mask_t;
51
52 typedef enum
53 {
54         cm_none,
55         cm_rle1
56 } compress_t;
57
58 typedef struct
59 {
60         UWORD           w,h;
61         short           x,y;
62         UBYTE           nPlanes;
63         UBYTE           masking;
64         UBYTE           compression;
65         UBYTE           pad1;
66         UWORD           transparentColor;
67         UBYTE           xAspect,yAspect;
68         short           pageWidth,pageHeight;
69 } bmhd_t;
70
71 extern  bmhd_t  bmhd;                                           // will be in native byte order
72
73
74
75 #define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24))
76 #define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24))
77 #define PBMID  ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24))
78 #define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24))
79 #define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24))
80 #define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24))
81
82
83 bmhd_t  bmhd;
84
85 int    Align (int l)
86 {
87         if (l&1)
88                 return l+1;
89         return l;
90 }
91
92
93
94 /*
95 ================
96 LBMRLEdecompress
97
98 Source must be evenly aligned!
99 ================
100 */
101 byte  *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth)
102 {
103         int     count;
104         byte    b,rept;
105
106         count = 0;
107
108         do
109         {
110                 rept = *source++;
111
112                 if (rept > 0x80)
113                 {
114                         rept = (rept^0xff)+2;
115                         b = *source++;
116                         memset(unpacked,b,rept);
117                         unpacked += rept;
118                 }
119                 else if (rept < 0x80)
120                 {
121                         rept++;
122                         memcpy(unpacked,source,rept);
123                         unpacked += rept;
124                         source += rept;
125                 }
126                 else
127                         rept = 0;               // rept of 0x80 is NOP
128
129                 count += rept;
130
131         } while (count<bpwidth);
132
133         if (count>bpwidth)
134                 Error ("Decompression exceeded width!\n");
135
136
137         return source;
138 }
139
140
141 /*
142 =================
143 LoadLBM
144 =================
145 */
146 void LoadLBM (char *filename, byte **picture, byte **palette)
147 {
148         byte    *LBMbuffer, *picbuffer, *cmapbuffer;
149         int             y;
150         byte    *LBM_P, *LBMEND_P;
151         byte    *pic_p;
152         byte    *body_p;
153
154         int    formtype,formlength;
155         int    chunktype,chunklength;
156
157 // qiet compiler warnings
158         picbuffer = NULL;
159         cmapbuffer = NULL;
160
161 //
162 // load the LBM
163 //
164         LoadFile (filename, (void **)&LBMbuffer);
165
166 //
167 // parse the LBM header
168 //
169         LBM_P = LBMbuffer;
170         if ( *(int *)LBMbuffer != LittleLong(FORMID) )
171            Error ("No FORM ID at start of file!\n");
172
173         LBM_P += 4;
174         formlength = BigLong( *(int *)LBM_P );
175         LBM_P += 4;
176         LBMEND_P = LBM_P + Align(formlength);
177
178         formtype = LittleLong(*(int *)LBM_P);
179
180         if (formtype != ILBMID && formtype != PBMID)
181                 Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff
182                 ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff);
183
184         LBM_P += 4;
185
186 //
187 // parse chunks
188 //
189
190         while (LBM_P < LBMEND_P)
191         {
192                 chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24);
193                 LBM_P += 4;
194                 chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24);
195                 LBM_P += 4;
196
197                 switch ( chunktype )
198                 {
199                 case BMHDID:
200                         memcpy (&bmhd,LBM_P,sizeof(bmhd));
201                         bmhd.w = BigShort(bmhd.w);
202                         bmhd.h = BigShort(bmhd.h);
203                         bmhd.x = BigShort(bmhd.x);
204                         bmhd.y = BigShort(bmhd.y);
205                         bmhd.pageWidth = BigShort(bmhd.pageWidth);
206                         bmhd.pageHeight = BigShort(bmhd.pageHeight);
207                         break;
208
209                 case CMAPID:
210                         cmapbuffer = malloc (768);
211                         memset (cmapbuffer, 0, 768);
212                         memcpy (cmapbuffer, LBM_P, chunklength);
213                         break;
214
215                 case BODYID:
216                         body_p = LBM_P;
217
218                         pic_p = picbuffer = malloc (bmhd.w*bmhd.h);
219                         if (formtype == PBMID)
220                         {
221                         //
222                         // unpack PBM
223                         //
224                                 for (y=0 ; y<bmhd.h ; y++, pic_p += bmhd.w)
225                                 {
226                                         if (bmhd.compression == cm_rle1)
227                                                 body_p = LBMRLEDecompress ((byte *)body_p
228                                                 , pic_p , bmhd.w);
229                                         else if (bmhd.compression == cm_none)
230                                         {
231                                                 memcpy (pic_p,body_p,bmhd.w);
232                                                 body_p += Align(bmhd.w);
233                                         }
234                                 }
235
236                         }
237                         else
238                         {
239                         //
240                         // unpack ILBM
241                         //
242                                 Error ("%s is an interlaced LBM, not packed", filename);
243                         }
244                         break;
245                 }
246
247                 LBM_P += Align(chunklength);
248         }
249
250         free (LBMbuffer);
251
252         *picture = picbuffer;
253
254         if (palette)
255                 *palette = cmapbuffer;
256 }
257
258
259 /*
260 ============================================================================
261
262                                                         WRITE LBM
263
264 ============================================================================
265 */
266
267 /*
268 ==============
269 WriteLBMfile
270 ==============
271 */
272 void WriteLBMfile (char *filename, byte *data,
273                                    int width, int height, byte *palette)
274 {
275         byte    *lbm, *lbmptr;
276         int    *formlength, *bmhdlength, *cmaplength, *bodylength;
277         int    length;
278         bmhd_t  basebmhd;
279
280         lbm = lbmptr = malloc (width*height+1000);
281
282 //
283 // start FORM
284 //
285         *lbmptr++ = 'F';
286         *lbmptr++ = 'O';
287         *lbmptr++ = 'R';
288         *lbmptr++ = 'M';
289
290         formlength = (int*)lbmptr;
291         lbmptr+=4;                      // leave space for length
292
293         *lbmptr++ = 'P';
294         *lbmptr++ = 'B';
295         *lbmptr++ = 'M';
296         *lbmptr++ = ' ';
297
298 //
299 // write BMHD
300 //
301         *lbmptr++ = 'B';
302         *lbmptr++ = 'M';
303         *lbmptr++ = 'H';
304         *lbmptr++ = 'D';
305
306         bmhdlength = (int *)lbmptr;
307         lbmptr+=4;                      // leave space for length
308
309         memset (&basebmhd,0,sizeof(basebmhd));
310         basebmhd.w = BigShort((short)width);
311         basebmhd.h = BigShort((short)height);
312         basebmhd.nPlanes = 8;
313         basebmhd.xAspect = 5;
314         basebmhd.yAspect = 6;
315         basebmhd.pageWidth = BigShort((short)width);
316         basebmhd.pageHeight = BigShort((short)height);
317
318         memcpy (lbmptr,&basebmhd,sizeof(basebmhd));
319         lbmptr += sizeof(basebmhd);
320
321         length = lbmptr-(byte *)bmhdlength-4;
322         *bmhdlength = BigLong(length);
323         if (length&1)
324                 *lbmptr++ = 0;          // pad chunk to even offset
325
326 //
327 // write CMAP
328 //
329         *lbmptr++ = 'C';
330         *lbmptr++ = 'M';
331         *lbmptr++ = 'A';
332         *lbmptr++ = 'P';
333
334         cmaplength = (int *)lbmptr;
335         lbmptr+=4;                      // leave space for length
336
337         memcpy (lbmptr,palette,768);
338         lbmptr += 768;
339
340         length = lbmptr-(byte *)cmaplength-4;
341         *cmaplength = BigLong(length);
342         if (length&1)
343                 *lbmptr++ = 0;          // pad chunk to even offset
344
345 //
346 // write BODY
347 //
348         *lbmptr++ = 'B';
349         *lbmptr++ = 'O';
350         *lbmptr++ = 'D';
351         *lbmptr++ = 'Y';
352
353         bodylength = (int *)lbmptr;
354         lbmptr+=4;                      // leave space for length
355
356         memcpy (lbmptr,data,width*height);
357         lbmptr += width*height;
358
359         length = lbmptr-(byte *)bodylength-4;
360         *bodylength = BigLong(length);
361         if (length&1)
362                 *lbmptr++ = 0;          // pad chunk to even offset
363
364 //
365 // done
366 //
367         length = lbmptr-(byte *)formlength-4;
368         *formlength = BigLong(length);
369         if (length&1)
370                 *lbmptr++ = 0;          // pad chunk to even offset
371
372 //
373 // write output file
374 //
375         SaveFile (filename, lbm, lbmptr-lbm);
376         free (lbm);
377 }
378
379
380 /*
381 ============================================================================
382
383 LOAD PCX
384
385 ============================================================================
386 */
387
388 typedef struct
389 {
390     char        manufacturer;
391     char        version;
392     char        encoding;
393     char        bits_per_pixel;
394     unsigned short      xmin,ymin,xmax,ymax;
395     unsigned short      hres,vres;
396     unsigned char       palette[48];
397     char        reserved;
398     char        color_planes;
399     unsigned short      bytes_per_line;
400     unsigned short      palette_type;
401     char        filler[58];
402     unsigned char       data;                   // unbounded
403 } pcx_t;
404
405
406 /*
407 ==============
408 LoadPCX
409 ==============
410 */
411 void LoadPCX (char *filename, byte **pic, byte **palette, int *width, int *height)
412 {
413         byte    *raw;
414         pcx_t   *pcx;
415         int             x, y;
416         int             len;
417         int             dataByte, runLength;
418         byte    *out, *pix;
419
420         if (pic)
421                 *pic = NULL;
422         if (palette)
423                 *palette = NULL;
424         if (width)
425                 *width = 0;
426         if (height)
427                 *height = 0;
428
429         //
430         // load the file
431         //
432         len = LoadFile (filename, (void **)&raw);
433         if (len == -1)
434                 return;
435
436         //
437         // parse the PCX file
438         //
439         pcx = (pcx_t *)raw;
440         raw = &pcx->data;
441
442         pcx->xmin = LittleShort(pcx->xmin);
443         pcx->ymin = LittleShort(pcx->ymin);
444         pcx->xmax = LittleShort(pcx->xmax);
445         pcx->ymax = LittleShort(pcx->ymax);
446         pcx->hres = LittleShort(pcx->hres);
447         pcx->vres = LittleShort(pcx->vres);
448         pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
449         pcx->palette_type = LittleShort(pcx->palette_type);
450
451         if (pcx->manufacturer != 0x0a
452                 || pcx->version != 5
453                 || pcx->encoding != 1
454                 || pcx->bits_per_pixel != 8
455                 || pcx->xmax >= 640
456                 || pcx->ymax >= 480)
457                 Error ("Bad pcx file %s", filename);
458
459         if (palette)
460         {
461                 *palette = malloc(768);
462                 memcpy (*palette, (byte *)pcx + len - 768, 768);
463         }
464
465         if (width)
466                 *width = pcx->xmax+1;
467         if (height)
468                 *height = pcx->ymax+1;
469
470         if (!pic)
471                 return;
472
473         out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
474         if (!out)
475                 Error ("Skin_Cache: couldn't allocate");
476
477         *pic = out;
478
479         pix = out;
480
481         for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1)
482         {
483                 for (x=0 ; x<=pcx->xmax ; )
484                 {
485                         dataByte = *raw++;
486
487                         if((dataByte & 0xC0) == 0xC0)
488                         {
489                                 runLength = dataByte & 0x3F;
490                                 dataByte = *raw++;
491                         }
492                         else
493                                 runLength = 1;
494
495                         while(runLength-- > 0)
496                                 pix[x++] = dataByte;
497                 }
498
499         }
500
501         if ( raw - (byte *)pcx > len)
502                 Error ("PCX file %s was malformed", filename);
503
504         free (pcx);
505 }
506
507 /*
508 ==============
509 WritePCXfile
510 ==============
511 */
512 void WritePCXfile (char *filename, byte *data,
513                                    int width, int height, byte *palette)
514 {
515         int             i, j, length;
516         pcx_t   *pcx;
517         byte            *pack;
518
519         pcx = malloc (width*height*2+1000);
520         memset (pcx, 0, sizeof(*pcx));
521
522         pcx->manufacturer = 0x0a;       // PCX id
523         pcx->version = 5;                       // 256 color
524         pcx->encoding = 1;              // uncompressed
525         pcx->bits_per_pixel = 8;                // 256 color
526         pcx->xmin = 0;
527         pcx->ymin = 0;
528         pcx->xmax = LittleShort((short)(width-1));
529         pcx->ymax = LittleShort((short)(height-1));
530         pcx->hres = LittleShort((short)width);
531         pcx->vres = LittleShort((short)height);
532         pcx->color_planes = 1;          // chunky image
533         pcx->bytes_per_line = LittleShort((short)width);
534         pcx->palette_type = LittleShort(2);             // not a grey scale
535
536         // pack the image
537         pack = &pcx->data;
538
539         for (i=0 ; i<height ; i++)
540         {
541                 for (j=0 ; j<width ; j++)
542                 {
543                         if ( (*data & 0xc0) != 0xc0)
544                                 *pack++ = *data++;
545                         else
546                         {
547                                 *pack++ = 0xc1;
548                                 *pack++ = *data++;
549                         }
550                 }
551         }
552
553         // write the palette
554         *pack++ = 0x0c; // palette ID byte
555         for (i=0 ; i<768 ; i++)
556                 *pack++ = *palette++;
557
558 // write output file
559         length = pack - (byte *)pcx;
560         SaveFile (filename, pcx, length);
561
562         free (pcx);
563 }
564
565
566 /*
567 ============================================================================
568
569 LOAD IMAGE
570
571 ============================================================================
572 */
573
574 /*
575 ==============
576 Load256Image
577
578 Will load either an lbm or pcx, depending on extension.
579 Any of the return pointers can be NULL if you don't want them.
580 ==============
581 */
582 void Load256Image (char *name, byte **pixels, byte **palette,
583                                    int *width, int *height)
584 {
585         char    ext[128];
586
587         ExtractFileExtension (name, ext);
588         if (!Q_strcasecmp (ext, "lbm"))
589         {
590                 LoadLBM (name, pixels, palette);
591                 if (width)
592                         *width = bmhd.w;
593                 if (height)
594                         *height = bmhd.h;
595         }
596         else if (!Q_strcasecmp (ext, "pcx"))
597         {
598                 LoadPCX (name, pixels, palette, width, height);
599         }
600         else
601                 Error ("%s doesn't have a known image extension", name);
602 }
603
604
605 /*
606 ==============
607 Save256Image
608
609 Will save either an lbm or pcx, depending on extension.
610 ==============
611 */
612 void Save256Image (char *name, byte *pixels, byte *palette,
613                                    int width, int height)
614 {
615         char    ext[128];
616
617         ExtractFileExtension (name, ext);
618         if (!Q_strcasecmp (ext, "lbm"))
619         {
620                 WriteLBMfile (name, pixels, width, height, palette);
621         }
622         else if (!Q_strcasecmp (ext, "pcx"))
623         {
624                 WritePCXfile (name, pixels, width, height, palette);
625         }
626         else
627                 Error ("%s doesn't have a known image extension", name);
628 }
629
630
631
632
633 /*
634 ============================================================================
635
636 TARGA IMAGE
637
638 ============================================================================
639 */
640
641 typedef struct _TargaHeader {
642         unsigned char   id_length, colormap_type, image_type;
643         unsigned short  colormap_index, colormap_length;
644         unsigned char   colormap_size;
645         unsigned short  x_origin, y_origin, width, height;
646         unsigned char   pixel_size, attributes;
647 } TargaHeader;
648
649 int fgetLittleShort (FILE *f)
650 {
651         byte    b1, b2;
652
653         b1 = fgetc(f);
654         b2 = fgetc(f);
655
656         return (short)(b1 + b2*256);
657 }
658
659 int fgetLittleLong (FILE *f)
660 {
661         byte    b1, b2, b3, b4;
662
663         b1 = fgetc(f);
664         b2 = fgetc(f);
665         b3 = fgetc(f);
666         b4 = fgetc(f);
667
668         return b1 + (b2<<8) + (b3<<16) + (b4<<24);
669 }
670
671
672 /*
673 =============
674 LoadTGA
675 =============
676 */
677 void LoadTGA (char *name, byte **pixels, int *width, int *height)
678 {
679         int                             columns, rows, numPixels;
680         byte                    *pixbuf;
681         int                             row, column;
682         FILE                    *fin;
683         byte                    *targa_rgba;
684         TargaHeader             targa_header;
685
686         fin = fopen (name, "rb");
687         if (!fin)
688                 Error ("Couldn't read %s", name);
689
690         targa_header.id_length = fgetc(fin);
691         targa_header.colormap_type = fgetc(fin);
692         targa_header.image_type = fgetc(fin);
693
694         targa_header.colormap_index = fgetLittleShort(fin);
695         targa_header.colormap_length = fgetLittleShort(fin);
696         targa_header.colormap_size = fgetc(fin);
697         targa_header.x_origin = fgetLittleShort(fin);
698         targa_header.y_origin = fgetLittleShort(fin);
699         targa_header.width = fgetLittleShort(fin);
700         targa_header.height = fgetLittleShort(fin);
701         targa_header.pixel_size = fgetc(fin);
702         targa_header.attributes = fgetc(fin);
703
704         if (targa_header.image_type!=2
705                 && targa_header.image_type!=10)
706                 Error ("LoadTGA: Only type 2 and 10 targa RGB images supported\n");
707
708         if (targa_header.colormap_type !=0
709                 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))
710                 Error ("Texture_LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
711
712         columns = targa_header.width;
713         rows = targa_header.height;
714         numPixels = columns * rows;
715
716         if (width)
717                 *width = columns;
718         if (height)
719                 *height = rows;
720         targa_rgba = malloc(numPixels*4);
721         *pixels = targa_rgba;
722
723         if (targa_header.id_length != 0)
724                 fseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment
725
726         if (targa_header.image_type==2) {  // Uncompressed, RGB images
727                 for(row=rows-1; row>=0; row--) {
728                         pixbuf = targa_rgba + row*columns*4;
729                         for(column=0; column<columns; column++) {
730                                 unsigned char red,green,blue,alphabyte;
731                                 switch (targa_header.pixel_size) {
732                                         case 24:
733
734                                                         blue = getc(fin);
735                                                         green = getc(fin);
736                                                         red = getc(fin);
737                                                         *pixbuf++ = red;
738                                                         *pixbuf++ = green;
739                                                         *pixbuf++ = blue;
740                                                         *pixbuf++ = 255;
741                                                         break;
742                                         case 32:
743                                                         blue = getc(fin);
744                                                         green = getc(fin);
745                                                         red = getc(fin);
746                                                         alphabyte = getc(fin);
747                                                         *pixbuf++ = red;
748                                                         *pixbuf++ = green;
749                                                         *pixbuf++ = blue;
750                                                         *pixbuf++ = alphabyte;
751                                                         break;
752                                 }
753                         }
754                 }
755         }
756         else if (targa_header.image_type==10) {   // Runlength encoded RGB images
757                 unsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;
758                 for(row=rows-1; row>=0; row--) {
759                         pixbuf = targa_rgba + row*columns*4;
760                         for(column=0; column<columns; ) {
761                                 packetHeader=getc(fin);
762                                 packetSize = 1 + (packetHeader & 0x7f);
763                                 if (packetHeader & 0x80) {        // run-length packet
764                                         switch (targa_header.pixel_size) {
765                                                 case 24:
766                                                                 blue = getc(fin);
767                                                                 green = getc(fin);
768                                                                 red = getc(fin);
769                                                                 alphabyte = 255;
770                                                                 break;
771                                                 case 32:
772                                                                 blue = getc(fin);
773                                                                 green = getc(fin);
774                                                                 red = getc(fin);
775                                                                 alphabyte = getc(fin);
776                                                                 break;
777                                         }
778
779                                         for(j=0;j<packetSize;j++) {
780                                                 *pixbuf++=red;
781                                                 *pixbuf++=green;
782                                                 *pixbuf++=blue;
783                                                 *pixbuf++=alphabyte;
784                                                 column++;
785                                                 if (column==columns) { // run spans across rows
786                                                         column=0;
787                                                         if (row>0)
788                                                                 row--;
789                                                         else
790                                                                 goto breakOut;
791                                                         pixbuf = targa_rgba + row*columns*4;
792                                                 }
793                                         }
794                                 }
795                                 else {                            // non run-length packet
796                                         for(j=0;j<packetSize;j++) {
797                                                 switch (targa_header.pixel_size) {
798                                                         case 24:
799                                                                         blue = getc(fin);
800                                                                         green = getc(fin);
801                                                                         red = getc(fin);
802                                                                         *pixbuf++ = red;
803                                                                         *pixbuf++ = green;
804                                                                         *pixbuf++ = blue;
805                                                                         *pixbuf++ = 255;
806                                                                         break;
807                                                         case 32:
808                                                                         blue = getc(fin);
809                                                                         green = getc(fin);
810                                                                         red = getc(fin);
811                                                                         alphabyte = getc(fin);
812                                                                         *pixbuf++ = red;
813                                                                         *pixbuf++ = green;
814                                                                         *pixbuf++ = blue;
815                                                                         *pixbuf++ = alphabyte;
816                                                                         break;
817                                                 }
818                                                 column++;
819                                                 if (column==columns) { // pixel packet run spans across rows
820                                                         column=0;
821                                                         if (row>0)
822                                                                 row--;
823                                                         else
824                                                                 goto breakOut;
825                                                         pixbuf = targa_rgba + row*columns*4;
826                                                 }
827                                         }
828                                 }
829                         }
830                         breakOut:;
831                 }
832         }
833
834         fclose(fin);
835 }