Добро пожаловать, гость ( Вход | Регистрация )
| Lumis |
Mar 9 2026, 15:47
Сообщение
#1
|
|
Member ![]() ![]() Группа: Authorized Сообщений: 11 Регистрация: 2-March 26 Пользователь №: 18,038 Спасибо сказали: 11 раз(а) |
Привет. По просьбе -=CHE@TER=- перегнал в ANSI C и протестировал на EPF от Aladdin 1996 с помощью chatgpt оригинальный код распаковщика ASM + C. В его тестовой среде в докере и у меня на винде отрабатывает чисто.
CODE #include <stdio.h> #include <stdlib.h> #include <string.h> #if defined(_MSC_VER) && (_MSC_VER < 1600) typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #else #include <stdint.h> #endif #define EPFS_MAGIC 0x53465045UL #define EPFS_HEADER_SIZE 11 #define EPFS_ITEM_SIZE 22 #define LZW_FIRST_CODE 256 #define LZW_MAX_BITS 14 #define LZW_DICT_CAP 0x4680u /* from original buffers: 0x8D00 bytes / 2 */ #define LZW_STACK_CAP 0x0FA0u /* original hard stop */ typedef struct epfs_item_tag { char name[14]; uint8_t packed; uint32_t packed_size; uint32_t unpacked_size; } epfs_item; static uint16_t rd16le(const uint8_t *p) { return (uint16_t)((uint16_t)p[0] | ((uint16_t)p[1] << 8)); } static uint32_t rd32le(const uint8_t *p) { return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) | ((uint32_t)p[3] << 24); } static int read_fully(FILE *fp, void *buf, size_t size) { return fread(buf, 1, size, fp) == size; } static int write_fully(FILE *fp, const void *buf, size_t size) { return fwrite(buf, 1, size, fp) == size; } static void sanitize_name(char *s) { char *p = s; while (*p) { unsigned char c = (unsigned char)*p; if (c < 32 || c == ':' || c == '\\' || c == '/' || c == '*' || c == '?' || c == '"' || c == '<' || c == '>' || c == '|') { *p = '_'; } ++p; } if (s[0] == '\0') { strcpy(s, "NONAME.BIN"); } } /* * This is not textbook LZW. * * The reset code is (maxvalue - 1), end code is maxvalue. * The key quirk, matching the original game code: * reset clears nextcode back to 256, but DOES NOT reset bit width to 9. * * If you "fix" that into normal LZW, several real ALADDIN.EPF members fail * with bogus recursive chains and depth overflow. */ static int unlzw_epfs(uint32_t out_size, const uint8_t *src, uint32_t src_size, uint8_t *dst) { uint16_t prefix[LZW_DICT_CAP]; uint8_t suffix[LZW_DICT_CAP]; uint8_t stack[LZW_STACK_CAP]; const uint8_t *sp; const uint8_t *src_end; uint8_t *dp; uint8_t *dst_end; uint32_t bitbuf; unsigned bitcount; unsigned curbits; uint16_t maxvalue; uint16_t dicreset; uint16_t incbits; uint16_t nextcode; uint16_t prev_code; uint16_t code; uint16_t cur; uint8_t first_char; sp = src; src_end = src + src_size; dp = dst; dst_end = dst + out_size; bitbuf = 0; bitcount = 0; curbits = 9; maxvalue = (uint16_t)((1u << curbits) - 1u); dicreset = (uint16_t)(maxvalue - 1u); incbits = (uint16_t)(maxvalue - 2u); nextcode = LZW_FIRST_CODE; #define GET_CODE(out_code) \ do { \ while (bitcount < curbits) { \ if (sp >= src_end) { \ return 2; \ } \ bitbuf = ((bitbuf << 8) | (uint32_t)(*sp++)) & 0xFFFFFFFFUL; \ bitcount += 8; \ } \ bitcount -= curbits; \ (out_code) = (uint16_t)((bitbuf >> bitcount) & maxvalue); \ } while (0) #define INC_BITS_IF_NEEDED() \ do { \ if (nextcode > incbits && curbits < LZW_MAX_BITS) { \ ++curbits; \ maxvalue = (uint16_t)((1u << curbits) - 1u); \ dicreset = (uint16_t)(maxvalue - 1u); \ incbits = (uint16_t)(maxvalue - 2u); \ } \ } while (0) if (out_size == 0) { return 0; } GET_CODE(code); if (code > 0xFFu) { return 3; } *dp++ = (uint8_t)code; prev_code = code; first_char = (uint8_t)code; for (;;) { unsigned sptr; if (dp >= dst_end) { return 0; } GET_CODE(code); if (code == maxvalue) { return 0; } if (code == dicreset) { nextcode = LZW_FIRST_CODE; GET_CODE(code); if (code == maxvalue) { return 0; } if (code > 0xFFu) { return 3; } *dp++ = (uint8_t)code; prev_code = code; first_char = (uint8_t)code; continue; } sptr = 0; cur = code; if (cur >= nextcode) { if (sptr >= LZW_STACK_CAP) { return 1; } stack[sptr++] = first_char; cur = prev_code; } while (cur > 0xFFu) { if (cur >= LZW_DICT_CAP || sptr >= LZW_STACK_CAP) { return 1; } stack[sptr++] = suffix[cur]; cur = prefix[cur]; } stack[sptr++] = (uint8_t)cur; first_char = (uint8_t)cur; while (sptr != 0) { if (dp >= dst_end) { return 4; } *dp++ = stack[--sptr]; } if (nextcode < LZW_DICT_CAP) { prefix[nextcode] = prev_code; suffix[nextcode] = first_char; } ++nextcode; INC_BITS_IF_NEEDED(); prev_code = code; } #undef GET_CODE #undef INC_BITS_IF_NEEDED } static int load_item_table(FILE *fp, uint32_t table_offset, uint16_t count, epfs_item **out_items) { epfs_item *items; uint16_t i; items = (epfs_item *)calloc((size_t)count, sizeof(items[0])); if (items == NULL) { return 0; } if (fseek(fp, (long)table_offset, SEEK_SET) != 0) { free(items); return 0; } for (i = 0; i < count; ++i) { uint8_t raw[EPFS_ITEM_SIZE]; if (!read_fully(fp, raw, sizeof(raw))) { free(items); return 0; } memcpy(items[i].name, raw, 13); items[i].name[13] = '\0'; items[i].packed = raw[13]; items[i].packed_size = rd32le(raw + 14); items[i].unpacked_size = rd32le(raw + 18); } *out_items = items; return 1; } static int extract_epf(const char *path) { FILE *fp; uint8_t hdr[EPFS_HEADER_SIZE]; uint32_t magic; uint32_t table_offset; uint8_t archive_flags; uint16_t count; epfs_item *items; uint16_t i; int rc; fp = fopen(path, "rb"); if (fp == NULL) { fprintf(stderr, "error: cannot open input file: %s\n", path); return 2; } rc = 3; items = NULL; if (!read_fully(fp, hdr, sizeof(hdr))) { fprintf(stderr, "error: cannot read EPF header\n"); goto done; } magic = rd32le(hdr + 0); table_offset = rd32le(hdr + 4); archive_flags = hdr[8]; count = rd16le(hdr + 9); (void)archive_flags; if (magic != EPFS_MAGIC) { fprintf(stderr, "error: invalid EPF signature\n"); goto done; } if (!load_item_table(fp, table_offset, count, &items)) { fprintf(stderr, "error: cannot read EPF file table\n"); goto done; } if (fseek(fp, EPFS_HEADER_SIZE, SEEK_SET) != 0) { fprintf(stderr, "error: cannot seek to data area\n"); goto done; } for (i = 0; i < count; ++i) { void *packed_buf; void *out_buf; size_t packed_size; size_t out_size; char out_name[14]; packed_size = (size_t)items[i].packed_size; out_size = (size_t)(items[i].packed ? items[i].unpacked_size : items[i].packed_size); memcpy(out_name, items[i].name, sizeof(out_name)); out_name[13] = '\0'; sanitize_name(out_name); printf("%s", out_name); packed_buf = malloc(packed_size ? packed_size : 1u); if (packed_buf == NULL) { printf(" - out of memory\n"); rc = 4; goto done; } if (packed_size && !read_fully(fp, packed_buf, packed_size)) { free(packed_buf); printf(" - short read\n"); rc = 5; goto done; } if (items[i].packed) { int urc; out_buf = malloc(out_size ? out_size : 1u); if (out_buf == NULL) { free(packed_buf); printf(" - out of memory\n"); rc = 4; goto done; } memset(out_buf, 0, out_size); urc = unlzw_epfs(items[i].unpacked_size, (const uint8_t *)packed_buf, items[i].packed_size, (uint8_t *)out_buf); free(packed_buf); if (urc != 0) { free(out_buf); printf(" - unpack error %d\n", urc); rc = 6; goto done; } } else { out_buf = packed_buf; } { FILE *fo = fopen(out_name, "wb"); if (fo == NULL) { free(out_buf); printf(" - cannot create output\n"); rc = 7; goto done; } if (out_size && !write_fully(fo, out_buf, out_size)) { fclose(fo); free(out_buf); printf(" - write error\n"); rc = 8; goto done; } fclose(fo); } free(out_buf); printf("\n"); } rc = 0; done: free(items); fclose(fp); return rc; } int main(int argc, char **argv) { printf("East Point Software .EPF unpacker v2.0\n"); printf("© CTPAX-X Team 2010,2018 © Lumis 2026\nhttp://www.CTPAX-X.org/\n\n"); if (argc != 2) { printf("usage: %s <file.epf>\n", argv[0]); return 1; } return extract_epf(argv[1]); } Спасибо сказали:
|
![]() ![]() |
Lumis East Point Software .EPF file unpacker v2.0 Mar 9 2026, 15:47
-=CHE@TER=- Привет. По просьбе -=CHE@TER=- перегнал в ANSI C и... Mar 9 2026, 18:39
Lumis Отлично, рад что работает четко! Я на него пот... Mar 9 2026, 19:13
-=CHE@TER=- Огромное-преогромное спасибо!
Всё, сайт обнови... Mar 9 2026, 19:51
-=CHE@TER=- Что именно с файлами не так?Там два файла в архиве... Mar 25 2026, 15:23![]() ![]() |
| Упрощённая версия | Сейчас: 21st April 2026 - 11:38 |