EMPHASIS我不希望任何人对我的特殊 RLE 结构进行逆向工程。它都是开源的,我可以共享文件只是不确定我是否被允许,这是一个解决这个问题的新帖子。我有 RLE 的源代码,我有用于压缩/解压缩数据的编译器/反编译源代码。它全部用 C 语言编写。我需要为这个主要问题创建一个通用的解决方案。 RLE 具有表示变量字段值的偏移量。这些变量字段中的一半或更多以零值编码到编译/压缩的 RLE 输出文件中。我需要一种方法来计算这些偏移量,以便我可以以更合理的方式解析和编辑。我包含了一些比较编译/重新编译文件的图像,以便您了解我在说什么。 我想如果我有 RLE 源代码:
#include "common.h"
#define IMP_DEBUG
#define IMP_1BIT_RLE 25
#define IMP_4BIT_RLE 57
#define IMP_8BIT 8
#define IMP_8BIT_RLE 9
typedef struct {
u2 Type; // Sprite Type:
// 8: 8-bit uncompressed
// 9: 8-bit RLE packed
// 25: 1-bit RLE packed
// 57: 4-bit RLE-packed image???
u1 Unknown1; // never seen it other than 1 (shadow key or version?)
u1 ColorKey; // when it takes values other than 0, image has special purpose
u2 Width; // virtual Width
u2 Height; // virtual Height
u4 PaletteOffset; // from start of file
// Following is funny
// When Type=25 or Type=57, it contains offset to a field, 8 or 16 bytes in
// length, just after palette and before frame data.
// There are various evidences, that this field contains color map indices
// for Type=57 it contains 16 indices in sequence from 0 to 15,
// for type=25 it contains only 0 and 1 + padding 0-bytes
// otherwise it contains nonsense text garbage. A few examples:
// "Anim", "All", "Buil" or "E:\1", ": 1)", "spr )", "c.SP", "D:\s", "p1c.",
// "p3b", "Ccke", "ccla", "aala", "\ele", "PR\A", "Spri", "Full", "mpre",
// "E:\", "Read", "\air" "b' b", "Aabr", "4MB", "24MB", "Edit", "twr1",
// "mp' ", "comp", "docu"
// That is why malloc considered harmful to your security
u4 PaletteOffset2;
u4 Unknown3;
u4 Unknown4;
u2 Unknown5;
u2 NumSequences;
u4 SequencesOffset;
//Sequence Sequences[NumSequences];
// Sequence represents specific animation (like movement or spellcasting),
// together with facings
//Facing Facings[]; // directions, sprite can face (some are mirrored)
//Facing Frames[]; // frame headers
//u1 Palette[256*4]; // RGBA palette:
// index 0 used for transparency,
// index 1 is shadow
//Data[] // all frames compressed or uncompressed data
//HotSpot HPs[]; // hotspot (selection) at the end of the file
} __attribute__ ((packed)) Header;
typedef struct {
u4 Unknown1; // this looks similar to pairs of XY offsets.
// sample values:
// #10f8000, #10f8004, #1088000, #1088004
u4 Unknown2; // never seen it other than #FF (-1?)
u1 Unknown3; // never seen it other than 0
u2 Unknown4; // never seen it other than 0
u1 Size; // length of sequence
u4 Offset; // offset of facing groups (directions)
} __attribute__ ((packed)) Sequence;
// Facings go clockwise
typedef struct {
u2 Unknown1; // never seen it other than 0
u2 Size;
u4 Offset;
} __attribute__ ((packed)) Facing;
typedef struct {
u1 Type; // 0=normal, 8=duplicate-back-reference
u1 HSType; // What kind of value HSpot holds:
// 0: packed 16-bit DispX and DispY (both signed)
// 2: offset to HotSpot structure
// 3: offset to HotSpot structure (how is it different from 2?)
// 4: offset to HotSpot structure (how is it different from 2?)
u2 Width; // real width
u2 Height; // real height
u2 Size; // compressed size, or uncompressed, if Type=8 or Header->Type=9
// should be aligned to 4-bytes. Unsure about Header->Type=25
// some IMPs, like missile/spl03ap.imp, have it zeroed.
// we dont use it for anything.
u4 HSpot; // Hot Spot: offset or packed Disp XY-pair
u4 Offset; // offset or number of duplicating frame
// Note: duplicates used for animation delay. Don't simply strip them.
} __attribute__ ((packed)) Frame;
typedef struct {
s2 Unknown1;
s2 DispX; // XY displacement from virtual Width and Height
s2 DispY; // It's where unit's feet are
s2 Unknown2;
s2 HotX; // click-point for cursors
s2 HotY; // unsure what it does for unit's (missile spawning place?)
s2 Unknown3;
s2 Unknown4;
} __attribute__ ((packed)) HotSpot;
#define MAX_FRAMES (16*1024)
#define MAX_SEQS 1024
static Frame *Frames[MAX_FRAMES];
static char *SeqNames[MAX_SEQS];
static char *downcase(char *t) {
char *s = t;
while(*s) {if(isupper(*s)) *s = tolower(*s); s++;}
return t;
}
static char *impTypeName(int Type) {
if(Type == IMP_8BIT) return "8-bit";
else if (Type == IMP_8BIT_RLE) return "8-bit, RLE-compressed";
else if (Type == IMP_1BIT_RLE) return "1-bit, RLE-compressed";
else if (Type == IMP_4BIT_RLE) return "4-bit, RLE-compressed";
return "unknown format";
}
spr *impLoad(char *Input) {
FILE *Ds;
pic *A, *B;
u1 *D, *P, *M;
int I, J, K, L, C, N;
char Tmp[1024];
int NumFrames;
Header *H;
Frame *F;
Facing *FC;
Sequence *Seqs;
HotSpot *HS;
spr *S = sprNew();
int Sz = fileSize(Input);
unless (H = readFile(0, sizeof(Header), Input)) {
printf("Invalid IMP file: %s\n", Input);
abort();
}
#ifdef IMP_DEBUG
printf("Type: %d\n", H->Type);
printf("Unknown1: #%x\n", H->Unknown1);
printf("ColorKey: #%x\n", H->ColorKey);
printf("Width: %d\n", H->Width);
printf("Height: %d\n", H->Height);
printf("PaletteOffset: #%x\n", H->PaletteOffset);
printf("PaletteOffset2: #%x\n", H->PaletteOffset2);
printf("Unknown3: #%x\n", H->Unknown3);
printf("Unknown4: #%x\n", H->Unknown4);
printf("NumSequences: %d\n", H->NumSequences);
printf("SequencesOffset: #%x\n", H->SequencesOffset);
printf("\n");
#else
printf("%dx%d Type%d (%s), %d animations, Key=%d\n"
,H->Width, H->Height, H->Type, impTypeName(H->Type)
,H->NumSequences, H->ColorKey);
#endif
strcpy(Tmp, Input);
strcpy(Tmp+strlen(Tmp)-3, "h");
if (Ds = fopen(Tmp, "r")) {
char *P, *Q;
I = -1;
while(fgets(Tmp, 1024, Ds)) {
unless(!strncmp("#define ", Tmp, 7)) continue;
if(I == -1) {I=0; continue;}
P = Tmp+8;
while(isalnum(*P++));
Q = P;
while(isalnum(*P) || *P == '_') P++;
*P = 0;
SeqNames[I++] = downcase(strdup(Q));
}
} else {
printf("No %s: proceeding without animation names\n", Tmp);
times(I, H->NumSequences) SeqNames[I] = "";
}
D = readFile(0, Sz, Input);
P = D + H->PaletteOffset;
// normalize palette to 256 32bit RGB colors
S->Palette = ns(u1, 256*4);
times (I, 256) {
S->Palette[I*4+0] = P[I*4+2];
S->Palette[I*4+1] = P[I*4+1];
S->Palette[I*4+2] = P[I*4+0];
S->Palette[I*4+3] = 0;
}
S->ColorKey = H->ColorKey;
S->Palette[S->ColorKey*4+3] = 255;
//sprintf(Tmp, "%s/palette.pcx", Output);
//pcxSavePalette(Tmp, S->Palette);
NumFrames = 0;
Seqs = (Sequence*)(D+H->SequencesOffset);
S->NAnis = H->NumSequences;
S->Anis = ns(ani, S->NAnis);
times(I, S->NAnis) {
#ifdef IMP_DEBUG
printf("%d:%s: Length=%d Offset=#%x U1=#%x U2=#%x U3=#%x U4=#%x\n"
, I, SeqNames[I], Seqs[I].Size, Seqs[I].Offset
, Seqs[I].Unknown1, Seqs[I].Unknown2, Seqs[I].Unknown3, Seqs[I].Unknown4);
#endif
S->Anis[I].Name = strdup(SeqNames[I]);
S->Anis[I].NFacs = Seqs[I].Size;
S->Anis[I].Facs = ns(fac, S->Anis[I].NFacs);
times(J, S->Anis[I].NFacs) {
FC = (Facing*)(D + Seqs[I].Offset + J*sizeof(Facing));
#ifdef IMP_DEBUG
printf(" %d: Offset=#%x Size=#%x U1=#%x\n"
,J, FC->Offset, FC->Size, FC->Unknown1);
#endif
S->Anis[I].Facs[J].NPics = FC->Size;
S->Anis[I].Facs[J].Pics = ns(pic*, S->Anis[I].Facs[J].NPics);
times(K, S->Anis[I].Facs[J].NPics) {
F = (Frame*)(D + FC->Offset + K*sizeof(Frame));
#ifdef IMP_DEBUG
printf(" %d: Type=%d Offset=#%x Size=#%x Width=%d Height=%d HSType=#%x HS=#%x\n"
,K, F->Type, F->Offset, F->Size, F->Width, F->Height
,F->HSType, F->HSpot);
#endif
if(F->Type==8) continue; //F->Offset = Frames[F->Offset]->Offset;
Frames[NumFrames++] = F;
P = D + F->Offset;
A = picNew(F->Width, F->Height, 8);
//sprintf(Tmp, "%s/%02d-%s-%02d-%03d.bin", Output, I, SeqNames[I], J, K);
//writeFile(0, F->Size || Sz-F->Offset, Tmp, O);
if (H->Type == IMP_8BIT) {
// uncompressed
memcpy(A->D, P, A->H*A->W);
} else if (H->Type == IMP_8BIT_RLE) {
// missile/csp02ap.imp is a little unusual and uses H->ColorKey
// bulding/aabrks0b.imp has a strange chunk of pixels to the right
for(L = 0; L < F->Width*F->Height; ) {
C = (s1)*P++;
if(C<0) {
C = -C;
//printf("copy %d\n", C);
while(C--) A->D[L++] = *P++;
} else {
C = C + 3;
//printf("run %d\n", C);
while(C--) A->D[L++] = *P;
P++;
}
}
} else if(H->Type == IMP_1BIT_RLE) {
// missile/stickaps.imp uses it
M = malloc(A->H*A->W+0xffff);
for(L = 0; L < (A->W*A->H+7)/8; ) {
C = (s1)*P++;
if(C<0) {
C = -C;
//printf("copy %d\n", C);
while(C--) M[L++] = *P++;
} else {
C = C + 3;
//printf("run %d\n", C);
while(C--) M[L++] = *P;
P++;
}
}
P = M;
for(C = L = 0; L < A->W*A->H; L++) {
A->D[L] = (*P>>C++)&1;
if(C == 8) {P++; C = 0;}
}
free(M);
} else if(H->Type == IMP_4BIT_RLE) {
// aicr5aa.imp uses it
continue;
} else {
continue;
}
HS = n(HotSpot);
if (F->HSType == 0) {
HS->DispX = (s2)((F->HSpot)&0xffff);
HS->DispY = (s2)((F->HSpot>>16)&0xffff);
} else if (F->HSType == 2 || F->HSType == 3 || F->HSType == 4) {
memcpy(HS, D+F->HSpot, sizeof(HotSpot));
}
#ifdef IMP_DEBUG
printf(" HotSpot: X=%d Y=%d DX=%d DY=%d U1=%d U2=%d U3=%d U4=%d\n"
,HS->HotX, HS->HotY, HS->DispX, HS->DispY
,HS->Unknown1, HS->Unknown2, HS->Unknown3, HS->Unknown4);
#endif
// typical render resolution at the time of LoM was 512x512
B = picNew(512,512,8);
free(B->P);
B->P = S->Palette;
B->SharedPalette = 1;
B->K = H->ColorKey;
picClear(B, B->K);
// 1 is added, as we want alignment by 2
// else sprite will be jumping like crazy
picBlt(B, A, 0
,(B->W-A->W+1)/2 + HS->DispX, (B->H-A->H+1)/2 + HS->DispY
,0, 0, A->W, A->H);
S->Anis[I].Facs[J].Pics[K] = B;
picDel(A);
}
}
}
printf("Total Frames: %d\n", NumFrames);
return S;
}
static int runP(u1 *P, int I, int N) {
return N-I >= 3 && P[I+0]==P[I+1] && P[I+1]==P[I+2];
}
static int findRun(u1 *P, int I, int N) {
int C;
for (C = 0; C < 127 && I < N && !runP(P,I,N); C++, I++);
return C;
}
static int impLineRLE(u1 *O, u1 *P, int N) {
int I, V, T, C;
for (T=I=0; I < N; ) {
C = findRun(P, I, N);
if (C) {
O[T++] = 0xFF - C + 1;
while(C--) O[T++] = P[I++];
}
if (runP(P,I,N)) {
V = P[I++];
C = 1;
while (I < N && P[I] == V && C < 127+3) {C++; I++;}
O[T++] = C-3;
O[T++] = V;
}
}
return T;
}
void impSave(char *Output, spr *S) {
int I, J, K, JJ, KK, L, N, X, Y, Z;
u1 *D = ns(u1, 8*1024*1024); // should be enough
int PaletteSet = 0;
Header *H = (Header*)D;
Frame *F;
Facing *FC;
Sequence *Seqs;
u1 *Palette;
HotSpot *HS;
H->Type = IMP_8BIT_RLE;
H->Unknown1 = 1;
H->ColorKey = S->ColorKey!=-1 ? S->ColorKey : 0;
H->NumSequences = S->NAnis;
H->SequencesOffset = sizeof(Header);
H->Width = 512;
H->Height = 512;
Seqs = (Sequence *)(D+H->SequencesOffset);
FC = (Facing*)((u1*)Seqs + sizeof(Sequence)*S->NAnis);
L = (u1*)FC - D;
times (I, S->NAnis) {
Seqs[I].Unknown2 = 0xFF;
Seqs[I].Size = S->Anis[I].NFacs;
Seqs[I].Offset = L;
L += Seqs[I].Size*sizeof(Facing);
}
F = (Frame*)(D+L);
JJ = 0;
times(I, S->NAnis) {
times(J, S->Anis[I].NFacs) {
FC[JJ].Size = S->Anis[I].Facs[J].NPics;
FC[JJ].Offset = L;
L += FC[JJ].Size*sizeof(Frame);
JJ++;
}
}
H->PaletteOffset = L;
Palette = D+H->PaletteOffset;
L += 256*4;
JJ = KK = 0;
times(I, S->NAnis) {
times(J, S->Anis[I].NFacs) {
times(K, S->Anis[I].Facs[J].NPics) {
pic *P = S->Anis[I].Facs[J].Pics[K];
if (P) {
unless (PaletteSet) {
times (Z, 256) {
Palette[Z*4+0] = P->P[Z*4+2];
Palette[Z*4+1] = P->P[Z*4+1];
Palette[Z*4+2] = P->P[Z*4+0];
}
PaletteSet = 1;
}
F[KK].Offset = L;
F[KK].Width = P->W;
F[KK].Height = P->H;
times(Y, P->H) L += impLineRLE(D+L, P->D + Y*P->I, P->W);
F[KK].Size = L - F[KK].Offset;
} else {
F[KK].Type = 8;
F[KK].Offset = KK-1;
}
KK++;
}
JJ++;
}
}
writeFile(0, L, Output, D);
free(D);
}
这是我创建的具有相应字节大小的变量字段列表,我试图为 010 Hex Editor 制作一个二进制模板但是不确定它是否不起作用,因为我在试用版但不想承诺购买如果产品没有完成我需要它做的事情:
RLE HEADER 类型:2 字节 Unknown1:1 字节 ColorKey:1 字节 宽度:2 字节 MISSING #1 高度:2 字节 MISSING #2 PaletteOffset:4 字节 PaletteOffset2:4 字节 Unknown3:4 字节 Unknown4:4 字节 Unknown5:2 字节 NumSequences:2 字节 SequencesOffset:4 字节
Sequence Unknown1(在 Sequence 结构中):4 个字节 MISSING #3 Unknown2:4 个字节 Unknown3(在 Sequence 结构中):1 个字节 Unknown4(在 序列结构):2 字节大小:1 字节偏移量:4 字节
Facing Unknown1(在 Facing 结构中):2 字节大小(在 Facing 结构中):2 字节偏移量(在 Facing 结构中):4 字节
Frame 类型(在 Frame 结构中):1 字节 HSType:1 字节 MISSING #4 宽度(在 Frame 结构中):2 字节 MISSING $5 高度(在 Frame 结构中):2 字节 MISSING #6 大小(在 Frame 结构中) ): 2 bytes MISSING #7 HS: 4 bytes MISSING #8 Offset (in Frame 结构):4 个字节
Hotspot Unknown1(在 HotSpot 结构中):2 个字节 DispX:2 个字节 MISSING #9 DispY:2 个字节 MISSING #10 Unknown2(在 HotSpot 结构):缺少 2 个字节 #11 HotX:缺少 2 个字节 #12 HotY:缺少 2 个字节 #13 Unknown3(在 HotSpot 结构中):2 个字节 Unknown4(在 HotSpot 结构中):2 个字节
这是我用来压缩/解压缩特殊 RLE 文件类型的编译器/反编译器源代码。在大多数情况下,变量字段几乎都是静态的。 Header 变量字段是静态的。 Sequences 变量取决于 NumSequences 的值,因此它的长度可以变化,但它在 RLE 中的位置是静态的,只是可变的。 Facing 结构的变量也是如此,否则它们在 RLE 数据顶部附近是静态的。 我在解析和编辑这些变量字段时的主要问题来自 RLE 的最后一个结构。 RLE 源代码中的 Frame 和 Hotspot 结构似乎分散在整个编码中,因此很难定位和更改。这两个结构也代表了所有缺失变量字段的一半丢失的地方。
这里是编译器/反编译器的源代码:
#include "common.h"
#define LOMUT_VERSION "0.1"
char *Input, *Output;
u1 MPQMagic[] = {0x4D, 0x50, 0x51, 0x1A};
// FIXME: test IMP saving code more
// http://download.descent-network.com/ddn/sources/descent1/original/d1srcpc.exe
int main(int ArgC, char **ArgV) {
spr *S;
pic *P;
fileList *FL;
char *Q;
int I, J, K;
u1 *H;
char Ext[16];
char Tmp[1024];
char *ProgDir;
char *ProgName;
if (Q = strrchr(ArgV[0], '/')) {
strncpy(Tmp, ArgV[0], Q-ArgV[0]);
ProgName = strdup(Q+1);
Tmp[Q-ArgV[0]] = 0;
ProgDir = strdup(Tmp);
} else {
ProgName = ArgV[0];
ProgDir = ".";
}
unless (ArgC == 3) {
printf("Lords of Magic Utility v%s (C) 2011 SNV\n"
"\n"
"Usage: %s <Input.imp> <OutputDirectory> ; extract all frames\n"
" %s <InputDirectory> <Output.imp> ; compile IMP from frames\n"
" %s <Input.lbm> <Output.pcx> ; convert LBM to PCX\n"
" %s <Input.pcx> <Output.lbm> ; create LBM\n"
" %s <Input.mpq> <OutputDirectory> ; extract all files\n"
" %s <InputDirectory> <Output.mpq> ; create MPQ\n"
"\n"
"Note1: IMP frames are expected to be 512x512 8-bit images\n"
"Note2: Only PBMs LBM are supported\n"
"Note3: use unix-style path separators '/', not '\\'\n"
"Example:\n"
" for i in data/portrait/*.lbm; do ./lomut $i out/$i.pcx; done\n"
,LOMUT_VERSION, ProgName,ProgName,ProgName,ProgName,ProgName,ProgName);
exit(-1);
}
Input = ArgV[1];
Output = ArgV[2];
if (strlen(Output)>4) strcpy(Ext, Output+strlen(Output)-4);
else Ext[0] = 0;
if (!strcmp(Ext, ".imp")) {
S = sprCompile(Input, 1);
impSave(Output, S);
sprDel(S);
return 0;
}
if (!strcmp(Ext, ".lbm")) {
P = pcxLoad(Input);
lbmSave(Output, P);
picDel(P);
return 0;
}
if (!strcmp(Ext, ".mpq")) {
FL = getFileList(Input);
mpqCompile(Output, FL);
freeFileList(FL);
return 0;
}
unless (H = readFile(0, 16, Input)) {
printf("Invalid input file: %s\n", Input);
abort();
}
if (!memcmp(H, "FORM", 4)) { // ILBM file?
P = lbmLoad(Input);
pcxSave(Output, P);
picDel(P);
return 0;
}
if (!memcmp(H, MPQMagic, 4)) {
sprintf(Tmp, "%s/%s", ProgDir, "listfile.txt");
mpqExtractAll(Tmp, Input, Output);
return 0;
}
S = impLoad(Input);
sprSaveFrames(Output, S);
return 0;
}
如您所见,此编译器缺乏定义和修改这些字段的能力,因此它具有另一个功能,该功能可以让用户在编码时为变量字段定义这些值,但未成功。
这就是为什么另一个程序最适合解析和编辑这些字段的原因。我尝试编写的程序应该将十六进制偏移位置保存在二进制文件或 CSV 文件中,这样至少我不会手动搜索。即使是为所有这些字段提供我可以调整的默认值的方法也可以。我觉得有很多解决方案涉及变通或聪明的思考,但这是我能想到的最好的。
RLE 文件类型是.imp,它就像一个.gif 文件,将图像文件的各个帧编译成它。这是特殊图像文件类型的 RLE 源代码,如果它很重要,就会被编译:
#include "common.h"
typedef struct {
u1 Manufacturer; // set to 10 = ZSoft
u1 Version; // 0 = Paintbrush v2.5
// 2 = Paintbrush v2.8 w palette
// 3 = Paintbrush v2.8 w/o palette
// 4 = Paintbrush for Windows
// 5 = Paintbrush v3.0+
u1 Encoding; // 1 = RLE
u1 BPP; // bits per pixel, 1, 2, 4 or 8 (per plane)
u2 XMin;
u2 YMin;
u2 XMax;
u2 YMax;
u2 HDpi;
u2 VDpi;
u1 ColorMap[48];
u1 Reserved; // set to 0
u1 NPlanes; // number of color planes (like R, G and B)
u2 BytesPerLine;
u2 PaletteInfo; // 1 = Color/BW, 2 = Grayscale
u2 HScreenSize;
u2 VScreenSize;
u1 Filler[54]; // set to 0
} __attribute__ ((packed)) PCXHeader;
pic *pcxLoad(char *FileName) {
pic *P;
int I, C, Sz;
u1 *M, *D;
PCXHeader *PCX;
Sz = fileSize(FileName);
D = readFile(0, Sz, FileName);
unless(D) {
printf("Cant to open %s\n", FileName);
abort();
}
PCX = (PCXHeader *)D;
P = picNew(PCX->XMax-PCX->XMin+1, PCX->YMax-PCX->YMin+1, PCX->BPP);
M = D+Sz-256*3;
times (I, 256) {
P->P[I*4+0] = M[I*3+0];
P->P[I*4+1] = M[I*3+1];
P->P[I*4+2] = M[I*3+2];
P->P[I*4+3] = 0;
}
M = D+sizeof(PCXHeader);
for(I = 0; I < P->W*P->H; ) {
C = *M++;
if ((C&0xC0) != 0xC0) P->D[I++] = C;
else {
C ^= 0xC0;
while(C-- > 0) P->D[I++] = *M;
M++;
}
}
return P;
}
static int pcxLineRLE(FILE *F, u1 *P, int N) {
int I, V, T, C;
for (T=I=0; I < N; ) {
V = P[I++];
C = 1;
while (I < N && P[I] == V && C < 63) {C++; I++;}
if (C == 1 && (V&0xC0) != 0xC0) {
putc(V, F);
T += 1;
} else {
putc(C|0xC0, F);
putc(V, F);
T += 2;
}
}
return T;
}
void pcxSave(char *File, pic *P) {
int I, Y;
FILE *F;
PCXHeader PH;
memset(&PH, 0, sizeof(PCXHeader));
PH.Manufacturer = 10;
PH.Version = 5;
PH.Encoding = 1;
PH.BPP = 8;
PH.XMax = P->W-1;
PH.YMax = P->H-1;
PH.HDpi = PH.XMax;
PH.VDpi = PH.XMax;
PH.NPlanes = 1;
PH.BytesPerLine = P->W;
PH.PaletteInfo = 1;
writeFile(0, 0, File, File);
F = fopen(File, "wb");
fwrite(&PH, 1, sizeof(PCXHeader), F);
times(Y, P->H) pcxLineRLE(F, P->D+Y*P->I, P->W);
fputc(0x0C, F); // VGA palette ID
times(I, 256) {
fputc(P->P[I*4+0], F);
fputc(P->P[I*4+1], F);
fputc(P->P[I*4+2], F);
}
fclose(F);
}
void pcxSavePalette(char *File, u1 *Palette) {
int I;
pic *P = picNew(16,16,8);
times(I, 256) P->D[I]=I;
pcxSave(File, P);
picDel(P);
}
我已经制作了这个 C 程序,它应该为每个字段移动指针和存储偏移量,但我的代码是垃圾,它不会产生二进制文件输出,所以我可以为我反编译/解压缩的每个文件保存偏移量。如果我能做到这一点,我可以编写其他使用这些偏移量的解决方案:
#include <stdio.h>
#include <stdlib.h>
// Function to locate variable-length fields in the compressed data
void findVariableFields(unsigned char* compressedData, int fileSize);
// Function to decompress the compressed data
int decompressData(unsigned char* compressedData, unsigned char* decompressedData, int fileSize);
int main() {
// Open input file
FILE* file = fopen("example.imp", "rb");
if (file == NULL) {
printf("Failed to open file\n");
return 1;
}
// Get file size
fseek(file, 0, SEEK_END);
int fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
// Allocate memory for compressed and decompressed data
unsigned char* compressedData = malloc(fileSize);
unsigned char* decompressedData = malloc(fileSize * 8);
// Read compressed data
fread(compressedData, fileSize, 1, file);
fclose(file);
// Find variable-length fields in the compressed data
findVariableFields(compressedData, fileSize);
// Decompress the compressed data
int decompressedSize = decompressData(compressedData, decompressedData, fileSize);
// Output decompressed data to a binary file
FILE *outFile = fopen("output.bin", "wb");
fwrite(decompressedData, decompressedSize, 1, outFile);
fclose(outFile);
// Free allocated memory
free(compressedData);
free(decompressedData);
return 0;
}
void findVariableFields(unsigned char* compressedData, int fileSize) {
int i = 0;
while (i < fileSize) {
unsigned char c = compressedData[i++];
if (c >= 0x80) {
if (c == 0x80) {
// End of line
i += (8 - (i % 8)) % 8; // Pad to byte boundary
} else {
// Variable-length field
int fieldSize = c - 256;
unsigned char fieldType = compressedData[i++];
printf("Found variable-length field of type 0x%02X and size %d bytes at offset 0x%04X\n", fieldType, fieldSize, i);
i += fieldSize - 1;
}
} else if (c > 0) {
// Compressed run
i++;
} else {
// Uncompressed run
int runSize = compressedData[i++];
i += runSize;
}
}
}
int decompressData(unsigned char* compressedData, unsigned char* decompressedData, int fileSize) {
int i = 0;
int j = 0;
while (i < fileSize) {
unsigned char c = compressedData[i++];
if (c < 128) {
// Uncompressed run
for (int k = 0; k <= c; k++) {
decompressedData[j++] = compressedData[i++];
}
} else if (c > 128 && c < 256) {
// Compressed run
unsigned char pixel = compressedData[i++];
int count = c - 128;
for (int k = 0; k < count; k++) {
decompressedData[j++] = pixel;
}
} else if (c == 0x80) {
// End of line
j += (8 - (j % 8)) % 8; // Pad to byte boundary
} else {
// Variable-length field
int fieldSize = c - 256;
i++; // Skip field type byte
i += fieldSize - 1; // Skip variable field data
}
}
return j;
}