模拟城市中文网

 找回密码
 入住
搜索
查看: 5119|回复: 9

Format of Simcity4 Archive data files(SC4存档格式标准)

[复制链接]
发表于 2009-8-20 10:11 | 显示全部楼层 |阅读模式
再次提醒
小白慎入

如果您是想学做插件
建议您打道回府
如果您是做软工的想学习游戏制作

那么可以继续……
    ——by rszxh


Most simcity Data is as you probably know stored in various types of archive files that all have the same internal format such as DAT, SC4, SC4lot, etc. This format is proprietary to maxis and has been used in the sims online as well as this one.
Header (96 bytes)
File 1
File 2
File n
Index Entry 1 (20 bytes)
Index Entry 2
Index Entry n

Header first, individual files following with no filenames and a small file header area at the beginning of each followed by an index of all the files in the archive at 20 bytes per entry.

Header:

Offset 00 - Identifier (DBPF - the type of dat)
Offset 04 - Version Major (1 in SC4/Ts2 Dats)
Offset 08 - Version Minor (0 in sc4 dats, 1 in most TS2 packages)
Offset 12 - 3 DWORDS of unused data. RESERVED for maxis use.
Offset 24 - Date Created in Hex (Unused in Version 1.1)
Offset 28 - Date Modified in Hex (Unused in Version 1.1)
Offset 32 - Index Type/Version (Always 7 in SC4/TS2 dats)
Offset 36 - Number of entries in the index
Offset 40 - Location of first index entry
Offset 44 - Size of index
Offset 48 - Number of Hole entries in the Hole Record
Offset 52 - Location of the hole Record
Offset 56 - Size of the hole Record
Offset 60 - Number of Instances in Index (0x01 or 0x02; Version 1.1+ in TS2 only)
Offset 64 - 32 Bytes reserved for Future Use in other versions.

File: (File starts at offset 0 if uncompressed or 9 if compressed with this header)

Offset 00 - Size of file
Offset 04 - Compression signature (if file is compressed or not)
Offset 06 - Uncompressed filesize (Big Endian)
Offset 09 - Start of compressed/uncompressed file data


The size of an index entry with 1 Instance is 20 bytes, like this:

Offset 00 - Type ID (main type of file. picture, texture, model etc)
Offset 04 - Group ID (group of the file by purpose or type)
Offset 08 - Instance ID (marker used by the format for finding a specific file)
Offset 12 - Location of the file in the archive
Offset 16 - Size of the file

New 2 Instance Index Entry 24 bytes

Offset 00 - Type ID (main type of file. picture, texture, model etc)
Offset 04 - Group ID (group of the file by purpose or type)
Offset 08 - Instance ID (marker used by the format for finding a specific file)
Offset 12 - Instance2/Resource ID
Offset 16 - Location of the file in the archive
Offset 20 - Size of the file


One of the problems with this dat format is that filenames and filetypes are not preserved. Therefore the only way of knowing the type of file is by its IDS and then you don't have a true extension. It is for this reason that some of the filetypes to follow have names created by us instead of the true Maxis names. They simply aren't available.

A Hole record contains the location and size of all holes in a DAt file. Its format is as follows

(repeating)
DWORD - Hole Location
DWORD - Hole size

a Hole is simply garbage data that can be filled in with useful data at a later point



Compression

The idea behind the compression is to reuse previously decoded strings. For example, if the word "heureka" occurs twice in a file, the second occurence would be encoded by pointing to the first.

The compression is done by defining control characters that tells three things:


How many characters of plain text that follows that should be appended to the output.
How many characters that should be read from the already decoded text (and appended to the output)
At which offset in the aldready decoded text to read the characters.

Thus, the algorithm to decompress these files goes like this:

Read file size at offset 0
Seek to offset 9
while not end of file is reached do
{

Read next control character.
(Depending on control character read 0-3 more bytes that are a part of the control character.)
Figure out how many characters that should be read and from where by inspecting the control character.
Read 0-n characters from source and append them to the output.
Copy 0-n characters from somewhere in the output to the end of the output.
}

There are 4 types of control characters which are used with different restrictions of how many characters that can be read and from how far behind these can be read. The following conventions are used to describe them:

CC length - Length of control character.
Num plain text - Number of chars immediately after the control character that should be read and appended to output.
Num to copy - Number of chars that should be copied from somewhere in the already decoded output and added to the end of the output.
Copy offset - Where to start reading characters when copying from somewhere in the already decoded output.
This is given as an offset from the current end of the output buffer, i.e. an offset of 0 means that you should copy the last character in the output and append it to the output. And offset of 1 means that you should copy the second-to-last character.
byte0 - first byte of control character.
Bits - Bits of the control character. p = num plain text, c = num to copy, o = copy offset, i = identifier.

Note: It can sometimes be confusing when a control character states that you should copy for example 10 characters 5 steps from the end of the output. Clearly, you cannot read more than 5 characters before you reach the end of the buffer. The solution is to read and write one character at the time. Each time you read a character you copy it to the end thereby increasing the size of the output. By doing this, even offset 0 is possible and would result in duplicating the last character a number of times. This is utilized by the compression to recreate repeating text, for example bars of repeating dashes


0xE0 - 0xFF

CC length: 1 byte
Num plain text: ((byte0 & 0x1F) < < 2 ) + 4
Num to copy: 0
Copy offset: -

Bits: 111ppppp
Num plain text limit: 4-128
Num to copy limit: 0
Maximum Offset: -

This is the simplest form of control character. The only thing it does is telling how many plain text characters that follows. The formula for this is: (C - 0x7F) * 4. Thus a value of 0xE0 means that you should read 4 characters of plain text and append to the output.


0x00 - 0x7F

CC length: 2 bytes
Num plain text: byte0 & 0x03
Num to copy: ( (byte0 & 0x1C) > > 2) + 3
Copy offset: ( (byte0 & 0x60) < < 3) + byte1 + 1

Bits: 0oocccpp oooooooo
Num plain text limit: 0-3
Num to copy limit: 3-11
Maximum Offset: 1023


0x80 - 0xBF

CC length: 3 bytes
Num plain text: ((byte1 & 0xC0) > > 6 ) & 0x03
Num to copy: (byte0 & 0x3F) + 4
Copy offset: ( (byte1 & 0x3F) < < 8 ) + byte2 + 1

Bits: 10cccccc ppoooooo oooooooo

Num plain text limit: 0-3
Num to copy limit: 4-67
Maximum Offset: 16383


0xC0 - 0xDF

CC length: 4 bytes
Num plain text: byte0 & 0x03
Num to copy: ( (byte0 & 0x1C) < < 6 ) + byte3 + 5
Copy offset: (byte1 < < 8) + byte2

Bits: 110cccpp oooooooo oooooooo cccccccc

Num plain text limit: 0-3
Num to copy limit: 5-2047
Maximum Offset: 65535

Note: Sims2 uses a slightly different variation here:
CC length: 4 bytes
Num plain text: byte0 & 0x03
Num to copy: ( (byte0 & 0x0C) < < 6 ) + byte3 + 5
Copy offset: ((byte0 & 0x10) < < 12 ) + (byte1 < < 8 ) + byte2 + 1

Bits: 110occpp oooooooo oooooooo cccccccc

Num plain text limit: 0-3
Num to copy limit: 5-1028
Maximum Offset: 131072




Directory Files explained

Directory files are one of the newer filetypes I found about the beginning of May. Their purpose is to spead up the loading of a DAT file by showing exactly what is compressed inside it. They are directories of all the compressed files in an archive. This luckily makes their structure fairly simple. 4 DWORDS repeated over and over

(Repeated Chunk)

DWORD - Type ID of the file
DWORD - Group ID of the file
DWORD - Instance ID of the file
DWORD (only in new index format dbpfs) - Instance2/Resource ID
DWORD - Size of the decompressed file in Hex

These files are found as DIR/Directory by the reader and are automatically modified by it during changes to dat files.

It is HIGHLY reccommended that you modify the Directory after editing any compressed file before saving the dat if you are working manually in Hex or making your own program.

If identifying Directory files manually by Hex, their Type ID in the index will be (EF 1E 6B E8)

[ 本帖最后由 rszxh 于 2009-8-21 18:22 编辑 ]

评分

参与人数 1威望 +3 收起 理由
rszxh + 3 内容独特

查看全部评分

 楼主| 发表于 2009-8-20 10:18 | 显示全部楼层
顺便说一句,我想看懂的是这个

MAD文件格式信息

MAD video is the format of Simcity4's videos. Not really anything else to say about it. Its taken us a long time to really get started on this though, but here we are

There are video and audio blocks
The video is EA specific type
The audio is EA ASF STR Audio
The whole format is really a one block video one block audio repeat.

It has the following structure


--------------------------------------------------------------------------------
Video blocks - Hayly,Darkmatter,Karybdis

--------------------------------------------------------------------------------
Header:

DWORD - MAD* - Identifier of Block where * is a unique block type identifier :
DWORD - Size of the block
DWORD - Unknown
WORD - Suggested Buffer (in Bytes)
WORD - Frames per second (in ms delay per frame)
WORD - Pixel width of the block
WORD - Pixel height of the block
BYTE - Unknown
BYTE - Unknown
WORD - Unknown

--MAD TYPES
k = Mad pixel encoding type K. (Has 15 byte Entries., or 10 byte, 20 byte, rept)
m = Mad Pixel encoding type M. (Has 18 byte Entries.)
e = Mad Block Type E (18 byte entries)


--------------------------------------------------------------------------------
Video Data - Each video block has readable data blocks with a size dependant on its identifier (k,m). The codec breakdown is unknown, so we cant view the movies yet


= 1. .ASF/.STR Music Files (MAD Audio Blocks) - Valery V. Anisimovsky

=
The music in many new Electronic Arts games is in .ASF stand-alone files
(sometimes ASF files have extension .STR). These files have the block
structure analoguous to RIFF. Namely, these files are divided into blocks
(without any global file header like RIFFs have). Each block has the
following header:

struct ASFBlockHeader
{
  char        szBlockID[4];
  DWORD dwSize;
};
szBlockID -- string ID for the block.

dwSize -- size of the block (in bytes) INCLUDING this header.

Further I'll describe the contents of blocks of all block types in .ASF file.

When I say "block begins with..." that means "the contents of that
block (which begin just after ASFBlockHeader) begin with...".
Quoted strings are block IDs.

"SCHl": header block. This is the first block in ASF.
In the most of files this block begins with the ID string "PT\0\0" (or number
0x50540000). Further goes the PT header data which describes audio data in
the file. This PT header should be parsed rather than just read as a simple
structure. Here I give the parsing code. These functions use fread() and fseek()
stdio functions.

// first of all, we need a function which reads a small (variable) number
// bytes and composes a DWORD of them. Note that such DWORD will be a kind
// of big-endian (Motorola) stored, e.g. 3 consecutive bytes 0x12 0x34 0x56
// will give a DWORD 0x00123456.
DWORD ReadBytes(FILE* file, BYTE count)
{
  BYTE        i, byte;
  DWORD result;

  result=0L;
  for (i=0;i<count; i+ + )
  {
        fread(&byte,sizeof(BYTE),1,file);
        result<<=8;
        result+=byte;
  }

  return result;
}

// these will be set by ParsePTHeader
DWORD dwSampleRate;
DWORD dwChannels;
DWORD dwCompression;
DWORD dwNumSamples;
DWORD dwDataStart;
DWORD dwLoopOffset;
DWORD dwLoopLength;
DWORD dwBytesPerSample;
BYTE  bSplit;
BYTE  bSplitCompression;

// Here goes the parser itself
// This function assumes that the current file pointer is set to the
// start of PT header data, that is, just after PT string ID "PT\0\0"
void ParsePTHeader(FILE* file)
{
  BYTE byte;
  BOOL bInHeader, bInSubHeader;

  bInHeader=TRUE;
  while (bInHeader)
  {
        fread(&byte,sizeof(BYTE),1,file);
        switch (byte) // parse header code
        {
          case 0xFF: // end of header
           bInHeader=FALSE;
          case 0xFE: // skip
          case 0xFC: // skip
           break;
          case 0xFD: // subheader starts...
           bInSubHeader=TRUE;
           while (bInSubHeader)
           {
             fread(&byte,sizeof(BYTE),1,file);
             switch (byte) // parse subheader code
             {
               case 0x82:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwChannels=ReadBytes(file,byte);
                    break;
               case 0x83:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwCompression=ReadBytes(file,byte);
                    break;
               case 0x84:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwSampleRate=ReadBytes(file,byte);
                    break;
               case 0x85:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwNumSamples=ReadBytes(file,byte);
                    break;
               case 0x86:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwLoopOffset=ReadBytes(file,byte);
                    break;
               case 0x87:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwLoopLength=ReadBytes(file,byte);
                    break;
               case 0x88:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwDataStart=ReadBytes(file,byte);
                    break;
               case 0x92:
                    fread(&byte,sizeof(BYTE),1,file);
                    dwBytesPerSample=ReadBytes(file,byte);
                    break;
               case 0x80: // ???
                    fread(&byte,sizeof(BYTE),1,file);
                    bSplit=ReadBytes(file,byte);
                    break;
               case 0xA0: // ???
                    fread(&byte,sizeof(BYTE),1,file);
                    bSplitCompression=ReadBytes(file,byte);
                    break;
               case 0xFF:
                    subflag=FALSE;
                    flag=FALSE;
                    break;
               case 0x8A: // end of subheader
                    bInSubHeader=FALSE;
               default: // ???
                    fread(&byte,sizeof(BYTE),1,file);
                    fseek(file,byte,SEEK_CUR);
             }
           }
           break;
          default:
           fread(&byte,sizeof(BYTE),1,file);
           if (byte==0xFF)
              fseek(file,4,SEEK_CUR);
           fseek(file,byte,SEEK_CUR);
        }
  }
}
dwSampleRate -- sample rate for the file. Note that headers of most of
ASFs/MUSes I've seen DO NOT contain sample rate subheader section. Currently
I just set sample rate for such files to the default: 22050 Hz. It seems to
work okay.

dwChannels -- number of channels for the file: 1 for mono, 2 for stereo.
If this is NOT set by ParsePTHeader, then you may use the default: stereo.

dwCompression -- Compression tag. If this is 0x00, then no compression is
used and audio data is signed 16-bit PCM. If this is 0x07, the audio data is
compressed with EA ADPCM algorithm. Please read the next section for the
description of EA ADPCM decompression scheme. In some files this tag is
omitted -- I use 0x00 (no compression) for them.

dwNumSamples -- number of samples in the file.

dwDataStart -- in ASF files this's not used.

dwLoopOffset -- offset when looping (from start of sound part).

dwLoopLength -- length when looping.

dwBytesPerSample -- bytes per sample (Default is 2). Divide this by
dwChannels to get resolution of sound data.

bSplit -- this looks like to be 0x01 for files using "split" SCDl blocks
(see below). If this subheader field is absent, the file uses "normal"
(interleaved) SCDl blocks.

bSplitCompression -- this looks like to be 0x08 for files using non-compressed
"split" SCDl blocks. If this subheader field is absent in the file using
"split" SCDls, the file uses EA ADPCM compression. This subheader field
should not appear in a file using "normal" (interleaved) SCDls.

"SCCl": count block. This block goes after "SCHl" and contains one DWORD
value which is a number of "SCDl" data blocks in ASF file.

"SCDl": data block. These blocks contain audio data. Depending on the
parameters set in the header (see above) SCDl block may contain compressed
(by EA ADPCM or IMA ADPCM) or non-compressed audio data and the data itself
may be interleaved or split (see below).

If no compression is used and the file does not use "split" SCDl blocks,
SCDl block begins with a DWORD value which is the number of samples in this
block and after that comes signed 16-bit PCM data, in the interleaved form:
LRLR...LR (L and R are 16-bit sample values for left and right channels).

Hereafter by "chunk" I mean the audio data in the "SCDl" data block, that is,
compressed/non-compressed data which starts after chunk header.

In the newer EA games (NHL'2000/NBA'2000/FIFA'99'2000/NFS5) non-compressed
"split" SCDl blocks are used. These blocks begin with a chunk header:

struct ASFSplitPCMChunkHeader
{
  DWORD dwOutSize;
  DWORD dwLeftChannelOffset;
  DWORD dwRightChannelOffset;
}
dwOutSize -- size of audio data in this chunk (in samples).

dwLeftChannelOffset, dwRightChannelOffset -- offsets to PCM data for
left and right channels, relative to the byte which immediately follows
ASFSplitPCMChunkHeader structure. E.g. for left channel this offset is zero
-- the data starts immediately after this structure.

After this structure comes PCM data for stereo wavestream and it's not
interleaved (LRLRLR...), but it's split: first go sample values for left
channel, then -- for right channel, that is the layout is LL...LRR...R.

If EA ADPCM (or IMA ADPCM) compression is used, but the file does not use
"split" SCDls, each SCDl block begins with a chunk header:

struct ASFChunkHeader
{
  DWORD dwOutSize;
  SHORT lCurSampleLeft;
  SHORT lPrevSampleLeft;
  SHORT lCurSampleRight;
  SHORT lPrevSampleRight;
};
dwOutSize -- size of decompressed audio data in this chunk (in samples).

lCurSampleLeft, lCurSampleRight, lPrevSampleLeft, lPrevSampleRight are initial
values for EA ADPCM decompression routine for this data block (for left and right
channels respectively). I'll describe the usage of these further when I get to
EA ADPCM decompression scheme.

Note that the structure above is ONLY for stereo files. For mono there're
just no lCurSampleRight, lPrevSampleRight fields.

If IMA ADPCM compression is used, the meanings of some chunk header fields
are different -- see my EA-ASF.TXT specs for details.

After this chunk header the compressed data comes. See the next section for
EA ADPCM decompression scheme description.

If EA ADPCM (or IMA ADPCM) compression is used and the file uses "split" SCDls,
each SCDl block begins with a different chunk header:

struct ASFSplitChunkHeader
{
  DWORD dwOutSize;
  DWORD dwLeftChannelOffset;
  DWORD dwRightChannelOffset;
};
SHORT lCurSampleLeft;
SHORT lPrevSampleLeft;
BYTE  bLeftChannelData[]; // compressed data for left channel goes here...
SHORT lCurSampleRight;
SHORT lPrevSampleRight;
BYTE  bRightChannelData[]; // compressed data for right channel goes here...
dwOutSize -- size of decompressed audio data in this chunk (in samples).

dwLeftChannelOffset, dwRightChannelOffset -- offsets to compressed data for
left and right channels, relative to the byte which immediately follows
ASFSplitChunkHeader structure. E.g. for left channel this offset is zero --
the data starts immediately after this structure.

lCurSampleLeft, lCurSampleRight, lPrevSampleLeft, lPrevSampleRight have the
same meaning as above, but note that these values are SHORTs.

So, use mono decoder for each channel data and then create normal LRLR...
stereo waveform before outputting.
Such (newer) files may be separated from the others by presence of 0x80 type
section in PT header (the value stored in the section is 0x01 for such files).
Some of such files also do not contain compression type (0x83) section in
their PT header.

"SCLl": loop block. This block defines looping point for the song. It
contains only DWORD value, which is the looping jump position (in samples)
relative to the start of the song. You should make the jump just when you
encounter this block.

"SCEl": end block. This block indicates the end of audio stream.

Note that in some games audio files are contained within game resources. As
a rule, such resources are not compressed/encrypted, so you may just search
for ASF file signature (e.g. "SCHl") and this will mark the beginning of audio
stream, while "SCEl" block marks the end of that stream.


2. EA ADPCM Decompression Algorithm


During the decompression four LONG variables must be maintained for stereo
stream: lCurSampleLeft, lCurSampleRight, lPrevSampleLeft, lPrevSampleRight
and two -- for mono stream: lCurSample, lPrevSample. At the beginning of each
"SCDl" data block you must initialize these variables using the values in
ASFChunkHeader.
Note that LONG here is signed.

Here's the code which decompresses one "SCDl" block of EA ADPCM compressed
stereo stream.

BYTE  InputBuffer[InputBufferSize]; // buffer containing audio data of "SCDl" block
BYTE  bInput;
DWORD dwOutSize; // outsize value from the ASFChunkHeader
DWORD i, bCount, sCount;
LONG  c1left,c2left,c1right,c2right,left,right;
BYTE  dleft,dright;

DWORD dwSubOutSize=0x1c;

i=0;

// process integral number of (dwSubOutSize) samples
for (bCount=0;bCount<(dwOutSize/dwSubOutSize);bCount++)
{
  bInput=InputBuffer[i++];
  c1left=EATable[HINIBBLE(bInput)];   // predictor coeffs for left channel
  c2left=EATable[HINIBBLE(bInput)+4];
  c1right=EATable[LONIBBLE(bInput)];  // predictor coeffs for right channel
  c2right=EATable[LONIBBLE(bInput)+4];
  bInput=InputBuffer[i++];
  dleft=HINIBBLE(bInput)+8;   // shift value for left channel
  dright=LONIBBLE(bInput)+8;  // shift value for right channel
  for (sCount=0;sCount<dwSubOutSize;sCount++)
  {
        bInput=InputBuffer[i++];
        left=HINIBBLE(bInput);  // HIGHER nibble for left channel
        right=LONIBBLE(bInput); // LOWER nibble for right channel
        left=(left<<0x1c)>>dleft;
        right=(right<<0x1c)>>dright;
        left=(left+lCurSampleLeft*c1left+lPrevSampleLeft*c2left+0x80)>>8;
        right=(right+lCurSampleRight*c1right+lPrevSampleRight*c2right+0x80)>>8;
        left=Clip16BitSample(left);
        right=Clip16BitSample(right);
        lPrevSampleLeft=lCurSampleLeft;
        lCurSampleLeft=left;
        lPrevSampleRight=lCurSampleRight;
        lCurSampleRight=right;

        // Now we've got lCurSampleLeft and lCurSampleRight which form one stereo
        // sample and all is set for the next input byte...
        Output((SHORT)lCurSampleLeft,(SHORT)lCurSampleRight); // send the sample to output
  }
}

// process the rest (if any)
if ((dwOutSize % dwSubOutSize) != 0)
{
  bInput=InputBuffer[i++];
  c1left=EATable[HINIBBLE(bInput)];   // predictor coeffs for left channel
  c2left=EATable[HINIBBLE(bInput)+4];
  c1right=EATable[LONIBBLE(bInput)];  // predictor coeffs for right channel
  c2right=EATable[LONIBBLE(bInput)+4];
  bInput=InputBuffer[i++];
  dleft=HINIBBLE(bInput)+8;   // shift value for left channel
  dright=LONIBBLE(bInput)+8;  // shift value for right channel
  for (sCount=0;sCount<(dwOutSize % dwSubOutSize);sCount++)
  {
        bInput=InputBuffer[i++];
        left=HINIBBLE(bInput);  // HIGHER nibble for left channel
        right=LONIBBLE(bInput); // LOWER nibble for right channel
        left=(left<<0x1c)>>dleft;
        right=(right<<0x1c)>>dright;
        left=(left+lCurSampleLeft*c1left+lPrevSampleLeft*c2left+0x80)>>8;
        right=(right+lCurSampleRight*c1right+lPrevSampleRight*c2right+0x80)>>8;
        left=Clip16BitSample(left);
        right=Clip16BitSample(right);
        lPrevSampleLeft=lCurSampleLeft;
        lCurSampleLeft=left;
        lPrevSampleRight=lCurSampleRight;
        lCurSampleRight=right;

        // Now we've got lCurSampleLeft and lCurSampleRight which form one stereo
        // sample and all is set for the next input byte...
        Output((SHORT)lCurSampleLeft,(SHORT)lCurSampleRight); // send the sample to output
  }
}
HINIBBLE and LONIBBLE are higher and lower 4-bit nibbles:
#define HINIBBLE(byte) ((byte) >> 4)
#define LONIBBLE(byte) ((byte) & 0x0F)
Note that depending on your compiler you may need to use additional nibble
separation in these defines, e.g. (((byte) >> 4) & 0x0F).

EATable is the table given in the next section of this document.

Output() is just a placeholder for any action you would like to perform for
decompressed sample value.

Clip16BitSample is quite evident:
LONG Clip16BitSample(LONG sample)
{
  if (sample>32767)
         return 32767;
  else if (sample<-32768)
         return (-32768);
  else
         return sample;
}
As to mono sound, it's just analoguous: dwSubOutSize=0x0E for mono and
you should get predictor coeffs and shift from one byte:
bInput=InputBuffer[i++];
c1=EATable[HINIBBLE(bInput)];        // predictor coeffs
c2=EATable[HINIBBLE(bInput)+4];
d=LONIBBLE(bInput)+8;  // shift value
And also you should process HIGHER nibble of the input byte first and then
LOWER nibble for mono sound.

Of course, this decompression routine may be greatly optimized.


3. EA ADPCM Table

LONG EATable[]=
{
  0x00000000,
  0x000000F0,
  0x000001CC,
  0x00000188,
  0x00000000,
  0x00000000,
  0xFFFFFF30,
  0xFFFFFF24,
  0x00000000,
  0x00000001,
  0x00000003,
  0x00000004,
  0x00000007,
  0x00000008,
  0x0000000A,
  0x0000000B,
  0x00000000,
  0xFFFFFFFF,
  0xFFFFFFFD,
  0xFFFFFFFC
};
发表于 2009-8-20 10:53 | 显示全部楼层
是源代码么
 楼主| 发表于 2009-8-20 11:09 | 显示全部楼层
原帖由 legojohn 于 2009-8-20 10:53 发表
是源代码么

应该是MIME格式标准
发表于 2009-8-21 09:49 | 显示全部楼层
是整个SimCity 4.exe的吗?还是其中一部分
 楼主| 发表于 2009-8-21 09:56 | 显示全部楼层
原帖由 legojohn 于 2009-8-21 09:49 发表
是整个SimCity 4.exe的吗?还是其中一部分

这是SC4存档的格式标准。。。你译一下标题就知道了
发表于 2009-8-21 10:17 | 显示全部楼层
LZ想写存档
发表于 2009-8-21 12:43 | 显示全部楼层
原帖由 jackxu888 于 2009/8/21 10:17 发表
LZ想写存档



如果能像用 Word一样写存档就太好了
发表于 2013-4-20 09:15 | 显示全部楼层
不懂...........
回复 支持 反对

使用道具 举报

发表于 2013-6-22 11:05 | 显示全部楼层
匈牙利命名法……
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 入住

本版积分规则

小黑屋|手机版|模拟城市中文网

GMT+8, 2024-5-5 22:54 , Processed in 0.032388 second(s), 21 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表