diff --git a/src/const.h b/src/const.h index 21b99c2d..ad2b224d 100644 --- a/src/const.h +++ b/src/const.h @@ -146,6 +146,7 @@ enum FILE_FORMATS FORMAT_PPH, FORMAT_XPM, FORMAT_ICO, + FORMAT_INFO, FORMAT_MISC, ///< Must be last of enum: others formats recognized by SDL_image }; diff --git a/src/fileformats.c b/src/fileformats.c index 5b58b670..df281427 100644 --- a/src/fileformats.c +++ b/src/fileformats.c @@ -2341,6 +2341,420 @@ void Save_IFF(T_IO_Context * context) +/////////////////////////// .info (Amiga Icons) ///////////////////////////// +typedef struct +{ // offset + word Magic; // 0 + word Version; + dword NextGadget; + word LeftEdge; // 8 + word TopEdge; + word Width; + word Height; + word Flags; // 16 + word Activation; + word GadgetType; // 20 + dword GadgetRender; // 22 + dword SelectRender; + dword GadgetText; // 30 + dword MutualExclude; + dword SpecialInfo; // 38 + word GadgetID; + dword UserData; // 44 icon revision : 0 = OS 1.x, 1 = OS 2.x/3.x + byte Type; + byte padding; + dword DefaultTool; + dword ToolTypes; + dword CurrentX; + dword CurrentY; + dword DrawerData; + dword ToolWindow; + dword StackSize; +} T_INFO_Header; + +static int Read_INFO_Header(FILE * file, T_INFO_Header * header) +{ + return (Read_word_be(file, &header->Magic) + && Read_word_be(file, &header->Version) + && Read_dword_be(file, &header->NextGadget) + && Read_word_be(file, &header->LeftEdge) + && Read_word_be(file, &header->TopEdge) + && Read_word_be(file, &header->Width) + && Read_word_be(file, &header->Height) + && Read_word_be(file, &header->Flags) + && Read_word_be(file, &header->Activation) + && Read_word_be(file, &header->GadgetType) + && Read_dword_be(file, &header->GadgetRender) + && Read_dword_be(file, &header->SelectRender) + && Read_dword_be(file, &header->GadgetText) + && Read_dword_be(file, &header->MutualExclude) + && Read_dword_be(file, &header->SpecialInfo) + && Read_word_be(file, &header->GadgetID) + && Read_dword_be(file, &header->UserData) + && Read_byte(file, &header->Type) + && Read_byte(file, &header->padding) + && Read_dword_be(file, &header->DefaultTool) + && Read_dword_be(file, &header->ToolTypes) + && Read_dword_be(file, &header->CurrentX) + && Read_dword_be(file, &header->CurrentY) + && Read_dword_be(file, &header->DrawerData) + && Read_dword_be(file, &header->ToolWindow) + && Read_dword_be(file, &header->StackSize) + ); +} + +typedef struct +{ + short LeftEdge; + short TopEdge; + word Width; + word Height; + word Depth; + dword ImageData; + byte PlanePick; + byte PlaneOnOff; + dword NextImage; +} T_INFO_ImageHeader; + +static int Read_INFO_ImageHeader(FILE * file, T_INFO_ImageHeader * header) +{ + return (Read_word_be(file, (word *)&header->LeftEdge) + && Read_word_be(file, (word *)&header->TopEdge) + && Read_word_be(file, &header->Width) + && Read_word_be(file, &header->Height) + && Read_word_be(file, &header->Depth) + && Read_dword_be(file, &header->ImageData) + && Read_byte(file, &header->PlanePick) + && Read_byte(file, &header->PlaneOnOff) + && Read_dword_be(file, &header->NextImage) + ); +} + +void Test_INFO(T_IO_Context * context) +{ + T_INFO_Header header; + char filename[MAX_PATH_CHARACTERS]; + FILE *file; + + File_error=1; + Get_full_filename(filename, context->File_name, context->File_directory); + + file=fopen(filename, "rb"); + if (file == NULL) + return; + if (Read_INFO_Header(file, &header)) + { + if (header.Magic == 0xe310 && header.Version == 1) + File_error = 0; + } + + fclose(file); +} + +static char * Read_INFO_String(FILE * file) +{ + dword size; + char * p; + if (!Read_dword_be(file, &size)) + return NULL; + p = malloc(size); + if (p == NULL) + return NULL; + if (!Read_bytes(file, p, size)) + { + free(p); + p = NULL; + } + return p; +} + +static byte * Decode_NewIcons(const byte * p, int bits, int * len) +{ + int alloc_size; + int i; + byte * buffer; + dword current_byte = 0; + int current_bits = 0; + + alloc_size = 16*1024; + buffer = malloc(alloc_size); + if (buffer == NULL) + return NULL; + i = 0; + while (*p) + { + byte value = *p++; + if (0xd1 <= value) + { + value -= 0xd0; // RLE count + while (value-- > 0) + { + current_byte = (current_byte << 7); + current_bits += 7; + while (current_bits >= bits) + { + buffer[i++] = (current_byte >> (current_bits - bits)) & ((1 << bits) - 1); + current_bits -= bits; + } + } + continue; + } + if (0x20 <= value && value <= 0x6f) + value = value - 0x20; + else if (0xa1 <= value && value <= 0xd0) + value = value - 0x51; + else + { + Warning("Invalid value"); + break; + } + current_byte = (current_byte << 7) | value; + current_bits += 7; + while (current_bits >= bits) + { + buffer[i++] = (current_byte >> (current_bits - bits)) & ((1 << bits) - 1); + current_bits -= bits; + } + } + //buffer[i++] = (current_byte << (bits - current_bits)) & ((1 << bits) - 1); + *len = i; + return buffer; +} + + +void Load_INFO(T_IO_Context * context) +{ + static const T_Components amigaOS1x_pal[] = { +// { 85, 170, 255 }, + { 0, 85, 170 }, + { 255, 255, 255 }, + { 0, 0, 0 }, + { 255, 136, 0 }, + }; + static const T_Components amigaOS2x_pal[] = { + { 149, 149, 149 }, + { 0, 0, 0 }, + { 255, 255, 255 }, + { 59, 103, 162 }, + { 123, 123, 123 }, // MagicWB extended colors + { 175, 175, 175 }, + { 170, 144, 124 }, + { 255, 169, 151 }, + }; + T_INFO_Header header; + T_INFO_ImageHeader imgheaders[2]; + char filename[MAX_PATH_CHARACTERS]; + FILE *file; + long file_size; + word plane_line_size = 0; + word line_size = 0; + int plane; + short x_pos = 0, y_pos = 0; + int has_NewIcons = 0; + int img_count = 0; // 1 or 2 + byte * buffers[2]; + + File_error = 0; + Get_full_filename(filename, context->File_name, context->File_directory); + + file=fopen(filename, "rb"); + if (file == NULL) + { + File_error=1; + return; + } + file_size=File_length_file(file); + + if (Read_INFO_Header(file, &header) && header.Magic == 0xe310) + { + if (header.GadgetRender == 0) + File_error = 1; + if (header.DrawerData) // Skip DrawerData + if (fseek(file, 56, SEEK_CUR) != 0) + File_error = 1; + + // icons + for (img_count = 0; File_error == 0 && img_count < 2; img_count++) + { + buffers[img_count] = NULL; + if (img_count == 0 && header.GadgetRender == 0) + continue; + if (img_count == 1 && header.SelectRender == 0) + break; + if (!Read_INFO_ImageHeader(file, &imgheaders[img_count])) + File_error = 1; + else + { + plane_line_size = ((imgheaders[img_count].Width + 15) >> 4) * 2; + line_size = plane_line_size * imgheaders[img_count].Depth; + buffers[img_count] = malloc(line_size * imgheaders[img_count].Height); + for (plane = 0; plane < imgheaders[img_count].Depth; plane++) + { + for (y_pos = 0; y_pos < imgheaders[img_count].Height; y_pos++) + { + if (!Read_bytes(file, buffers[img_count] + y_pos * line_size + plane * plane_line_size, plane_line_size)) + { + File_error = 2; + break; + } + } + } + } + } + if (File_error == 0 && header.DefaultTool) + { + char * DefaultTool = Read_INFO_String(file); + if (DefaultTool == NULL) + File_error = 2; + else + { + free(DefaultTool); + } + } + if (File_error == 0 && header.ToolTypes) + { + int current_img = -1; + int width = 0; + int height = 0; + int color_count; + int bpp = 0; + + dword count; + char * ToolType; + if (Read_dword_be(file, &count)) + { + while(count > 0) + { + ToolType = Read_INFO_String(file); + if (ToolType == NULL) + break; + else + { + // NewIcons + if (strlen(ToolType) > 4 && ToolType[0] == 'I' && ToolType[1] == 'M' && ToolType[3] == '=') + { + byte * p; + int img_index = ToolType[2] - '0'; + p = (byte *)ToolType + 4; + if (img_index != current_img) + { + // image info + palette + byte * palette; + int palette_len; + + current_img = img_index; + if (*p++ == 'B') + { + context->Transparent_color = 0; + context->Background_transparent = 1; + } + else + context->Background_transparent = 0; + width = *p++ - 0x21; + height = *p++ - 0x21; + color_count = *p++ - 0x21; + color_count = (color_count << 6) + *p++ - 0x21; + for (bpp = 1; color_count > (1 << bpp); bpp++) { } + palette = Decode_NewIcons(p, 8, &palette_len); + if (palette) + { + if (Config.Clear_palette && img_index == 1) + memset(context->Palette,0,sizeof(T_Palette)); + memcpy(context->Palette, palette, palette_len); + free(palette); + } + if (img_index == 1) + { + Pre_load(context, width, height,file_size,FORMAT_INFO,PIXEL_SIMPLE, bpp); + if (context->Type == CONTEXT_MAIN_IMAGE) + { + Main.backups->Pages->Image_mode = IMAGE_MODE_ANIMATION; + Update_screen_targets(); + } + has_NewIcons = 1; + } + else + Set_loading_layer(context, img_index - 1); + x_pos = 0; y_pos = 0; + } + else + { + byte * pixels; + int pixel_count; + + pixels = Decode_NewIcons(p, bpp, &pixel_count); + if (pixels) + { + int i; + for (i = 0; i < pixel_count; i++) + { + Set_pixel(context, x_pos++, y_pos, pixels[i]); + if (x_pos >= width) + { + x_pos = 0; + y_pos++; + } + } + free(pixels); + } + } + } + free(ToolType); + } + count -= 4; + } + } + } + if (File_error == 0 && header.ToolWindow != 0) + { + char * ToolWindow = Read_INFO_String(file); + if (ToolWindow == NULL) + File_error = 2; + else + { + free(ToolWindow); + } + } + if (File_error == 0 && header.UserData == 1) + { + if (fseek(file, 8, SEEK_CUR) != 0) + File_error = 1; + } + // Glow Icon can follow... + + if (!has_NewIcons && img_count > 0) + { + if (Config.Clear_palette) + memset(context->Palette,0,sizeof(T_Palette)); + if (header.UserData == 0) + memcpy(context->Palette, amigaOS1x_pal, sizeof(amigaOS1x_pal)); + else + memcpy(context->Palette, amigaOS2x_pal, sizeof(amigaOS2x_pal)); + + Pre_load(context, header.Width, header.Height,file_size,FORMAT_INFO,PIXEL_SIMPLE, imgheaders[0].Depth); + if (context->Type == CONTEXT_MAIN_IMAGE) + { + Main.backups->Pages->Image_mode = IMAGE_MODE_ANIMATION; + Update_screen_targets(); + } + for (img_count = 0; img_count < 2 && buffers[img_count] != NULL; img_count++) + { + if (img_count > 0) + Set_loading_layer(context, img_count); + for (y_pos = 0; y_pos < imgheaders[img_count].Height; y_pos++) + Draw_IFF_line(context, buffers[img_count] + y_pos * line_size, y_pos, plane_line_size << 3, imgheaders[img_count].Depth); + free(buffers[img_count]); + buffers[img_count] = NULL; + } + } + } + else + File_error=1; + fclose(file); +} + + + //////////////////////////////////// BMP //////////////////////////////////// typedef struct { diff --git a/src/loadsave.c b/src/loadsave.c index 8a22ca3d..fe860644 100644 --- a/src/loadsave.c +++ b/src/loadsave.c @@ -170,6 +170,10 @@ void Load_PNG(T_IO_Context *); void Save_PNG(T_IO_Context *); #endif +// -- INFO (Amiga ICONS) ---------------------------------------------------- +void Test_INFO(T_IO_Context *); +void Load_INFO(T_IO_Context *); + // -- SDL_Image ------------------------------------------------------------- // (TGA, BMP, PNM, XPM, XCF, PCX, GIF, JPG, TIF, IFF, PNG, ICO) void Load_SDL_Image(T_IO_Context *); @@ -182,7 +186,7 @@ void Load_Recoil_Image(T_IO_Context *); // ENUM Name TestFunc LoadFunc SaveFunc PalOnly Comment Layers Ext Exts const T_Format File_formats[] = { - {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;2bp;pcx;pkm;iff;lbm;ilbm;sham;ham;ham6;ham8;acbm;pic;anim;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;ic2;cur;cm5;pph"}, + {FORMAT_ALL_IMAGES, "(all)", NULL, NULL, NULL, 0, 0, 0, "", "gif;png;bmp;2bp;pcx;pkm;iff;lbm;ilbm;sham;ham;ham6;ham8;acbm;pic;anim;img;sci;scq;scf;scn;sco;pi1;pc1;cel;neo;c64;koa;koala;fli;bml;cdu;prg;tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff;ico;ic2;cur;cm5;pph;info"}, {FORMAT_ALL_PALETTES, "(pal)", NULL, NULL, NULL, 1, 0, 0, "", "kcf;pal;gpl"}, {FORMAT_ALL_FILES, "(*.*)", NULL, NULL, NULL, 0, 0, 0, "", "*"}, {FORMAT_GIF, " gif", Test_GIF, Load_GIF, Save_GIF, 0, 1, 1, "gif", "gif"}, @@ -210,6 +214,7 @@ const T_Format File_formats[] = { {FORMAT_PPH, " pph", Test_PPH, Load_PPH, Save_PPH, 0, 0, 1, "pph", "pph"}, {FORMAT_XPM, " xpm", NULL, NULL, Save_XPM, 0, 0, 0, "xpm", "xpm"}, {FORMAT_ICO, " ico", Test_ICO, Load_ICO, Save_ICO, 0, 0, 0, "ico", "ico;ic2;cur"}, + {FORMAT_INFO," info",Test_INFO,Load_INFO,NULL, 0, 0, 0, "info", "info"}, {FORMAT_MISC,"misc.",NULL, NULL, NULL, 0, 0, 0, "", "tga;pnm;xpm;xcf;jpg;jpeg;tif;tiff"}, };