1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /*  Grafx2 - The Ultimate 256-color bitmap paint program
4 
5 	Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6 
7     Grafx2 is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; version 2
10     of the License.
11 
12     Grafx2 is distributed in the hope that it will be useful,
13     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 Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 
21 ///@file miscfileformats.c
22 /// Formats that aren't fully saving, either because of palette restrictions or other things
23 
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #ifdef _MSC_VER
29 #include <stdio.h>
30 #if _MSC_VER < 1900
31 #define snprintf _snprintf
32 #endif
33 #define strdup _strdup
34 #endif
35 
36 #include "global.h"
37 #include "io.h"
38 #include "loadsave.h"
39 #include "loadsavefuncs.h"
40 #include "misc.h"
41 #include "struct.h"
42 #include "windows.h"
43 #include "oldies.h"
44 #include "fileformats.h"
45 #include "gfx2mem.h"
46 #include "gfx2log.h"
47 
48 //////////////////////////////////// PAL ////////////////////////////////////
49 //
50 
51 // -- Test wether a file is in PAL format --------------------------------
Test_PAL(T_IO_Context * context,FILE * file)52 void Test_PAL(T_IO_Context * context, FILE * file)
53 {
54   char buffer[32];
55   long file_size;
56 
57   (void)context;
58   File_error = 1;
59 
60   file_size = File_length_file(file);
61   // First check for GrafX2 legacy palette format. The simplest one, 768 bytes
62   // of RGB data. It is a raw dump of the T_Palette structure. There is no
63   // header at all, so we check for the file size.
64   if (file_size == sizeof(T_Palette))
65     File_error = 0;
66   else if (file_size > 8)
67   {
68     // Bigger (or smaller ?) files may be in other formats. These have an
69     // header, so look for it.
70     if (!Read_bytes(file, buffer, 8))
71       return;
72     if (strncmp(buffer,"JASC-PAL",8) == 0)
73     {
74       // JASC file format, used by Paint Shop Pro and GIMP. This is also the
75       // one used for saving, as it brings greater interoperability.
76       File_error = 0;
77     }
78     else if(strncmp(buffer,"RIFF", 4) == 0)
79     {
80       // Microsoft RIFF file
81       // This is a data container (similar to IFF). We only check the first
82       // chunk header, and give up if that's not a palette.
83       fseek(file, 8, SEEK_SET);
84       if (!Read_bytes(file, buffer, 8))
85         return;
86       if (strncmp(buffer, "PAL data", 8) == 0)
87       {
88         File_error = 0;
89       }
90     }
91   }
92 }
93 
94 /// Test for GPL (Gimp Palette) file format
Test_GPL(T_IO_Context * context,FILE * file)95 void Test_GPL(T_IO_Context * context, FILE * file)
96 {
97   char buffer[16];
98   long file_size;
99 
100   (void)context;
101   File_error = 1;
102 
103   file_size = File_length_file(file);
104   if (file_size > 33) {
105     // minimum header length == 33
106     // "GIMP Palette" == 12
107     if (!Read_bytes(file, buffer, 12))
108       return;
109     if (strncmp(buffer,"GIMP Palette",12) == 0)
110       File_error = 0;
111   }
112 }
113 
114 /// skip the padding before a space-padded field.
skip_padding(FILE * file,int max_chars)115 static int skip_padding(FILE *file, int max_chars)
116 {
117   byte b;
118   int chars_read = 0;
119 
120   do {
121     if (chars_read == max_chars)
122       return chars_read; // eof
123     if (!Read_byte(file, &b))
124       return chars_read;
125     chars_read++;
126   } while (b == ' ');
127 
128   fseek(file, -1, SEEK_CUR);
129   return chars_read;
130 }
131 
132 /// Load GPL (Gimp Palette) file format
Load_GPL(T_IO_Context * context)133 void Load_GPL(T_IO_Context * context)
134 {
135   FILE *file;
136   char buffer[256];
137 
138   File_error = 1;
139 
140   file = Open_file_read(context);
141   if (file == NULL)
142     return;
143 
144   if (!Read_byte_line(file, buffer, sizeof(buffer)))
145     return;
146 
147   if (memcmp(buffer,"GIMP Palette",12) == 0)
148   {
149     int i, r, g, b, columns;
150     size_t len;
151     // Name: xxxxx
152     if (!Read_byte_line(file, buffer, sizeof(buffer)))
153       return;
154     len = strlen(buffer);
155     while (len > 0)
156     {
157       len--;
158       if (buffer[len] == '\r' || buffer[len] == '\n')
159         buffer[len] = '\0';
160     }
161     GFX2_Log(GFX2_DEBUG, "GPL %s\n", buffer);
162     if (0 == memcmp(buffer, "Name: ", 6))
163       snprintf(context->Comment, sizeof(context->Comment), "GPL: %s", buffer + 6);
164 
165     // Columns: 16
166     if (fscanf(file, "Columns: %d", &columns) != 1)
167       return;
168     Read_byte_line(file, buffer, sizeof(buffer));
169     /// @todo set grafx2 columns setting to match.
170     // #<newline>
171 
172     for (i = 0; i < 256; i++)
173     {
174       for (;;)
175       {
176         // skip comments
177         int c = getc(file);
178         if (c == '#')
179         {
180           if (!Read_byte_line(file, buffer, sizeof(buffer)))
181             return;
182           GFX2_Log(GFX2_DEBUG, "comment: %s", buffer);
183         }
184         else
185         {
186           fseek(file, -1, SEEK_CUR);
187           break;
188         }
189       }
190       skip_padding(file, 32);
191       if (fscanf(file, "%d", &r) != 1)
192         break;
193       skip_padding(file, 32);
194       if (fscanf(file, "%d", &g) != 1)
195         break;
196       skip_padding(file, 32);
197       if (fscanf(file, "%d\t", &b) != 1)
198         break;
199       if (!Read_byte_line(file, buffer, sizeof(buffer)))
200         break;
201       len = strlen(buffer);
202       while (len > 1)
203       {
204         len--;
205         if (buffer[len] == '\r' || buffer[len] == '\n')
206           buffer[len] = '\0';
207       }
208       /// @todo analyze color names to build shade table
209 
210       GFX2_Log(GFX2_DEBUG, "GPL: %3d: RGB(%3d,%3d,%3d) %s\n", i, r,g,b, buffer);
211       context->Palette[i].R = r;
212       context->Palette[i].G = g;
213       context->Palette[i].B = b;
214     }
215     if (i > 0)  // at least one color was read
216       File_error = 0;
217   }
218   else
219     File_error = 2;
220 
221   // close the file
222   fclose(file);
223 }
224 
225 
226 /// Save GPL (Gimp Palette) file format
227 void
Save_GPL(T_IO_Context * context)228 Save_GPL (T_IO_Context * context)
229 {
230   // Gimp is a unix program, so use Unix file endings (LF aka '\n')
231   FILE *file;
232 
233   file = Open_file_write(context);
234 
235   if (file != NULL )
236   {
237     int i;
238 
239     File_error = 0;
240     fprintf (file, "GIMP Palette\n");
241     fprintf (file, "Name: %s\n", context->File_name);
242     // TODO: use actual columns value
243     fprintf (file, "Columns: %d\n#\n", 16);
244 
245     for (i = 0; i < 256 && File_error==0; i++)
246     {
247       // TODO: build names from shade table data
248       if (fprintf(file,"%d %d %d\tUntitled\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0)
249         File_error=1;
250     }
251     fclose(file);
252 
253     if (File_error)
254       Remove_file(context);
255   }
256   else
257   {
258     // unable to open output file, nothing saved.
259     File_error=1;
260   }
261 }
262 
263 
264 
265 // -- Lire un fichier au format PAL -----------------------------------------
Load_PAL(T_IO_Context * context)266 void Load_PAL(T_IO_Context * context)
267 {
268   FILE *file;              // Fichier du fichier
269 
270   File_error=0;
271 
272   // Ouverture du fichier
273   if ((file=Open_file_read(context)))
274   {
275     long file_size = File_length_file(file);
276     // Le fichier ne peut être au format PAL que si sa taille vaut 768 octets
277     if (file_size == sizeof(T_Palette))
278     {
279       T_Palette palette_64;
280       // Pre_load(context, ?); // Pas possible... pas d'image...
281 
282       // Lecture du fichier dans context->Palette
283       if (Read_bytes(file, palette_64, sizeof(T_Palette)))
284       {
285         Palette_64_to_256(palette_64);
286         memcpy(context->Palette, palette_64, sizeof(T_Palette));
287       }
288       else
289         File_error = 2;
290     } else {
291       char buffer[16];
292       if (!Read_bytes(file, buffer, 8))
293       {
294         File_error = 2;
295         fclose(file);
296         return;
297       }
298       buffer[8] = '\0';
299       if (strncmp(buffer,"JASC-PAL",8) == 0)
300       {
301         int i, n, r, g, b;
302         i = fscanf(file, "%d",&n);
303         if(i != 1 || n != 100)
304         {
305           File_error = 2;
306           fclose(file);
307           return;
308         }
309         // Read color count
310         if (fscanf(file, "%d",&n) == 1)
311         {
312           for (i = 0; i < n; i++)
313           {
314             if (fscanf(file, "%d %d %d",&r, &g, &b) == 3)
315             {
316               context->Palette[i].R = r;
317               context->Palette[i].G = g;
318               context->Palette[i].B = b;
319             }
320             else
321               File_error = 2;
322           }
323         }
324         else
325           File_error = 2;
326       }
327       else if(strncmp(buffer, "RIFF", 4) == 0)
328       {
329         // Microsoft RIFF format.
330         fseek(file, 8, SEEK_SET);
331         Read_bytes(file, buffer, 8);
332         if (strncmp(buffer, "PAL data", 8) == 0)
333         {
334           word color_count;
335           word i = 0;
336 
337           fseek(file, 22, SEEK_SET);
338           if (!Read_word_le(file, &color_count))
339             File_error = 2;
340           else
341             for(i = 0; i < color_count && File_error == 0; i++)
342             {
343               byte colors[4];
344               if (!Read_bytes(file, colors, 4))
345                 File_error = 2;
346               context->Palette[i].R = colors[0];
347               context->Palette[i].G = colors[1];
348               context->Palette[i].B = colors[2];
349             }
350         } else File_error = 2;
351       } else
352         File_error = 2;
353     }
354 
355     fclose(file);
356   }
357   else
358     // Si on n'a pas réussi à ouvrir le fichier, alors il y a eu une erreur
359     File_error=1;
360 }
361 
362 
363 // -- Sauver un fichier au format PAL ---------------------------------------
Save_PAL(T_IO_Context * context)364 void Save_PAL(T_IO_Context * context)
365 {
366   // JASC-PAL is a DOS/Windows format, so use CRLF line endings "\r\n"
367   FILE *file;
368 
369   File_error=0;
370 
371   // Open output file
372   if ((file=Open_file_write(context)) != NULL)
373   {
374     int i;
375 
376     setvbuf(file, NULL, _IOFBF, 64*1024);
377 
378     if (fputs("JASC-PAL\r\n0100\r\n256\r\n", file)==EOF)
379       File_error=1;
380     for (i = 0; i < 256 && File_error==0; i++)
381     {
382       if (fprintf(file,"%d %d %d\r\n",context->Palette[i].R, context->Palette[i].G, context->Palette[i].B) <= 0)
383         File_error=1;
384     }
385 
386     fclose(file);
387 
388     if (File_error)
389       Remove_file(context);
390   }
391   else
392   {
393     // unable to open output file, nothing saved.
394     File_error=1;
395   }
396 }
397 
398 
399 //////////////////////////////////// PKM ////////////////////////////////////
400 typedef struct
401 {
402   char Ident[3];    // String "PKM" }
403   byte Method;      // Compression method
404                     //   0 = per-line compression (c)KM
405                     //   others = unknown at the moment
406   byte Recog1;      // Recognition byte 1
407   byte Recog2;      // Recognition byte 2
408   word Width;       // Image width
409   word Height;      // Image height
410   T_Palette Palette;// RGB Palette 256*3, on a 1-64 scale for each component
411   word Jump;        // Size of the jump between header and image:
412                     //   Used to insert a comment
413 } T_PKM_Header;
414 
415 // -- Tester si un fichier est au format PKM --------------------------------
Test_PKM(T_IO_Context * context,FILE * file)416 void Test_PKM(T_IO_Context * context, FILE * file)
417 {
418   T_PKM_Header header;
419 
420   (void)context;
421   File_error=1;
422 
423   // Lecture du header du fichier
424   if (Read_bytes(file,&header.Ident,3) &&
425       Read_byte(file,&header.Method) &&
426       Read_byte(file,&header.Recog1) &&
427       Read_byte(file,&header.Recog2) &&
428       Read_word_le(file,&header.Width) &&
429       Read_word_le(file,&header.Height) &&
430       Read_bytes(file,&header.Palette,sizeof(T_Palette)) &&
431       Read_word_le(file,&header.Jump))
432   {
433     // On regarde s'il y a la signature PKM suivie de la méthode 0.
434     // La constante "PKM" étant un chaîne, elle se termine toujours par 0.
435     // Donc pas la peine de s'emm...er à regarder si la méthode est à 0.
436     if ( (!memcmp(&header,"PKM",4)) && header.Width && header.Height)
437       File_error=0;
438   }
439 }
440 
441 
442 // -- Lire un fichier au format PKM -----------------------------------------
Load_PKM(T_IO_Context * context)443 void Load_PKM(T_IO_Context * context)
444 {
445   FILE *file;             // Fichier du fichier
446   T_PKM_Header header;
447   byte  color;
448   byte  temp_byte;
449   word  len;
450   word  index;
451   dword Compteur_de_pixels;
452   dword Compteur_de_donnees_packees;
453   dword image_size;
454   dword Taille_pack;
455   long  file_size;
456 
457   File_error=0;
458 
459   if ((file=Open_file_read(context)))
460   {
461     file_size=File_length_file(file);
462 
463     if (Read_bytes(file,&header.Ident,3) &&
464         Read_byte(file,&header.Method) &&
465         Read_byte(file,&header.Recog1) &&
466         Read_byte(file,&header.Recog2) &&
467         Read_word_le(file,&header.Width) &&
468         Read_word_le(file,&header.Height) &&
469         Read_bytes(file,&header.Palette,sizeof(T_Palette)) &&
470         Read_word_le(file,&header.Jump))
471     {
472       context->Comment[0]='\0'; // On efface le commentaire
473       if (header.Jump)
474       {
475         index=0;
476         while ( (index<header.Jump) && (!File_error) )
477         {
478           if (Read_byte(file,&temp_byte))
479           {
480             index+=2; // On rajoute le "Field-id" et "le Field-size" pas encore lu
481             switch (temp_byte)
482             {
483               case 0 : // Commentaire
484                 if (Read_byte(file,&temp_byte))
485                 {
486                   if (temp_byte>COMMENT_SIZE)
487                   {
488                     color=temp_byte;              // On se sert de color comme
489                     temp_byte=COMMENT_SIZE;   // variable temporaire
490                     color-=COMMENT_SIZE;
491                   }
492                   else
493                     color=0;
494 
495                   if (Read_bytes(file,context->Comment,temp_byte))
496                   {
497                     index+=temp_byte;
498                     context->Comment[temp_byte]='\0';
499                     if (color)
500                       if (fseek(file,color,SEEK_CUR))
501                         File_error=2;
502                   }
503                   else
504                     File_error=2;
505                 }
506                 else
507                   File_error=2;
508                 break;
509 
510               case 1 : // Dimensions de l'écran d'origine
511                 if (Read_byte(file,&temp_byte))
512                 {
513                   if (temp_byte==4)
514                   {
515                     index+=4;
516                     if ( ! Read_word_le(file,(word *) &Original_screen_X)
517                       || !Read_word_le(file,(word *) &Original_screen_Y) )
518                       File_error=2;
519                     else
520                       GFX2_Log(GFX2_DEBUG, "PKM original screen %dx%d\n", (int)Original_screen_X, (int)Original_screen_Y);
521                   }
522                   else
523                     File_error=2;
524                 }
525                 else
526                   File_error=2;
527                 break;
528 
529               case 2 : // color de transparence
530                 if (Read_byte(file,&temp_byte))
531                 {
532                   if (temp_byte==1)
533                   {
534                     index++;
535                     if (! Read_byte(file,&Back_color))
536                       File_error=2;
537                   }
538                   else
539                     File_error=2;
540                 }
541                 else
542                   File_error=2;
543                 break;
544 
545               default:
546                 if (Read_byte(file,&temp_byte))
547                 {
548                   index+=temp_byte;
549                   if (fseek(file,temp_byte,SEEK_CUR))
550                     File_error=2;
551                 }
552                 else
553                   File_error=2;
554             }
555           }
556           else
557             File_error=2;
558         }
559         if ( (!File_error) && (index!=header.Jump) )
560           File_error=2;
561       }
562 
563       /*Init_lecture();*/
564 
565       if (!File_error)
566       {
567         Pre_load(context, header.Width,header.Height,file_size,FORMAT_PKM,PIXEL_SIMPLE,0);
568         if (File_error==0)
569         {
570 
571           image_size=(dword)(context->Width*context->Height);
572           // Palette lue en 64
573           memcpy(context->Palette,header.Palette,sizeof(T_Palette));
574           Palette_64_to_256(context->Palette);
575 
576           Compteur_de_donnees_packees=0;
577           Compteur_de_pixels=0;
578           // Header size is 780
579           Taille_pack=(file_size)-780-header.Jump;
580 
581           // Boucle de décompression:
582           while ( (Compteur_de_pixels<image_size) && (Compteur_de_donnees_packees<Taille_pack) && (!File_error) )
583           {
584             if(Read_byte(file, &temp_byte)!=1)
585             {
586               File_error=2;
587               break;
588             }
589 
590             // Si ce n'est pas un octet de reconnaissance, c'est un pixel brut
591             if ( (temp_byte!=header.Recog1) && (temp_byte!=header.Recog2) )
592             {
593               Set_pixel(context, Compteur_de_pixels % context->Width,
594                                   Compteur_de_pixels / context->Width,
595                                   temp_byte);
596               Compteur_de_donnees_packees++;
597               Compteur_de_pixels++;
598             }
599             else // Sinon, On regarde si on va décompacter un...
600             { // ... nombre de pixels tenant sur un byte
601                 if (temp_byte==header.Recog1)
602                 {
603                   if(Read_byte(file, &color)!=1)
604                 {
605                     File_error=2;
606                     break;
607                 }
608                 if(Read_byte(file, &temp_byte)!=1)
609                 {
610                     File_error=2;
611                     break;
612                 }
613                 for (index=0; index<temp_byte; index++)
614                   Set_pixel(context, (Compteur_de_pixels+index) % context->Width,
615                                       (Compteur_de_pixels+index) / context->Width,
616                                       color);
617                 Compteur_de_pixels+=temp_byte;
618                 Compteur_de_donnees_packees+=3;
619               }
620               else // ... nombre de pixels tenant sur un word
621               {
622                 if(Read_byte(file, &color)!=1)
623                 {
624                     File_error=2;
625                     break;
626         }
627                 Read_word_be(file, &len);
628                 for (index=0; index<len; index++)
629                   Set_pixel(context, (Compteur_de_pixels+index) % context->Width,
630                                       (Compteur_de_pixels+index) / context->Width,
631                                       color);
632                 Compteur_de_pixels+=len;
633                 Compteur_de_donnees_packees+=4;
634               }
635             }
636           }
637         }
638       }
639       /*Close_lecture();*/
640     }
641     else // Lecture header impossible: Error ne modifiant pas l'image
642       File_error=1;
643 
644     fclose(file);
645   }
646   else // Ouv. fichier impossible: Error ne modifiant pas l'image
647     File_error=1;
648 }
649 
650 
651 // -- Sauver un fichier au format PKM ---------------------------------------
652 
653   // Trouver quels sont les octets de reconnaissance
Find_recog(byte * recog1,byte * recog2)654   void Find_recog(byte * recog1, byte * recog2)
655   {
656     dword Find_recon[256]; // Table d'utilisation de couleurs
657     byte  best;   // Meilleure couleur pour recon (recon1 puis recon2)
658     dword NBest;  // Nombre d'occurences de cette couleur
659     word  index;
660 
661 
662     // On commence par compter l'utilisation de chaque couleurs
663     Count_used_colors(Find_recon);
664 
665     // Ensuite recog1 devient celle la moins utilisée de celles-ci
666     *recog1=0;
667     best=1;
668     NBest=INT_MAX; // Une même couleur ne pourra jamais être utilisée 1M de fois.
669     for (index=1;index<=255;index++)
670       if (Find_recon[index]<NBest)
671       {
672         best=index;
673         NBest=Find_recon[index];
674       }
675     *recog1=best;
676 
677     // Enfin recog2 devient la 2ème moins utilisée
678     *recog2=0;
679     best=0;
680     NBest=INT_MAX;
681     for (index=0;index<=255;index++)
682       if ( (Find_recon[index]<NBest) && (index!=*recog1) )
683       {
684         best=index;
685         NBest=Find_recon[index];
686       }
687     *recog2=best;
688   }
689 
690 
Save_PKM(T_IO_Context * context)691 void Save_PKM(T_IO_Context * context)
692 {
693   FILE *file;
694   T_PKM_Header header;
695   dword Compteur_de_pixels;
696   dword image_size;
697   word  repetitions;
698   byte  last_color;
699   byte  pixel_value;
700   size_t comment_size;
701 
702 
703 
704   // Construction du header
705   memcpy(header.Ident,"PKM",3);
706   header.Method=0;
707   Find_recog(&header.Recog1,&header.Recog2);
708   header.Width=context->Width;
709   header.Height=context->Height;
710   memcpy(header.Palette,context->Palette,sizeof(T_Palette));
711   Palette_256_to_64(header.Palette);
712 
713   // Calcul de la taille du Post-header
714   header.Jump=9; // 6 pour les dimensions de l'ecran + 3 pour la back-color
715   comment_size=strlen(context->Comment);
716   if (comment_size > 255) comment_size = 255;
717   if (comment_size)
718     header.Jump+=(word)comment_size+2;
719 
720 
721   File_error=0;
722 
723   // Ouverture du fichier
724   if ((file=Open_file_write(context)))
725   {
726     setvbuf(file, NULL, _IOFBF, 64*1024);
727 
728     // Ecriture du header
729     if (Write_bytes(file,&header.Ident,3) &&
730         Write_byte(file,header.Method) &&
731         Write_byte(file,header.Recog1) &&
732         Write_byte(file,header.Recog2) &&
733         Write_word_le(file,header.Width) &&
734         Write_word_le(file,header.Height) &&
735         Write_bytes(file,&header.Palette,sizeof(T_Palette)) &&
736         Write_word_le(file,header.Jump))
737     {
738 
739       // Ecriture du commentaire
740       // (Compteur_de_pixels est utilisé ici comme simple index de comptage)
741       if (comment_size > 0)
742       {
743         Write_one_byte(file,0);
744         Write_one_byte(file,(byte)comment_size);
745         for (Compteur_de_pixels=0; Compteur_de_pixels<comment_size; Compteur_de_pixels++)
746           Write_one_byte(file,context->Comment[Compteur_de_pixels]);
747       }
748       // Ecriture des dimensions de l'écran
749       Write_one_byte(file,1);
750       Write_one_byte(file,4);
751       Write_one_byte(file,Screen_width&0xFF);
752       Write_one_byte(file,Screen_width>>8);
753       Write_one_byte(file,Screen_height&0xFF);
754       Write_one_byte(file,Screen_height>>8);
755       // Ecriture de la back-color
756       Write_one_byte(file,2);
757       Write_one_byte(file,1);
758       Write_one_byte(file,Back_color);
759 
760       // Routine de compression PKM de l'image
761       image_size=(dword)(context->Width*context->Height);
762       Compteur_de_pixels=0;
763       pixel_value=Get_pixel(context, 0,0);
764 
765       while ( (Compteur_de_pixels<image_size) && (!File_error) )
766       {
767         Compteur_de_pixels++;
768         repetitions=1;
769         last_color=pixel_value;
770         if(Compteur_de_pixels<image_size)
771         {
772           pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width);
773         }
774         while ( (pixel_value==last_color)
775              && (Compteur_de_pixels<image_size)
776              && (repetitions<65535) )
777         {
778           Compteur_de_pixels++;
779           repetitions++;
780           if(Compteur_de_pixels>=image_size) break;
781           pixel_value=Get_pixel(context, Compteur_de_pixels % context->Width,Compteur_de_pixels / context->Width);
782         }
783 
784         if ( (last_color!=header.Recog1) && (last_color!=header.Recog2) )
785         {
786           if (repetitions==1)
787             Write_one_byte(file,last_color);
788           else
789           if (repetitions==2)
790           {
791             Write_one_byte(file,last_color);
792             Write_one_byte(file,last_color);
793           }
794           else
795           if ( (repetitions>2) && (repetitions<256) )
796           { // RECON1/couleur/nombre
797             Write_one_byte(file,header.Recog1);
798             Write_one_byte(file,last_color);
799             Write_one_byte(file,repetitions&0xFF);
800           }
801           else
802           if (repetitions>=256)
803           { // RECON2/couleur/hi(nombre)/lo(nombre)
804             Write_one_byte(file,header.Recog2);
805             Write_one_byte(file,last_color);
806             Write_one_byte(file,repetitions>>8);
807             Write_one_byte(file,repetitions&0xFF);
808           }
809         }
810         else
811         {
812           if (repetitions<256)
813           {
814             Write_one_byte(file,header.Recog1);
815             Write_one_byte(file,last_color);
816             Write_one_byte(file,repetitions&0xFF);
817           }
818           else
819           {
820             Write_one_byte(file,header.Recog2);
821             Write_one_byte(file,last_color);
822             Write_one_byte(file,repetitions>>8);
823             Write_one_byte(file,repetitions&0xFF);
824           }
825         }
826       }
827     }
828     else
829       File_error=1;
830     fclose(file);
831   }
832   else
833   {
834     File_error=1;
835     fclose(file);
836   }
837   //   S'il y a eu une erreur de sauvegarde, on ne va tout de même pas laisser
838   // ce fichier pourri traîner... Ca fait pas propre.
839   if (File_error)
840     Remove_file(context);
841 }
842 
843 
844 //////////////////////////////////// CEL ////////////////////////////////////
845 typedef struct
846 {
847   word Width;              // width de l'image
848   word Height;             // height de l'image
849 } T_CEL_Header1;
850 
851 typedef struct
852 {
853   byte Signature[4];           // Signature du format
854   byte Kind;               // Type de fichier ($10=PALette $20=BitMaP)
855   byte Nb_bits;             // Nombre de bits
856   word Filler1;            // ???
857   word Width;            // width de l'image
858   word Height;            // height de l'image
859   word X_offset;         // Offset en X de l'image
860   word Y_offset;         // Offset en Y de l'image
861   byte Filler2[16];        // ???
862 } T_CEL_Header2;
863 
864 // -- Tester si un fichier est au format CEL --------------------------------
865 
Test_CEL(T_IO_Context * context,FILE * file)866 void Test_CEL(T_IO_Context * context, FILE * file)
867 {
868   int  size;
869   T_CEL_Header1 header1;
870   T_CEL_Header2 header2;
871   int file_size;
872 
873   (void)context;
874   File_error=0;
875 
876   file_size = File_length_file(file);
877   if (Read_word_le(file,&header1.Width) &&
878       Read_word_le(file,&header1.Height) )
879   {
880       //   Vu que ce header n'a pas de signature, il va falloir tester la
881       // cohérence de la dimension de l'image avec celle du fichier.
882 
883       size=file_size-4;
884       if ( (!size) || ( (((header1.Width+1)>>1)*header1.Height)!=size ) )
885       {
886         // Tentative de reconnaissance de la signature des nouveaux fichiers
887 
888         fseek(file,0,SEEK_SET);
889         if (Read_bytes(file,&header2.Signature,4) &&
890             !memcmp(header2.Signature,"KiSS",4) &&
891             Read_byte(file,&header2.Kind) &&
892             (header2.Kind==0x20) &&
893             Read_byte(file,&header2.Nb_bits) &&
894             Read_word_le(file,&header2.Filler1) &&
895             Read_word_le(file,&header2.Width) &&
896             Read_word_le(file,&header2.Height) &&
897             Read_word_le(file,&header2.X_offset) &&
898             Read_word_le(file,&header2.Y_offset) &&
899             Read_bytes(file,&header2.Filler2,16))
900         {
901           // ok
902         }
903         else
904           File_error=1;
905       }
906       else
907         File_error=1;
908   }
909   else
910   {
911     File_error=1;
912   }
913 }
914 
915 
916 // -- Lire un fichier au format CEL -----------------------------------------
917 
Load_CEL(T_IO_Context * context)918 void Load_CEL(T_IO_Context * context)
919 {
920   FILE *file;
921   T_CEL_Header1 header1;
922   T_CEL_Header2 header2;
923   short x_pos;
924   short y_pos;
925   byte  last_byte=0;
926   long  file_size;
927   const long int header_size = 4;
928 
929   File_error=0;
930   if ((file=Open_file_read(context)))
931   {
932     if (Read_word_le(file,&(header1.Width))
933     &&  Read_word_le(file,&(header1.Height)))
934     {
935       file_size=File_length_file(file);
936       if ( (file_size>header_size)
937         && ( (((header1.Width+1)>>1)*header1.Height)==(file_size-header_size) ) )
938       {
939         // Chargement d'un fichier CEL sans signature (vieux fichiers)
940         Pre_load(context, header1.Width, header1.Height,
941                  file_size, FORMAT_CEL, PIXEL_SIMPLE, 0);
942         if (File_error==0)
943         {
944           Original_screen_X = context->Width;
945           Original_screen_Y = context->Height;
946           // Chargement de l'image
947           /*Init_lecture();*/
948           for (y_pos=0;((y_pos<context->Height) && (!File_error));y_pos++)
949             for (x_pos=0;((x_pos<context->Width) && (!File_error));x_pos++)
950               if ((x_pos & 1)==0)
951               {
952                 if(Read_byte(file,&last_byte)!=1) File_error = 2;
953                 Set_pixel(context, x_pos,y_pos,(last_byte >> 4));
954               }
955               else
956                 Set_pixel(context, x_pos,y_pos,(last_byte & 15));
957           /*Close_lecture();*/
958         }
959       }
960       else
961       {
962         // On réessaye avec le nouveau format
963 
964         fseek(file,0,SEEK_SET);
965         if (Read_bytes(file,header2.Signature,4)
966         && Read_byte(file,&(header2.Kind))
967         && Read_byte(file,&(header2.Nb_bits))
968         && Read_word_le(file,&(header2.Filler1))
969         && Read_word_le(file,&(header2.Width))
970         && Read_word_le(file,&(header2.Height))
971         && Read_word_le(file,&(header2.X_offset))
972         && Read_word_le(file,&(header2.Y_offset))
973         && Read_bytes(file,header2.Filler2,16)
974         )
975         {
976           // Chargement d'un fichier CEL avec signature (nouveaux fichiers)
977 
978           Pre_load(context,
979                    header2.Width + header2.X_offset,
980                    header2.Height + header2.Y_offset,
981                    file_size, FORMAT_CEL, PIXEL_SIMPLE, 0);
982           if (File_error==0)
983           {
984             Original_screen_X = context->Width;
985             Original_screen_Y = context->Height;
986             // Chargement de l'image
987             /*Init_lecture();*/
988 
989             if (!File_error)
990             {
991               // Effacement du décalage
992               for (y_pos=0;y_pos<header2.Y_offset;y_pos++)
993                 for (x_pos=0;x_pos<context->Width;x_pos++)
994                   Set_pixel(context, x_pos,y_pos,0);
995               for (y_pos=header2.Y_offset;y_pos<context->Height;y_pos++)
996                 for (x_pos=0;x_pos<header2.X_offset;x_pos++)
997                   Set_pixel(context, x_pos,y_pos,0);
998 
999               switch(header2.Nb_bits)
1000               {
1001                 case 4:
1002                   for (y_pos=0;((y_pos<header2.Height) && (!File_error));y_pos++)
1003                     for (x_pos=0;((x_pos<header2.Width) && (!File_error));x_pos++)
1004                       if ((x_pos & 1)==0)
1005                       {
1006                         if(Read_byte(file,&last_byte)!=1) File_error=2;
1007                         Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte >> 4));
1008                       }
1009                       else
1010                         Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,(last_byte & 15));
1011                   break;
1012 
1013                 case 8:
1014                   for (y_pos=0;((y_pos<header2.Height) && (!File_error));y_pos++)
1015                     for (x_pos=0;((x_pos<header2.Width) && (!File_error));x_pos++)
1016                     {
1017                       byte byte_read;
1018                       if(Read_byte(file,&byte_read)!=1) File_error = 2;
1019                       Set_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset,byte_read);
1020                       }
1021                   break;
1022 
1023                 default:
1024                   File_error=1;
1025               }
1026             }
1027             /*Close_lecture();*/
1028           }
1029         }
1030         else
1031           File_error=1;
1032       }
1033       fclose(file);
1034     }
1035     else
1036       File_error=1;
1037   }
1038   else
1039     File_error=1;
1040 }
1041 
1042 
1043 // -- Ecrire un fichier au format CEL ---------------------------------------
1044 
Save_CEL(T_IO_Context * context)1045 void Save_CEL(T_IO_Context * context)
1046 {
1047   FILE *file;
1048   T_CEL_Header1 header1;
1049   T_CEL_Header2 header2;
1050   short x_pos;
1051   short y_pos;
1052   byte  last_byte=0;
1053   dword color_usage[256]; // Table d'utilisation de couleurs
1054 
1055 
1056   // On commence par compter l'utilisation de chaque couleurs
1057   Count_used_colors(color_usage);
1058 
1059   File_error=0;
1060   if ((file=Open_file_write(context)))
1061   {
1062     setvbuf(file, NULL, _IOFBF, 64*1024);
1063 
1064     // On regarde si des couleurs >16 sont utilisées dans l'image
1065     for (x_pos=16;((x_pos<256) && (!color_usage[x_pos]));x_pos++);
1066 
1067     if (x_pos==256)
1068     {
1069       // Cas d'une image 16 couleurs (écriture à l'ancien format)
1070 
1071       header1.Width =context->Width;
1072       header1.Height=context->Height;
1073 
1074       if (Write_word_le(file,header1.Width)
1075       && Write_word_le(file,header1.Height)
1076       )
1077       {
1078         // Sauvegarde de l'image
1079         for (y_pos=0;((y_pos<context->Height) && (!File_error));y_pos++)
1080         {
1081           for (x_pos=0;((x_pos<context->Width) && (!File_error));x_pos++)
1082             if ((x_pos & 1)==0)
1083               last_byte=(Get_pixel(context, x_pos,y_pos) << 4);
1084             else
1085             {
1086               last_byte=last_byte | (Get_pixel(context, x_pos,y_pos) & 15);
1087               Write_one_byte(file,last_byte);
1088             }
1089 
1090           if ((x_pos & 1)==1)
1091             Write_one_byte(file,last_byte);
1092         }
1093       }
1094       else
1095         File_error=1;
1096       fclose(file);
1097     }
1098     else
1099     {
1100       // Cas d'une image 256 couleurs (écriture au nouveau format)
1101 
1102       // Recherche du décalage
1103       for (y_pos=0;y_pos<context->Height;y_pos++)
1104       {
1105         for (x_pos=0;x_pos<context->Width;x_pos++)
1106           if (Get_pixel(context, x_pos,y_pos)!=0)
1107             break;
1108         if (Get_pixel(context, x_pos,y_pos)!=0)
1109           break;
1110       }
1111       header2.Y_offset=y_pos;
1112       for (x_pos=0;x_pos<context->Width;x_pos++)
1113       {
1114         for (y_pos=0;y_pos<context->Height;y_pos++)
1115           if (Get_pixel(context, x_pos,y_pos)!=0)
1116             break;
1117         if (Get_pixel(context, x_pos,y_pos)!=0)
1118           break;
1119       }
1120       header2.X_offset=x_pos;
1121 
1122       memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature
1123       header2.Kind=0x20;              // Initialisation du type (BitMaP)
1124       header2.Nb_bits=8;               // Initialisation du nombre de bits
1125       header2.Filler1=0;              // Initialisation du filler 1 (?)
1126       header2.Width=context->Width-header2.X_offset; // Initialisation de la largeur
1127       header2.Height=context->Height-header2.Y_offset; // Initialisation de la hauteur
1128       for (x_pos=0;x_pos<16;x_pos++)  // Initialisation du filler 2 (?)
1129         header2.Filler2[x_pos]=0;
1130 
1131       if (Write_bytes(file,header2.Signature,4)
1132       && Write_byte(file,header2.Kind)
1133       && Write_byte(file,header2.Nb_bits)
1134       && Write_word_le(file,header2.Filler1)
1135       && Write_word_le(file,header2.Width)
1136       && Write_word_le(file,header2.Height)
1137       && Write_word_le(file,header2.X_offset)
1138       && Write_word_le(file,header2.Y_offset)
1139       && Write_bytes(file,header2.Filler2,14)
1140       )
1141       {
1142         // Sauvegarde de l'image
1143         for (y_pos=0;((y_pos<header2.Height) && (!File_error));y_pos++)
1144           for (x_pos=0;((x_pos<header2.Width) && (!File_error));x_pos++)
1145             Write_one_byte(file,Get_pixel(context, x_pos+header2.X_offset,y_pos+header2.Y_offset));
1146       }
1147       else
1148         File_error=1;
1149       fclose(file);
1150     }
1151 
1152     if (File_error)
1153       Remove_file(context);
1154   }
1155   else
1156     File_error=1;
1157 }
1158 
1159 
1160 //////////////////////////////////// KCF ////////////////////////////////////
1161 typedef struct
1162 {
1163   struct
1164   {
1165     struct
1166     {
1167       byte Byte1;
1168       byte Byte2;
1169     } color[16];
1170   } Palette[10];
1171 } T_KCF_Header;
1172 
1173 // -- Tester si un fichier est au format KCF --------------------------------
1174 
Test_KCF(T_IO_Context * context,FILE * file)1175 void Test_KCF(T_IO_Context * context, FILE * file)
1176 {
1177   T_KCF_Header header1;
1178   T_CEL_Header2 header2;
1179   int pal_index;
1180   int color_index;
1181 
1182   (void)context;
1183   File_error=0;
1184     if (File_length_file(file)==320)
1185     {
1186       for (pal_index=0;pal_index<10 && !File_error;pal_index++)
1187         for (color_index=0;color_index<16 && !File_error;color_index++)
1188           if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) ||
1189               !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2))
1190             File_error=1;
1191       // On vérifie une propriété de la structure de palette:
1192       for (pal_index=0;pal_index<10;pal_index++)
1193         for (color_index=0;color_index<16;color_index++)
1194           if ((header1.Palette[pal_index].color[color_index].Byte2>>4)!=0)
1195             File_error=1;
1196     }
1197     else
1198     {
1199       if (Read_bytes(file,header2.Signature,4)
1200         && Read_byte(file,&(header2.Kind))
1201         && Read_byte(file,&(header2.Nb_bits))
1202         && Read_word_le(file,&(header2.Filler1))
1203         && Read_word_le(file,&(header2.Width))
1204         && Read_word_le(file,&(header2.Height))
1205         && Read_word_le(file,&(header2.X_offset))
1206         && Read_word_le(file,&(header2.Y_offset))
1207         && Read_bytes(file,header2.Filler2,14)
1208         )
1209       {
1210         if (memcmp(header2.Signature,"KiSS",4)==0)
1211         {
1212           if (header2.Kind!=0x10)
1213             File_error=1;
1214         }
1215         else
1216           File_error=1;
1217       }
1218       else
1219         File_error=1;
1220     }
1221 }
1222 
1223 
1224 // -- Lire un fichier au format KCF -----------------------------------------
1225 
Load_KCF(T_IO_Context * context)1226 void Load_KCF(T_IO_Context * context)
1227 {
1228   FILE *file;
1229   T_KCF_Header header1;
1230   T_CEL_Header2 header2;
1231   byte bytes[3];
1232   int pal_index;
1233   int color_index;
1234   int index;
1235   long  file_size;
1236 
1237 
1238   File_error=0;
1239   if ((file=Open_file_read(context)))
1240   {
1241     file_size=File_length_file(file);
1242     if (file_size==320)
1243     {
1244       // Fichier KCF à l'ancien format
1245       for (pal_index=0;pal_index<10 && !File_error;pal_index++)
1246         for (color_index=0;color_index<16 && !File_error;color_index++)
1247           if (!Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte1) ||
1248               !Read_byte(file,&header1.Palette[pal_index].color[color_index].Byte2))
1249             File_error=1;
1250 
1251       if (!File_error)
1252       {
1253         // Pre_load(context, ?); // Pas possible... pas d'image...
1254 
1255         if (Config.Clear_palette)
1256           memset(context->Palette,0,sizeof(T_Palette));
1257 
1258         // Chargement de la palette
1259         for (pal_index=0;pal_index<10;pal_index++)
1260           for (color_index=0;color_index<16;color_index++)
1261           {
1262             index=16+(pal_index*16)+color_index;
1263             context->Palette[index].R=((header1.Palette[pal_index].color[color_index].Byte1 >> 4) << 4);
1264             context->Palette[index].B=((header1.Palette[pal_index].color[color_index].Byte1 & 15) << 4);
1265             context->Palette[index].G=((header1.Palette[pal_index].color[color_index].Byte2 & 15) << 4);
1266           }
1267 
1268         for (index=0;index<16;index++)
1269         {
1270           context->Palette[index].R=context->Palette[index+16].R;
1271           context->Palette[index].G=context->Palette[index+16].G;
1272           context->Palette[index].B=context->Palette[index+16].B;
1273         }
1274 
1275       }
1276       else
1277         File_error=1;
1278     }
1279     else
1280     {
1281       // Fichier KCF au nouveau format
1282 
1283       if (Read_bytes(file,header2.Signature,4)
1284         && Read_byte(file,&(header2.Kind))
1285         && Read_byte(file,&(header2.Nb_bits))
1286         && Read_word_le(file,&(header2.Filler1))
1287         && Read_word_le(file,&(header2.Width))
1288         && Read_word_le(file,&(header2.Height))
1289         && Read_word_le(file,&(header2.X_offset))
1290         && Read_word_le(file,&(header2.Y_offset))
1291         && Read_bytes(file,header2.Filler2,14)
1292         )
1293       {
1294         // Pre_load(context, ?); // Pas possible... pas d'image...
1295 
1296         index=(header2.Nb_bits==12)?16:0;
1297         for (pal_index=0;pal_index<header2.Height;pal_index++)
1298         {
1299            // Pour chaque palette
1300 
1301            for (color_index=0;color_index<header2.Width;color_index++)
1302            {
1303              // Pour chaque couleur
1304 
1305              switch(header2.Nb_bits)
1306              {
1307                case 12: // RRRR BBBB | 0000 VVVV
1308                  Read_bytes(file,bytes,2);
1309                  context->Palette[index].R=(bytes[0] >> 4) << 4;
1310                  context->Palette[index].B=(bytes[0] & 15) << 4;
1311                  context->Palette[index].G=(bytes[1] & 15) << 4;
1312                  break;
1313 
1314                case 24: // RRRR RRRR | VVVV VVVV | BBBB BBBB
1315                  Read_bytes(file,bytes,3);
1316                  context->Palette[index].R=bytes[0];
1317                  context->Palette[index].G=bytes[1];
1318                  context->Palette[index].B=bytes[2];
1319              }
1320 
1321              index++;
1322            }
1323         }
1324 
1325         if (header2.Nb_bits==12)
1326           for (index=0;index<16;index++)
1327           {
1328             context->Palette[index].R=context->Palette[index+16].R;
1329             context->Palette[index].G=context->Palette[index+16].G;
1330             context->Palette[index].B=context->Palette[index+16].B;
1331           }
1332 
1333       }
1334       else
1335         File_error=1;
1336     }
1337     fclose(file);
1338   }
1339   else
1340     File_error=1;
1341 }
1342 
1343 
1344 // -- Ecrire un fichier au format KCF ---------------------------------------
1345 
Save_KCF(T_IO_Context * context)1346 void Save_KCF(T_IO_Context * context)
1347 {
1348   FILE *file;
1349   T_KCF_Header header1;
1350   T_CEL_Header2 header2;
1351   byte bytes[3];
1352   int pal_index;
1353   int color_index;
1354   int index;
1355   dword color_usage[256]; // Table d'utilisation de couleurs
1356 
1357   // On commence par compter l'utilisation de chaque couleurs
1358   Count_used_colors(color_usage);
1359 
1360   File_error=0;
1361   if ((file=Open_file_write(context)))
1362   {
1363     setvbuf(file, NULL, _IOFBF, 64*1024);
1364     // Sauvegarde de la palette
1365 
1366     // On regarde si des couleurs >16 sont utilisées dans l'image
1367     for (index=16;((index<256) && (!color_usage[index]));index++);
1368 
1369     if (index==256)
1370     {
1371       // Cas d'une image 16 couleurs (écriture à l'ancien format)
1372 
1373       for (pal_index=0;pal_index<10;pal_index++)
1374         for (color_index=0;color_index<16;color_index++)
1375         {
1376           index=16+(pal_index*16)+color_index;
1377           header1.Palette[pal_index].color[color_index].Byte1=((context->Palette[index].R>>4)<<4) | (context->Palette[index].B>>4);
1378           header1.Palette[pal_index].color[color_index].Byte2=context->Palette[index].G>>4;
1379         }
1380 
1381       // Write all
1382       for (pal_index=0;pal_index<10 && !File_error;pal_index++)
1383         for (color_index=0;color_index<16 && !File_error;color_index++)
1384           if (!Write_byte(file,header1.Palette[pal_index].color[color_index].Byte1) ||
1385               !Write_byte(file,header1.Palette[pal_index].color[color_index].Byte2))
1386             File_error=1;
1387     }
1388     else
1389     {
1390       // Cas d'une image 256 couleurs (écriture au nouveau format)
1391 
1392       memcpy(header2.Signature,"KiSS",4); // Initialisation de la signature
1393       header2.Kind=0x10;              // Initialisation du type (PALette)
1394       header2.Nb_bits=24;              // Initialisation du nombre de bits
1395       header2.Filler1=0;              // Initialisation du filler 1 (?)
1396       header2.Width=256;            // Initialisation du nombre de couleurs
1397       header2.Height=1;              // Initialisation du nombre de palettes
1398       header2.X_offset=0;           // Initialisation du décalage X
1399       header2.Y_offset=0;           // Initialisation du décalage Y
1400       for (index=0;index<16;index++) // Initialisation du filler 2 (?)
1401         header2.Filler2[index]=0;
1402 
1403       if (!Write_bytes(file,header2.Signature,4)
1404       || !Write_byte(file,header2.Kind)
1405       || !Write_byte(file,header2.Nb_bits)
1406       || !Write_word_le(file,header2.Filler1)
1407       || !Write_word_le(file,header2.Width)
1408       || !Write_word_le(file,header2.Height)
1409       || !Write_word_le(file,header2.X_offset)
1410       || !Write_word_le(file,header2.Y_offset)
1411       || !Write_bytes(file,header2.Filler2,14)
1412       )
1413         File_error=1;
1414 
1415       for (index=0;(index<256) && (!File_error);index++)
1416       {
1417         bytes[0]=context->Palette[index].R;
1418         bytes[1]=context->Palette[index].G;
1419         bytes[2]=context->Palette[index].B;
1420         if (! Write_bytes(file,bytes,3))
1421           File_error=1;
1422       }
1423     }
1424 
1425     fclose(file);
1426 
1427     if (File_error)
1428       Remove_file(context);
1429   }
1430   else
1431     File_error=1;
1432 }
1433 
1434 
1435 /////////////////////////////////// FLI/FLC /////////////////////////////////
1436 typedef struct {
1437   dword size;          /* Size of FLIC including this header */
1438   word  type;          /* File type 0xAF11, 0xAF12, 0xAF30, 0xAF44, ... */
1439   word  frames;        /* Number of frames in first segment */
1440   word  width;         /* FLIC width in pixels */
1441   word  height;        /* FLIC height in pixels */
1442   word  depth;         /* Bits per pixel (usually 8) */
1443   word  flags;         /* Set to zero or to three */
1444   dword speed;         /* Delay between frames */
1445   word  reserved1;     /* Set to zero */
1446   dword created;       /* Date of FLIC creation (FLC only) */
1447   dword creator;       /* Serial number or compiler id (FLC only) */
1448   dword updated;       /* Date of FLIC update (FLC only) */
1449   dword updater;       /* Serial number (FLC only), see creator */
1450   word  aspect_dx;     /* Width of square rectangle (FLC only) */
1451   word  aspect_dy;     /* Height of square rectangle (FLC only) */
1452   word  ext_flags;     /* EGI: flags for specific EGI extensions */
1453   word  keyframes;     /* EGI: key-image frequency */
1454   word  totalframes;   /* EGI: total number of frames (segments) */
1455   dword req_memory;    /* EGI: maximum chunk size (uncompressed) */
1456   word  max_regions;   /* EGI: max. number of regions in a CHK_REGION chunk */
1457   word  transp_num;    /* EGI: number of transparent levels */
1458   byte  reserved2[24]; /* Set to zero */
1459   dword oframe1;       /* Offset to frame 1 (FLC only) */
1460   dword oframe2;       /* Offset to frame 2 (FLC only) */
1461   byte  reserved3[40]; /* Set to zero */
1462 } T_FLIC_Header;
1463 
Load_FLI_Header(FILE * file,T_FLIC_Header * header)1464 static void Load_FLI_Header(FILE * file, T_FLIC_Header * header)
1465 {
1466   if (!(Read_dword_le(file,&header->size)
1467       && Read_word_le(file,&header->type)
1468       && Read_word_le(file,&header->frames)
1469       && Read_word_le(file,&header->width)
1470       && Read_word_le(file,&header->height)
1471       && Read_word_le(file,&header->depth)
1472       && Read_word_le(file,&header->flags)
1473       && Read_dword_le(file,&header->speed)
1474       && Read_word_le(file,&header->reserved1)
1475       && Read_dword_le(file,&header->created)
1476       && Read_dword_le(file,&header->creator)
1477       && Read_dword_le(file,&header->updated)
1478       && Read_dword_le(file,&header->updater)
1479       && Read_word_le(file,&header->aspect_dx)
1480       && Read_word_le(file,&header->aspect_dy)
1481       && Read_word_le(file,&header->ext_flags)
1482       && Read_word_le(file,&header->keyframes)
1483       && Read_word_le(file,&header->totalframes)
1484       && Read_dword_le(file,&header->req_memory)
1485       && Read_word_le(file,&header->max_regions)
1486       && Read_word_le(file,&header->transp_num)
1487       && Read_bytes(file,header->reserved2,24)
1488       && Read_dword_le(file,&header->oframe1)
1489       && Read_dword_le(file,&header->oframe2)
1490       && Read_bytes(file,header->reserved2,40) ))
1491   {
1492     File_error=1;
1493   }
1494 }
1495 
1496 /**
1497  * Test for the Autodesk Animator FLI/FLC format.
1498  *
1499  * Not to be confused with Commodore 64 FLI.
1500  */
Test_FLI(T_IO_Context * context,FILE * file)1501 void Test_FLI(T_IO_Context * context, FILE * file)
1502 {
1503   T_FLIC_Header header;
1504   (void)context;
1505 
1506   File_error=0;
1507   Load_FLI_Header(file, &header);
1508   if (File_error != 0) return;
1509 
1510   switch (header.type)
1511   {
1512     case 0xAF11:  // standard FLI
1513     case 0xAF12:  // FLC (8bpp)
1514 #if 0
1515     case 0xAF30:  // Huffman or BWT compression
1516     case 0xAF31:  // frame shift compression
1517     case 0xAF44:  // bpp != 8
1518 #endif
1519       File_error=0;
1520       break;
1521     default:
1522       File_error=1;
1523   }
1524 }
1525 
1526 /**
1527  * Load file in the Autodesk Animator FLI/FLC format.
1528  *
1529  * Not to be confused with Commodore 64 FLI.
1530  */
Load_FLI(T_IO_Context * context)1531 void Load_FLI(T_IO_Context * context)
1532 {
1533   FILE * file;
1534   unsigned long file_size;
1535   T_FLIC_Header header;
1536   dword chunk_size;
1537   word chunk_type;
1538   word sub_chunk_count, sub_chunk_index;
1539   dword sub_chunk_size;
1540   word sub_chunk_type;
1541   word frame_delay, frame_width, frame_height;
1542   int current_frame = 0;
1543 
1544   file = Open_file_read(context);
1545   if (file == NULL)
1546   {
1547     File_error=1;
1548     return;
1549   }
1550   File_error=0;
1551   file_size = File_length_file(file);
1552   Load_FLI_Header(file, &header);
1553   if (File_error != 0)
1554   {
1555     fclose(file);
1556     return;
1557   }
1558   if (header.size == 12)
1559   {
1560     // special "magic carpet" format
1561     header.depth = 8;
1562     header.speed = 66; // about 15fps
1563     fseek(file, 12, SEEK_SET);
1564   }
1565   else if (file_size != header.size)
1566     GFX2_Log(GFX2_WARNING, "Load_FLI(): file size mismatch in header %lu != %u\n", file_size, header.size);
1567 
1568   if (header.speed == 0)
1569   {
1570     if (header.type == 0xAF11) // FLI
1571       header.speed = 1;   // 1/70th seconds
1572     else
1573       header.speed = 10;  // 10ms
1574   }
1575 
1576   while (File_error == 0
1577      && Read_dword_le(file,&chunk_size) && Read_word_le(file,&chunk_type))
1578   {
1579     chunk_size -= 6;
1580     switch (chunk_type)
1581     {
1582       case 0xf1fa:  // FRAME
1583         Read_word_le(file, &sub_chunk_count);
1584         Read_word_le(file, &frame_delay);
1585         fseek(file, 2, SEEK_CUR);
1586         Read_word_le(file, &frame_width);
1587         Read_word_le(file, &frame_height);
1588         if (frame_width == 0)
1589           frame_width = header.width;
1590         if (frame_height == 0)
1591           frame_height = header.height;
1592         if (frame_delay == 0)
1593           frame_delay = header.speed;
1594         chunk_size -= 10;
1595 
1596         if (current_frame == 0)
1597         {
1598           Pre_load(context, header.width,header.height,file_size,FORMAT_FLI,PIXEL_SIMPLE,header.depth);
1599           Set_image_mode(context, IMAGE_MODE_ANIMATION);
1600           if (Config.Clear_palette)
1601             memset(context->Palette,0,sizeof(T_Palette));
1602         }
1603         else
1604         {
1605           Set_loading_layer(context, current_frame);
1606           if (context->Type == CONTEXT_MAIN_IMAGE && Get_image_mode(context) == IMAGE_MODE_ANIMATION)
1607           {
1608             // Copy the content of previous frame
1609             memcpy(
1610                 Main.backups->Pages->Image[Main.current_layer].Pixels,
1611                 Main.backups->Pages->Image[Main.current_layer-1].Pixels,
1612                 Main.backups->Pages->Width*Main.backups->Pages->Height);
1613           }
1614         }
1615         if (header.type == 0xAF11) // FLI
1616           Set_frame_duration(context, (frame_delay * 100) / 7); // 1/70th sec
1617         else
1618           Set_frame_duration(context, frame_delay); // msec
1619         current_frame++;
1620 
1621         for (sub_chunk_index = 0; sub_chunk_index < sub_chunk_count; sub_chunk_index++)
1622         {
1623           if (!(Read_dword_le(file,&sub_chunk_size) && Read_word_le(file,&sub_chunk_type)))
1624             File_error = 1;
1625           else
1626           {
1627             chunk_size -= sub_chunk_size;
1628             sub_chunk_size -= 6;
1629             if (sub_chunk_type == 0x04 || sub_chunk_type == 0x0b)   // color map
1630             {
1631               word packet_count;
1632               int i = 0;
1633               sub_chunk_size -= 2;
1634               if (!Read_word_le(file, &packet_count))
1635                 File_error = 1;
1636               else
1637                 while (packet_count-- > 0 && File_error == 0)
1638                 {
1639                   byte skip, count;
1640                   if (!(Read_byte(file, &skip) && Read_byte(file, &count)))
1641                     File_error = 1;
1642                   else
1643                   {
1644                     sub_chunk_size -= 2;
1645                     i += skip;  // count 0 means 256
1646                     do
1647                     {
1648                       byte r, g, b;
1649                       if (!(Read_byte(file, &r) && Read_byte(file, &g) && Read_byte(file, &b)))
1650                       {
1651                         File_error = 1;
1652                         break;
1653                       }
1654                       if (sub_chunk_type == 0x0b || header.size == 12) // 6bit per color
1655                       {
1656                         r = (r << 2) | (r >> 4);
1657                         g = (g << 2) | (g >> 4);
1658                         b = (b << 2) | (b >> 4);
1659                       }
1660                       context->Palette[i].R = r;
1661                       context->Palette[i].G = g;
1662                       context->Palette[i].B = b;
1663                       i++;
1664                       sub_chunk_size -= 3;
1665                     } while (--count != 0);
1666                   }
1667                 }
1668             }
1669             else if (sub_chunk_type == 0x0f)  // full frame RLE
1670             {
1671               word x, y;
1672               for (y = 0; y < frame_height && File_error == 0; y++)
1673               {
1674                 byte count, data;
1675                 Read_byte(file, &count); // packet count, but dont rely on it
1676                 sub_chunk_size--;
1677                 for (x = 0; x < frame_width; )
1678                 {
1679                   if (!Read_byte(file, &count))
1680                   {
1681                     File_error = 1;
1682                     break;
1683                   }
1684                   sub_chunk_size--;
1685                   if ((count & 0x80) == 0)
1686                   {
1687                     if (!Read_byte(file, &data))  // repeat data count times
1688                     {
1689                       File_error = 1;
1690                       break;
1691                     }
1692                     sub_chunk_size--;
1693                     while (count-- > 0 && x < frame_width)
1694                       Set_pixel(context, x++, y, data);
1695                   }
1696                   else
1697                     while (count++ != 0 && x < frame_width)  // copy count bytes
1698                     {
1699                       if (!Read_byte(file, &data))
1700                       {
1701                         File_error = 1;
1702                         break;
1703                       }
1704                       Set_pixel(context, x++, y, data);
1705                       sub_chunk_size--;
1706                     }
1707                 }
1708               }
1709               if (context->Type == CONTEXT_PREVIEW || context->Type == CONTEXT_PREVIEW_PALETTE)
1710               { // load only 1st frame in preview
1711                 fclose(file);
1712                 return;
1713               }
1714             }
1715             else if (sub_chunk_type == 0x0c)  // delta image, RLE
1716             {
1717               word x, y, line_count;
1718 
1719               Read_word_le(file, &y);
1720               Read_word_le(file, &line_count);
1721               sub_chunk_size -= 4;
1722               while (sub_chunk_size > 0 && line_count > 0 && File_error == 0)
1723               {
1724                 byte packet_count;
1725 
1726                 x = 0;
1727                 if (!Read_byte(file, &packet_count))
1728                   File_error = 1;
1729                 else
1730                 {
1731                   sub_chunk_size--;
1732                   while (packet_count-- > 0 && File_error == 0)
1733                   {
1734                     byte skip, count, data;
1735                     if (!(Read_byte(file, &skip) && Read_byte(file, &count)))
1736                       File_error = 1;
1737                     else
1738                     {
1739                       sub_chunk_size -= 2;
1740                       x += skip;
1741                       if (count & 0x80)
1742                       {
1743                         Read_byte(file, &data);
1744                         sub_chunk_size--;
1745                         while (count++ != 0)
1746                           Set_pixel(context, x++, y, data);
1747                       }
1748                       else
1749                         while (count-- > 0)
1750                         {
1751                           Read_byte(file, &data);
1752                           sub_chunk_size--;
1753                           Set_pixel(context, x++, y, data);
1754                         }
1755                     }
1756                   }
1757                 }
1758                 y++;
1759                 line_count--;
1760               }
1761             }
1762             else if (sub_chunk_type == 0x07)  // FLC delta image
1763             {
1764               word opcode, y, line_count;
1765 
1766               y = 0;
1767               Read_word_le(file, &line_count);
1768               sub_chunk_size -= 2;
1769               while (line_count > 0)
1770               {
1771                 Read_word_le(file, &opcode);
1772                 sub_chunk_size -= 2;
1773                 if ((opcode & 0xc000) == 0x0000) // packet count
1774                 {
1775                   word x = 0;
1776                   while (opcode-- > 0)
1777                   {
1778                     byte skip, count, data1, data2;
1779                     if (!(Read_byte(file, &skip) && Read_byte(file, &count)))
1780                       File_error = 1;
1781                     else
1782                     {
1783                       sub_chunk_size -= 2;
1784                       x += skip;
1785                       if (count & 0x80)
1786                       {
1787                         Read_byte(file, &data1);
1788                         Read_byte(file, &data2);
1789                         sub_chunk_size -= 2;
1790                         while (count++ != 0)
1791                         {
1792                           Set_pixel(context, x++, y, data1);
1793                           Set_pixel(context, x++, y, data2);
1794                         }
1795                       }
1796                       else
1797                         while (count-- > 0)
1798                         {
1799                           Read_byte(file, &data1);
1800                           Set_pixel(context, x++, y, data1);
1801                           Read_byte(file, &data2);
1802                           Set_pixel(context, x++, y, data2);
1803                           sub_chunk_size -= 2;
1804                         }
1805                     }
1806                   }
1807                   y++;
1808                   line_count--;
1809                 }
1810                 else if ((opcode & 0xc000) == 0xc000)  // line skip
1811                 {
1812                   y -= opcode;
1813                 }
1814                 else if ((opcode & 0xc000) == 0x8000)  // last byte
1815                 {
1816                   Set_pixel(context, frame_width - 1, y, opcode & 0xff);
1817                 }
1818                 else
1819                 {
1820                   GFX2_Log(GFX2_WARNING, "Unsupported opcode %04x\n", opcode);
1821                   File_error = 2;
1822                   break;
1823                 }
1824               }
1825             }
1826             if (sub_chunk_size > 0)
1827             {
1828               fseek(file, sub_chunk_size, SEEK_CUR);
1829             }
1830           }
1831         }
1832         break;
1833       default:  // skip
1834         GFX2_Log(GFX2_WARNING, "Load_FLI(): unrecognized chunk %04x\n", chunk_type);
1835     }
1836     if (chunk_size > 0 && header.size != 12)
1837     {
1838       fseek(file, chunk_size, SEEK_CUR);
1839     }
1840   }
1841   fclose(file);
1842 }
1843 
1844 /////////////////////////////// Apple II Files //////////////////////////////
1845 
1846 /**
1847  * Test for an Apple II HGR or DHGR raw file
1848  */
Test_HGR(T_IO_Context * context,FILE * file)1849 void Test_HGR(T_IO_Context * context, FILE * file)
1850 {
1851   long file_size;
1852 
1853   (void)context;
1854   File_error = 1;
1855 
1856   file_size = File_length_file(file);
1857   if (file_size == 8192)  // HGR
1858     File_error = 0;
1859   else if(file_size == 16384) // DHGR
1860     File_error = 0;
1861 }
1862 
1863 /**
1864  * Load HGR (280x192) or DHGR (560x192) Apple II pictures
1865  *
1866  * Creates 2 layers :
1867  * 1. Monochrome
1868  * 2. Color
1869  */
Load_HGR(T_IO_Context * context)1870 void Load_HGR(T_IO_Context * context)
1871 {
1872   unsigned long file_size;
1873   FILE * file;
1874   byte * vram[2];
1875   int bank;
1876   int x, y;
1877   int is_dhgr = 0;
1878 
1879   file = Open_file_read(context);
1880   if (file == NULL)
1881   {
1882     File_error = 1;
1883     return;
1884   }
1885   file_size = File_length_file(file);
1886   if (file_size == 16384)
1887     is_dhgr = 1;
1888 
1889   vram[0] = GFX2_malloc(8192);
1890   Read_bytes(file, vram[0], 8192);
1891   if (is_dhgr)
1892   {
1893     vram[1] = GFX2_malloc(8192);
1894     Read_bytes(file, vram[1], 8192);
1895   }
1896   else
1897     vram[1] = NULL;
1898   fclose(file);
1899 
1900   if (Config.Clear_palette)
1901     memset(context->Palette,0,sizeof(T_Palette));
1902   if (is_dhgr)
1903   {
1904     DHGR_set_palette(context->Palette);
1905     Pre_load(context, 560, 192, file_size, FORMAT_HGR, PIXEL_TALL, 4);
1906   }
1907   else
1908   {
1909     HGR_set_palette(context->Palette);
1910     Pre_load(context, 280, 192, file_size, FORMAT_HGR, PIXEL_SIMPLE, 2);
1911   }
1912   for (y = 0; y < 192; y++)
1913   {
1914     byte palette = 0, color = 0;
1915     byte previous_palette = 0;  // palette for the previous pixel pair
1916     int column, i;
1917     int offset = ((y & 7) << 10) + ((y & 070) << 4) + ((y >> 6) * 40);
1918     x = 0;
1919     for (column = 0; column < 40; column++)
1920     for (bank = 0; bank <= is_dhgr; bank++)
1921     {
1922       byte b = vram[bank][offset+column];
1923       if (!is_dhgr)
1924         palette = (b & 0x80) ? 4 : 0;
1925       else
1926         palette = (b & 0x80) ? 0 : 16;
1927       for (i = 0; i < 7; i++)
1928       {
1929         if (context->Type == CONTEXT_MAIN_IMAGE)
1930         {
1931           // monochrome
1932           Set_loading_layer(context, 0);
1933           Set_pixel(context, x, y, ((b & 1) * (is_dhgr ? 15 : 3)) + palette);
1934           Set_loading_layer(context, 1);
1935         }
1936         // color
1937         color = (color << 1) | (b & 1);
1938         if (is_dhgr)
1939         {
1940           if ((x & 3) == 0)
1941             previous_palette = palette; // what is important is the value when the 1st bit was read...
1942           /// emulate "chat mauve" DHGR mixed mode.
1943           /// see http://boutillon.free.fr/Underground/Anim_Et_Graph/Extasie_Chat_Mauve_Reloaded/Extasie_Chat_Mauve_Reloaded.html
1944           if (previous_palette) // BW
1945             Set_pixel(context, x, y, ((b & 1) * 15) + palette);
1946           else if ((x & 3) == 3)
1947           {
1948             Set_pixel(context, x - 3, y, (color & 15) + palette);
1949             Set_pixel(context, x - 2, y, (color & 15) + palette);
1950             Set_pixel(context, x - 1, y, (color & 15) + palette);
1951             Set_pixel(context, x, y, (color & 15) + palette);
1952           }
1953         }
1954         else
1955         {
1956           /// HGR emulation following the behaviour of a "Le Chat Mauve"
1957           /// RVB adapter for the Apple //c.
1958           /// Within the bit stream, the color of the middle pixel is :<br>
1959           /// <tt>
1960           /// 111 \          <br>
1961           /// 110  }- white  <br>
1962           /// 011 /          <br>
1963           /// 010 \ _ color  <br>
1964           /// 101 /          <br>
1965           /// 000 \          <br>
1966           /// 001  }- black  <br>
1967           /// 100 /          <br>
1968           /// </tt>
1969           /// Color depends on the selected palette for the current byte
1970           /// and the position of the pixel (odd or even).
1971           if ((color & 3) == 3) // 11 => white
1972           {
1973             Set_pixel(context, x - 1, y, 3 + previous_palette);
1974             Set_pixel(context, x, y, 3 + palette);
1975           }
1976           else if ((color & 1) == 0) // 0 => black
1977             Set_pixel(context, x, y, palette);
1978           else // 01 => color
1979           {
1980             if ((color & 7) == 5) // 101
1981               Set_pixel(context, x - 1, y, 2 - (x & 1) + previous_palette);
1982             Set_pixel(context, x, y, 2 - (x & 1) + palette);
1983           }
1984           previous_palette = palette;
1985         }
1986         b >>= 1;
1987         x++;
1988       }
1989     }
1990   }
1991   // show hidden data in HOLES
1992   for (y = 0; y < 64; y++)
1993   for (bank = 0; bank < 1; bank++)
1994   {
1995     byte b = 0;
1996     for (x = 0; x < 8; x++)
1997       b |= vram[bank][x + (y << 7) + 120];
1998     if (b != 0)
1999       GFX2_LogHexDump(GFX2_DEBUG, bank ? "AUX " : "MAIN", vram[bank], (y << 7) + 120, 8);
2000   }
2001   free(vram[0]);
2002   free(vram[1]);
2003   File_error = 0;
2004 
2005   Set_image_mode(context, is_dhgr ? IMAGE_MODE_DHGR : IMAGE_MODE_HGR);
2006 }
2007 
2008 /**
2009  * Save HGR (280x192) or DHGR (560x192) Apple II pictures
2010  *
2011  * The data saved is the "monochrome" data from layer 1
2012  */
Save_HGR(T_IO_Context * context)2013 void Save_HGR(T_IO_Context * context)
2014 {
2015   FILE * file;
2016   byte * vram[2];
2017   int bank;
2018   int x, y;
2019   int is_dhgr = 0;
2020 
2021   File_error = 1;
2022   if (context->Height != 192 || (context->Width != 280 && context->Width != 560))
2023   {
2024     Warning_message("Picture must be 280x192 (HGR) or 560x192 (DHGR)");
2025     return;
2026   }
2027   if (context->Width == 560)
2028     is_dhgr = 1;
2029 
2030   file = Open_file_write(context);
2031   if (file == NULL)
2032     return;
2033   vram[0] = calloc(8192, 1);
2034   if (vram[0] == NULL)
2035   {
2036     fclose(file);
2037     return;
2038   }
2039   if (is_dhgr)
2040   {
2041     vram[1] = calloc(8192, 1);
2042     if (vram[1] == NULL)
2043     {
2044       free(vram[0]);
2045       fclose(file);
2046       return;
2047     }
2048   }
2049   else
2050     vram[1] = NULL;
2051 
2052   Set_saving_layer(context, 0); // "monochrome" layer
2053   for (y = 0; y < 192; y++)
2054   {
2055     int i, column = 0;
2056     int offset = ((y & 7) << 10) + ((y & 070) << 4) + ((y >> 6) * 40);
2057     x = 0;
2058     bank = 0;
2059     while (x < context->Width)
2060     {
2061       byte b;
2062       if (is_dhgr)
2063         b = (Get_pixel(context, x, y) & 16) ? 0 : 0x80;
2064       else
2065         b = (Get_pixel(context, x, y) & 4) ? 0x80 : 0;
2066       for (i = 0; i < 7; i++)
2067       {
2068         b = b | ((Get_pixel(context, x++, y) & 1) << i);
2069       }
2070       vram[bank][offset + column] = b;
2071       if (is_dhgr)
2072       {
2073         if (++bank > 1)
2074         {
2075           bank = 0;
2076           column++;
2077         }
2078       }
2079       else
2080         column++;
2081     }
2082   }
2083 
2084   if (Write_bytes(file, vram[0], 8192))
2085   {
2086     if (is_dhgr)
2087     {
2088       if (Write_bytes(file, vram[1], 8192))
2089         File_error = 0;
2090     }
2091     else
2092       File_error = 0;
2093   }
2094 
2095   free(vram[0]);
2096   free(vram[1]);
2097   fclose(file);
2098 }
2099 
2100 
2101 ///////////////////////////// HP-48 Grob Files ////////////////////////////
2102 
2103 /**
2104  * HP48 addresses are 20bits (5 nibbles)
2105  * offset is in nibble (half byte)
2106  */
Read_HP48Address(const byte * buffer,int offset)2107 static dword Read_HP48Address(const byte * buffer, int offset)
2108 {
2109   dword data = 0;
2110   int i = 4;
2111   do
2112   {
2113     byte nibble;
2114     nibble = buffer[(offset + i) >> 1];
2115     if ((offset + i) & 1)
2116       nibble >>= 4;
2117     nibble &= 15;
2118     data = (data << 4) | nibble;
2119   }
2120   while (i-- > 0);
2121   return data;
2122 }
2123 
2124 /**
2125  * Test for a HP-48 Grob file
2126  */
Test_GRB(T_IO_Context * context,FILE * file)2127 void Test_GRB(T_IO_Context * context, FILE * file)
2128 {
2129   byte buffer[18];
2130   unsigned long file_size;
2131   dword prologue, size, width, height;
2132 
2133   (void)context;
2134   File_error = 1;
2135   file_size = File_length_file(file);
2136   if (!Read_bytes(file, buffer, 18))
2137     return;
2138   if(memcmp(buffer, "HPHP48-R", 8) != 0)
2139     return;
2140   prologue = Read_HP48Address(buffer+8, 0);
2141   size = Read_HP48Address(buffer+8, 5);
2142   GFX2_Log(GFX2_DEBUG, "HP48 File detected. %lu bytes prologue %05x %u nibbles\n",
2143            file_size, prologue, size);
2144   if (prologue != 0x02b1e)
2145     return;
2146   height = Read_HP48Address(buffer+8, 10);
2147   width = Read_HP48Address(buffer+8, 15);
2148   GFX2_Log(GFX2_DEBUG, " Grob dimensions : %ux%u\n", width, height);
2149   if ((file_size - 8) < ((size + 5) / 2))
2150     return;
2151   if (file_size < (18 + ((width + 7) >> 3) * height))
2152     return;
2153   File_error = 0;
2154 }
2155 
Load_GRB(T_IO_Context * context)2156 void Load_GRB(T_IO_Context * context)
2157 {
2158   byte buffer[18];
2159   byte * bitplane[4];
2160   unsigned long file_size;
2161   dword prologue, size, width, height;
2162   byte bp, bpp;
2163   FILE * file;
2164   unsigned x, y;
2165 
2166   File_error = 1;
2167   file = Open_file_read(context);
2168   if (file == NULL)
2169     return;
2170   file_size = File_length_file(file);
2171   if (!Read_bytes(file, buffer, 18))
2172   {
2173     fclose(file);
2174     return;
2175   }
2176   prologue = Read_HP48Address(buffer+8, 0);
2177   size = Read_HP48Address(buffer+8, 5);
2178   height = Read_HP48Address(buffer+8, 10);
2179   width = Read_HP48Address(buffer+8, 15);
2180   if (height >= 256)
2181     bpp = 4;
2182   else if (height >= 192)
2183     bpp = 3;
2184   else if (height >= 128)
2185     bpp = 2;
2186   else
2187     bpp = 1;
2188 
2189   GFX2_Log(GFX2_DEBUG, "HP48: %05X size=%u %ux%u\n", prologue, size, width, height);
2190 
2191   File_error = 0;
2192   Pre_load(context, width, height/bpp, file_size, FORMAT_GRB, PIXEL_SIMPLE, bpp);
2193   if (File_error == 0)
2194   {
2195     dword bytes_per_plane = ((width + 7) >> 3) * (height/bpp);
2196     dword offset = 0;
2197 
2198     if (Config.Clear_palette)
2199       memset(context->Palette, 0, sizeof(T_Palette));
2200     for (x = 0; x < ((unsigned)1 << bpp); x++)
2201     {
2202       context->Palette[x].R = context->Palette[x].G = (x * 255) / ((1 << bpp) - 1);
2203       context->Palette[x].B = 127;
2204     }
2205 
2206     // Load all bit planes
2207     for (bp = 0; bp < bpp; bp++)
2208     {
2209       bitplane[bp] = GFX2_malloc(bytes_per_plane);
2210       if (bitplane[bp])
2211       {
2212         if (!Read_bytes(file, bitplane[bp], bytes_per_plane))
2213           File_error = 1;
2214       }
2215     }
2216     // set pixels
2217     for (y = 0; y < (height/bpp) && File_error == 0; y++)
2218     {
2219       for (x = 0; x < width; x++)
2220       {
2221         byte b = 0;
2222         for (bp = 0; bp < bpp; bp++)
2223           b |= ((bitplane[bp][offset] >> (x & 7)) & 1) << bp;
2224         // invert because 1 is a black pixel on HP-48 LCD display
2225         Set_pixel(context, x, y, b ^ ((1 << bpp) - 1));
2226         if ((x & 7) == 7)
2227           offset++;
2228       }
2229       if ((x & 7) != 7)
2230         offset++;
2231     }
2232     // Free bit planes
2233     for (bp = 0; bp < bpp; bp++)
2234       free(bitplane[bp]);
2235   }
2236   fclose(file);
2237 }
2238