FreeCNC

FreeCNC - Linux Software and Games reviews

Mix Format

admin @ 9:05 am

Mix Format

This explains the MIX file format used by Tiberian Dawn and Red Alert for data storage.

Written by Thomas Johansson.

File Layout

The first thing in the archive is the header. It looks like this:

Data Type Field Name Description
uint16 file_count Amount of files in the archive
uint32 data_size Size of mix archive in bytes, not including header and index

Following the header is the index, which is file_count file records, which have the following layout:

Data Type Field Name Description
uint32 id File id, see below how to compute this
uint32 offset Offset in bytes of the file in the archive, this is from the end of the index
uint32 size Size of the file in bytes

Following the index is the actual file data. It is simply the raw bytes, there is no compression.

This means that to get the actual offset of a file, you simply do: (file_count * 12) + 6 + offset

Computing the file ID

The original mix id algorithm only supports 8.3 style filenames, so 12 chars max.

To compute the ID you first zero-pad the filename up to 12 chars. You then walk the name in steps of 4 bytes, until you hit a 0. In other words you compute either 4, 8 or 12 bytes. For each step, first rotate the current id 1 bit to the left. Then cast the next 4 bytes to a 32 bit integer, and add it to the id.

# Python function to compute a mix id
 
def compute_id(filename):
  """
  Calculates a mix id from filename.
 
  filename: The filename to encode. Must be <= 12 chars.
  returns: The computed id.
  """
  if len(filename) > 12:
     raise Error, "'filename' must not exceed 12 characters in length"
 
  # Prepare filename
  s = filename.upper().ljust(12, '\0')
 
  # Compute ID
  id = 0
  for i in xrange(0, 12, 4):
      if s[i] != '\0':
          # Rotate 1 bit to the left
          id = ((id<<1) | ((id>>31) & 1))
          # Add the new value
          id += struct.unpack("<L", s[i:i+4])[0]
      else:
          break
 
  # Truncate to 32 bits
  id &= 0xFFFFFFFF
 
  return id
//
// Sample C application to calculate a mix id
//
 
#include <stdio.h>
#include <ctype.h>
 
#define ROL(n) ((n<<1) | ((n>>31) & 1))
 
long calc_id(char *fname)
{
  long calc;
  int i;
  char buffer[13];
  for (i=0; *fname!='\0' && i<12; i++)
    buffer[i]=toupper(*(fname++));
  while(i<13) buffer[i++]=0;
 
  calc=0;
  for(i=0;buffer[i]!=0;i+=4)
    calc=ROL(calc)+*(long *)(buffer+i);
  return calc;
}
 
void main()
{
  printf("ID = %lXn",calc_id("B1.DES"));
}
<pre>
 
<pre>
'Sample VB.Net Module To Calculate Mix ID 
 
    Private Declare Sub CopyMemoryCVL Lib "Kernel32" Alias "RtlMoveMemory" (ByRef hDest As Integer, ByVal hSource As String, ByVal iBytes As Integer)
 
    Public Function GetID(ByVal strFile As String) As UInt32
        Dim FArray(0 To 11) As UInt16
        Dim i As Integer
        Dim CurrentID As UInt32
        Dim PointID As UInt32
 
        If Len(strFile) > 12 Then
            strFile = Mid(strFile, 1, 12)
        End If
        strFile = UCase(strFile)
        For i = 0 To 11
            FArray(i) = 0
        Next
        For i = 1 To Len(strFile)
            FArray(i - 1) = Asc(Mid(strFile, i, 1))
        Next
        For i = 0 To 11 Step 4
            PointID = CVL(Chr(FArray(i)) & Chr(FArray(i + 1)) & Chr(FArray(i + 2)) & Chr(FArray(i + 3)))
            If i <> 0 And i < Len(strFile) Then
                CurrentID = CurrentID << 1
            End If
            CurrentID = CurrentID + PointID
        Next
        GetID = CurrentID + 1
    End Function
 
    Public Function CVL(ByRef Argument As String) As Long
        Dim lTemp As Integer = 0I
        If Len(Argument) <> 4 Then
            Return Long.MinValue
        End If
        CopyMemoryCVL(lTemp, Argument, 4I)
        Return CLng(lTemp)
    End Function
  1. Some MIX archives contains file with name more then 12 characters length.
    For example file named “local mix database.dat” contain archive files names.
    I’m create Total Commander archive plugin for viewing/unpacking MIX files. Write me if you interested in it to wicked_digger@mail.ru.

    Comment by Digger — January 14, 2012 @ 4:33 am



Leave a comment

Name (required)

Mail (will not be published) (required)

Website