C&C Format80 conversion - Porting Pascal to C

Started by
3 comments, last by Toolmaker 20 years ago
I already posted about this in the lounge, but it has become more technical now. I don''t understand the conversion code concerning the format, so I decided to convert the Pascal code to C, 1 on 1. I still don''t understand how the format works, because I blindly copied the copy and changed it to C(My Pascal knowledge sucks, I forgot most of it). Now I converted the code, I am getting access violations, mainly because the first byte of the first image is 0x00. If anyone can see what I am doing wrong, any help is welcome. There article on reading a format80 decoded file can be found here http://www.geocities.com/SiliconValley/8682/ccfiles4.txt(Skip down to the Format80 header). The SHP layout can be found here http://dune2.de/download/source/duneii_shp_specs.txt Here is the code for reading the file(It''s a SHP file, but I can read it properly, I tested the data read, the headers are correct and the last BYTE of the image part is 0x80. That''s correct)

struct SHP_IMAGEHEADER
{
    BYTE cType;
    BYTE cReserved0;
    BYTE cHeight;
    BYTE cWidth;
    BYTE cReserved1;
    BYTE cHeight0;
    WORD wSize;
    WORD wChecksum;
};

struct SHP_IMAGE
{
    SHP_IMAGE() { Data = NULL; } // Constructor


    SHP_IMAGEHEADER Header;
    BYTE           *Data;
};

void ReadImage(ifstream &File, DWORD Offset, SHP_IMAGE &Image)
{
    File.seekg(Offset + 2);
    File.read((char *)&Image.Header, sizeof(SHP_IMAGEHEADER));

    // Allocate memory for the data

    Image.Data = new BYTE[Image.Header.wSize - 10];
    File.read((char *)Image.Data, sizeof(BYTE) * (Image.Header.wSize - 10));
}
And this is my decode function:

void DecodeFormat80(SHP_IMAGE &Image, BYTE *Destination)
{
    BYTE *Source;
    BYTE *Dest;
    BYTE  Com;
    int   SP = 0;
    int   DP = 0;
    int   Posit = 0;
    int   Count = 0;
    
    Source = Image.Data;
    Dest   = Destination;

    while (SP < Image.Header.cWidth * Image.Header.cHeight)
    {
        Com = Source[SP];
        SP++;

        switch (Com >> 7)
        {
            case 0:
                Count = ((Com & 0x7F) >> 4) + 3;
                Posit = ((Com & 0x0F) << 8) + Source[SP];
                ++SP;
                Posit = DP - Posit;
                for (int i = Posit; i < Posit+Count; ++i)
                {
	                Dest[DP] = Dest[i];
	                ++DP;
                }break;

            case 1:
	            switch ((Com & 0x40) >> 6)
	            {
		            case 0:
			            Count = Com & 0x3F;
			            if (Count == 0) break; // EOF Marker

			            for (int i = 0; i < Count; ++i)
			            {
				            Dest[DP] = Source[SP];
				            ++DP; ++ SP;
			            }break;

                    case 1:
                        Count = Com & 0x3F;
                        if (Count < 0x3E)
                        {
                            Count += 3;
                            Posit = (WORD)Source[SP];
                            Source += 2;
                            for (int i = Posit; i < Posit+Count; ++i)
                            {
                                Dest[DP] = Dest[i];
                                DP++;
                            }
                        }
                        else if (Count == 0x3F)
                        {
                            Count = WORD(Source[SP]);
                            Posit = WORD(Source[SP+2]);
                            SP += 4;
                            for (int i = Posit; i < Posit + Count; ++i)
                            {
                                Dest[DP] = Dest[i];
                                DP++;
                            }
                        }
                        else
                        {
                            BYTE Color;
                            Count = (WORD)Source[SP];
                            SP += 2;
                            Color = Source[SP];
                            for (int i = 0; i < Count; ++i)
                            {
                                Dest[DP] = Color;
                                DP++;
                            }
                        }break; // case 1:

	            } // switch (b6)

	            break;
        } // switch (Command)

    }
}
Toolmaker -Earth is 98% full. Please delete anybody you can.

Advertisement
As I have replied to you before, I took a quick look. The problem is that you are looping while (SP < Image.Header.cWidth * Image.Header.cHeight) and of course there''s not that many bytes in the compressed data. And even the uncompressed data offly have that many BITS. You don''t know how many bytes there is in the compressed data(source) before, so nake it an endless loop.

You probably added it because it wouldn''t break out right? That''s because you copied the source slightly wrong compare
case 0:    Count = Com & 0x3F;    if (Count == 0) break; // EOF Marker	    for (int i = 0; i < Count; ++i)    {         Dest[DP] = Source[SP];				           ++DP; ++ SP;    }break; 

to
0 : begin  {Copy as is command (1)}    Count:=Com and $3F;  {mask 2 topmost bits}    if Count=0 then break; {EOF marker}    for i:=1 to Count do    begin        Dest[DP]:=Source[SP];        Inc(DP);        Inc(SP);    end;end; 


In the pascal source the break statement breaks out of the whole loop, while it only breaks out of the switch statement for you. So, that''s what you need to fix

I changed that code, but that''s actually not the problem. The problem is, when I decompress the first file(I never get any further anyway), the data read starts with 0x00 0x00. This results in Command 0 and the posit to be -128 + 3(Posit = 0 - 128 + 3) and a count of 3 aswell. I have no clue what I am doing wrong here...

Toolmaker


-Earth is 98% full. Please delete anybody you can.

Hm... I don''t see how you can get that

Count = ((Com & 0x7F) >> 4) + 3;
should give
((0x00 & 07F) >> 4) + 3
= (0x00 >> 4) + 3
= 3

Posit = ((Com & 0x0F) << 8) + Source[SP];
should give
((0x00 & 0x0F) << 8) + 0x00
=((0x00) << 8) +0x00
=0x00 + 0x00
=0

Posit = DP - Posit;
=0-0
=0

So this would copy 3 bytes in the destination buffer, starting at position 0 to position 0. In other words the only thing it does is incresing the destination pointer by 3. Which may or may not be right.

Allthough not documented there, it''s possible that 0x00 as the first byte just means start of the commands, so try starting from source position 1 or maybe 2, by setting SP at the start
Well, after a few days I finally got back to coding. However, it still won''t work. I changed everything to WORDs since I was using signed ints. Obviously, that doesn''t cause the problem. I took the 2 second image from the file.

It would run the first case right after start. This are the results:

Count = ((Com & 0x7F) >> 4) + 3;              // Count = 3Posit = ((Com & 0x0F) << 8) + Source[SP];     // Posit = 133 ???++SP;                                         // SP = 2Posit = DP - Posit;                           // Posit = 65403 


The rest is predictable, ie, not worky...

Toolmaker


-Earth is 98% full. Please delete anybody you can.

This topic is closed to new replies.

Advertisement