Initial commit of Command & Conquer Red Alert source code.

This commit is contained in:
LFeenanEA
2025-02-27 16:15:05 +00:00
parent b685cea758
commit 5e733d5dcc
2082 changed files with 797727 additions and 0 deletions
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
+104
View File
@@ -0,0 +1,104 @@
;Codewright Project File (do not remove or modify this line)
[ProjInit]
ProjSetConfigFlags=0x00010140
[State]
SysSetCwd='C:\PROJECTS\C&C\CODE\AUDIOMAK'
SrchSetFlags=0x20aa
FileSortMode=0x13
StateWindowFrame=-1,0,1020,690,0x0981f5fa
_StateWindow=0,0,1024,657,0x00000108,'c:\projects\c&c\code\audiomak\audiomak.cpp',240,7,244,32,32,0,32,32,32,32,8,65535,65535,1,0,'8514oem',65518,255,49,0,4,243,14,15,241,252,249,560,28,400,0,246,252,245,242,0,0,0,0,0
_StateBuffer='c:\projects\c&c\code\audiomak\audiomak.cpp',0x0400048e,560,28,25,'4 7','',0x0,''
_StateBuffer='c:\projects\c&c\code\audiomak\scode.asm',0x0400048e,30,64,25,'9 17','',0x0,''
WrapEnable=0
_StateHistory=SEARCH,'UncompBuffer','saved','orig','FALSE','tasm','TASM','tasm','ASSEMBLER','Decom','.asm.'
_StateHistory=REPLACE,'audiomak','desired','long','unsigned','unsigned char','int','source'
_StateHistory=FILELIST,'c:\projects\c&c\code\audiomak\cointabl.voc','c:\projects\c&c\code\audiomak\cointabl.wav','c:\projects\c&c\code\audiomak\globals.cpp','c:\projects\c&c\code\audiomak\bfeared.aud','c:\projects\c&c\code\audiomak\audiomak.asm','d:\library\source\soundio.c','c:\projects\c&c\code\audiomak\scode.asm','d:\library\wwlib.i','c:\projects\c&c\code\audiomak\makefile','d:\library\source\makefile'
_StateHistory=GOTOMARK,'1','2','1'
_StateHistory=GOTOLINE,'364','398','424','431','465'
[Editor]
FilterDeleteList
FilterAdd='Source Files','*.c;*.h;*.asm;*.inc',-1
FilterAdd='All Files','*.*',-1
FilterAdd='C++ Source Files','*.cpp;*.h;*.asm;*.inc',-1
StateSetMarkLevel=7
ClipboardSetTermStr='\r\n',0
ClipboardEnableTermStr=1
ClipboardSetSepStr='\r\n',0
ClipboardEnableSepStr=1
ScrapSetCount=1
ExtColorsAssoc='.cpp',1
ExtIndentEnableAssoc='.cpp',1
ExtSetDelimiters=.cpp,a-zA-Z_0-9
ExtColorsAssoc='.h',1
ExtIndentEnableAssoc='.h',1
ExtSetDelimiters=.h,a-zA-Z_0-9
ExtSetDelimiters=.*,a-zA-Z_0-9
ExtColorsAssoc='.int',1
ExtIndentEnableAssoc='.int',1
ExtSetDelimiters=.int,a-zA-Z_0-9
ExtColorsAssoc='.lst',1
ExtIndentEnableAssoc='.lst',1
ExtColorsAssoc='.asm',1
ExtSetDelimiters=.asm,a-zA-Z_0-9
ExtColorsAssoc='.scr',1
ExtIndentEnableAssoc='.scr',1
ExtSetDelimiters=.scr,a-zA-Z_0-9
ExtColorsAssoc='.c',1
ExtIndentEnableAssoc='.c',1
ExtSetDelimiters=.c,a-zA-Z_0-9
ExtColorsAssoc='.ash',1
ExtSetDelimiters=.ash,a-zA-Z_0-9
ExtColorsAssoc='.i',1
ExtIndentEnableAssoc='.i',1
ExtSetDelimiters=.i,a-zA-Z_0-9
Autosave=15,15
AutosaveDir=''
ExtSetUpdateDelay=10
ExtDelayedColoring=1
ExtCommentSearchLimit=200
KeyDelay=635
KeyRepeat=190
BufSetGlobalBackupSpec='%b.bak'
_FontDefault=0,'8514oem',65513,255,49,400,0
SysSetDefault=DEFAULT_WINDOW_LEFT_MARGIN,4
SysSetDefault=DEFAULT_WINDOW_VIS_MARGIN_COL,0
SysSetDefault=DEFAULT_WINDOW_HINC,8
SysSetDefault=DEFAULT_WINDOW_VIS_VIRTSPACES,32
SysSetDefault=DEFAULT_WINDOW_VIS_VIRTLINES,32
SysSetDefault=DEFAULT_WINDOW_VIS_TABS,32
SysSetDefault=DEFAULT_WINDOW_VIS_SPACES,32
SysSetDefault=DEFAULT_WINDOW_VIS_ELISION,0
SysSetDefault=DEFAULT_WINDOW_VIS_EOL,32
SysSetDefault=DEFAULT_WINDOW_VIS_EOF,32
SysSetDefault=DEFAULT_WINDOW_SYSFLAGS,0x118
SysSetDefault=DEFAULT_BUFFER_AUTOINDENT_MODE,0x0
SysSetDefault=DEFAULT_BUFFER_BACKUP_SPEC,''
SysSetDefault=DEFAULT_BUFFER_TABS,'5 9'
SysSetDefault=DEFAULT_BUFFER_MAX_TAB,200
SysSetDefault=DEFAULT_BUFFER_MAX_VLINES,25
SysSetDefault=DEFAULT_BUFFER_SYSFLAGS,0xc800048e
_RestoreSysFlags=0x0991f5fa, 0xfffffffc
[Compiler]
BrowseSetFile='c:\projects\c&c\code\audiomak\audiomak.ptg'
TagSetFile='c:\projects\c&c\code\audiomak\audiomak.tag'
CompilerAddBuild='Microsoft Assembler',1073741880,'ftee masm -w2 -zi %r%e;','','','','','_MicrosoftErrorInfo','','%v%p','','','','','',0
CompilerAddBuild='Borland C++',1073742089,'ftee make -DDEBUG=1 %r.obj','','','','','','','','ftee make -DDEBUG=1 %r.obj','','','','',49152
CompilerAddBuild='Borland Turbo Assembler',1073741835,'ftee make -B %r.obj','','','','','','','','','','','','',16384
CompilerAddBuild='$_cw_proj_hash_$',1073741875,'','ftee maker -B -DDEBUG=1 %r.obj','ftee maker -DDEBUG=1','','','_TasmErrorInfo','proj.err','c:\projects\c&c\code\audiomak','','_BorlandCppErrorInfo','','','',197376
CompilerAddBuild='Default Project',1073741880,'','ftee make','ftee make','','','_ErrorInfoDefault','proj.err','%v%p','','','','','',0
CompilerAddBuild='Microsoft C',1073741835,'ftee cl -c -AL -Gsw -Ow -Zpe %r%e','','','','','','','','','','','','',0
CompilerAddBuild='Script',1073741880,'ftee make %r.inf','ftee make','ftee make','','','_BorlandCppErrorInfo','','','','','','','',0
CompilerAddBuild='Zortech C++',1073741880,'ftee ztc -a -b -c -g -ml -W %r%e','','','','','_ZortechCppErrorInfo','','%v%p','','','','','',0
CompilerAssign='Borland C++','.scr'
CompilerAssign='Borland C++','.int'
CompilerAssign='Borland C++','.c'
CompilerNewExt=.prg
CompilerAssign='Microsoft C','.h'
CompilerAssign='Borland C++','.cpp'
CompilerAssign='Default Project','.*'
CompilerAssign='Zortech C++','.cxx'
CompilerAssign='Borland Turbo Assembler','.asm'
CompilerAssign='Borland C++','.hpp'
+116
View File
@@ -0,0 +1,116 @@
#
# Command & Conquer Red Alert(tm)
# Copyright 2025 Electronic Arts Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
.AUTODEPEND
OBJECTS = audiomak.obj scode.obj
.cpp.obj:
bcc {$*.cpp }
.asm.obj:
tasm $<,$&.obj
audiomak.exe: turboc.cfg tasm.cfg tlink.cfg $(OBJECTS)
tlink @&&!
c0l.obj $(OBJECTS)
audiomak.exe
audiomak.map
CL.LIB MATHL.LIB EMU.LIB
!
####################################################################
# Creates the TURBOC configuration file (also affects CPP.EXE)
turboc.cfg: makefile
copy &&!
-v # Debugging output.
-y
-Vt # Virtual table pointer comes at end of class members (NEVER CHANGE).
-Vb- # Always near pointer to virtual table.
-a- # Structures are packed (not byte aligned).
-b- # Enums as small as possible.
-3 # Enable 386 instructions.
-ml # Large model.
-C- # Don't allow nested comments (DON'T CHANGE THIS).
-c # Just compile -- don't link.
-Jg # Template instances are merged to avoid duplicates.
-Id:\bc4\include # Header search path.
-P- # If extension = .CPP then compile as C++, otherwise treat as C.
-w # Enable all warnings.
# -w! # Treat all warnings as errors.
-X- # Turn on autodependency checking.
-RT # Enable run time type itentification.
-x # Enable exception handling code.
-k- # Optimize: Use abbreviated stack frame.
-vi # Turns "inline" expansion on.
-Z # Optimize: Supress redundant register loads.
-Oi # Optimize: Helper functions expanded inline.
-O # Optimize: Jump optimization.
-Op # Optimize: Copy propagation to supress reloads.
-Ov # Optimize: Speeds array indexing inside of loops.
-Og # Optimize: Eliminates common subexpressions (globally).
-Oc # Optimize: Eliminates common subexpressions (locally).
-Ol # Optimize: Use REP instruction where possible.
-d # Optimize: Duplicate strings are merged.
-r # Try to put auto variables into registers.
-V # Use smart virtual tables (only usable with BCC and TLINK).
-dc- # Keep strings in the data segment (DON'T CHANGE THIS).
-Ff # Put very very large objects into the far segment.
-K2- # Treat "char" different from "signed char" or "unsigned char".
-Oa # Optimize: Assumes no pointer aliasing (could cause bugs)!
-R- # Don't include browser data (only used by IDE).
# -Oe # Optimize: Global register allocation tracking enabled.
# -Ob # Optimize: Dead code elimination.
# -Om # Optimize: Remove invariant code from loops.
# -p # Pascal calling convention default.
# -pr # Regiser calling convention default.
# -po # Pass "this" in registers when calling member functions.
# -f- # Floating point prohibited.
# -Yo # Compile as overlay module.
# -Ox # Optimize: Execution speed.
! turboc.cfg /Q
####################################################################
# Creates TASM config file.
tasm.cfg: makefile
copy &&!
/Zi # Include debug information into object file.
/w+ICG
/w-PDC
/t
/w2 # Maximum warning level.
/ml # Large model.
/w+
/v
/JIDEAL # Ideal mode.
/JP386N # Enable 386 instructions.
/UT300 # Force compatibility with old TASM.
! tasm.cfg
####################################################################
# Creates the TLINK.CFG file which implicitly controls linking.
tlink.cfg: makefile
copy &&!
/Ld:\bc4\lib
/v
/c
/e
/Tde
! tlink.cfg /Q
+322
View File
@@ -0,0 +1,322 @@
;
; Command & Conquer Red Alert(tm)
; Copyright 2025 Electronic Arts Inc.
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation, either version 3 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
;
IDEAL
IDEAL_MODE EQU 1
VERSION T300 ; Code written for V3.0 TASM version.
IDEAL
P386N ; target machine.
SMART ; Enable optimizations.
WARN ; Full warnings.
LOCALS ??
MODEL LARGE @filename
; INCLUDE "d:\library\wwlib.i"
CODE_2BIT EQU 0
CODE_4BIT EQU 1
CODE_RAW EQU 2
CODE_SILENCE EQU 3
MAGICNUMBER EQU 00000DEAFh
MAGICNUMBER2 EQU 0BABEBABEh
; VERSION T300 ; Code written for V3.0 TASM version.
; P386N ; target machine.
; MODEL LARGE @filename
; WARN ; Full warnings.
; LOCALS ??
CODESEG
_2bitdecode DB -2, -1, 0, 1
;_2bitdecode DB -2, -1, 1, 2
_4bitdecode DB -9,-8,-6,-5,-4,-3,-2,-1,0,1,2,3,4,5,6,8
;_4bitdecode DB -16,-13,-10,-8,-6,-4,-2,-1,1,2,4,6,8,10,13,16
GLOBAL C Decompress_Frame:FAR
PROC C Decompress_Frame FAR USES bx cx edx ds si es di bp
ARG source:DWORD
ARG dest:DWORD
ARG count:WORD
LOCAL previous:BYTE
LOCAL incount:WORD
; Initialize counter for number of bytes read from source.
mov [incount],0
; Verify parameters for legality.
cmp [source],0
je ??fini
cmp [dest],0
je ??fini
cmp [count],0
je ??fini
; Fetch parameter values into working registers.
lds si,[source] ; Pointer to source data.
les di,[dest] ; Pointer to destination data.
mov cx,[count] ; Number of bytes to fill dest buffer.
mov dl,080h ; Previous sample (starting value).
??mainloop:
; Check to see if the destination is full. Exit if so.
cmp cx,0
jle ??fini
; Fetch code byte from input stream.
xor ah,ah
mov al,[ds:si]
inc [incount]
inc si
shl ax,2 ; AH contains code.
shr al,2 ; AL contains sub-code data.
; Check to see if a raw sequence follows.
cmp ah,CODE_RAW
jne short ??try4bit
; The code contains either a 5 bit delta or a count of raw samples
; to dump out.
test al,00100000b
je short ??justraw
; The lower 5 bits are actually a signed delta. Sign extend the
; delta and add it to the stream.
shl al,3
sar al,3
add dl,al
mov [es:di],dl
dec cx
inc di
jmp ??mainloop
; The lower 5 bits hold a count of the number of raw samples that
; follow this code. Dump these samples to the output buffer.
??justraw:
mov bx,cx
xor ah,ah
inc al
mov cx,ax
shr cx,1
rep movsw
adc cx,cx
rep movsb
mov cx,bx
add [incount],ax
sub cx,ax
dec di
mov dl,[es:di] ; Set "previous" value.
inc di
jmp ??mainloop
; Check to see if this is a 4 bit delta code sequence.
??try4bit:
inc al ; Following codes use AL+1
cmp ah,CODE_4BIT
jne short ??try2bit
; A sequence of 4bit deltas follow. AL equals the number of nibble
; packed delta bytes to process.
??bit4loop:
; Fetch nibble packed delta codes.
mov ah,[ds:si]
mov bl,ah
inc [incount]
inc si
; Add first delta to 'previous' sample already in DL.
and bx,00001111b
add dl,[cs:_4bitdecode+bx] ; Add in delta
pushf
cmp [cs:_4bitdecode+bx],0
jl short ??neg1
popf
jnc short ??ok1
mov dl,0FFh
jmp short ??ok1
??neg1:
popf
jc short ??ok1
xor dl,dl
??ok1:
mov dh,dl ; DH now holds new 'previous' sample.
mov bl,ah
shr bl,4
add dh,[cs:_4bitdecode+bx] ; Add in delta
pushf
cmp [cs:_4bitdecode+bx],0
jl short ??neg2
popf
jnc short ??ok2
mov dh,0FFh
jmp short ??ok2
??neg2:
popf
jc short ??ok2
xor dh,dh
??ok2:
; Output the two sample bytes.
mov [es:di],dx
sub cx,2
add di,2
; Put the correct 'previous' sample in DL where it belongs.
mov dl,dh
; If there are more deltas to process then loop back.
dec al
jnz short ??bit4loop
jmp ??mainloop
; Check to see if 2 bit deltas need to be processed.
??try2bit:
cmp ah,CODE_2BIT
jne ??zerodelta
; A sequence of 2bit deltas follow. AL equals the number of
; packed delta bytes to process.
??bit2loop:
; Fetch packed delta codes.
mov ah,[ds:si]
inc [incount]
inc si
; Add first delta to 'previous' sample already in DL.
mov bl,ah
and bx,000011b
add dl,[cs:_2bitdecode+bx] ; Add in delta
pushf
cmp [cs:_2bitdecode+bx],0
jl short ??neg3
popf
jnc short ??ok3
mov dl,0FFh
jmp short ??ok3
??neg3:
popf
jc short ??ok3
xor dl,dl
??ok3:
mov dh,dl
ror edx,8
mov bl,ah
shr bx,2
and bl,00000011b
add dl,[cs:_2bitdecode+bx] ; Add in delta
pushf
cmp [cs:_2bitdecode+bx],0
jl short ??neg4
popf
jnc short ??ok4
mov dl,0FFh
jmp short ??ok4
??neg4:
popf
jc short ??ok4
xor dl,dl
??ok4:
mov dh,dl
ror edx,8
mov bl,ah
shr bx,4
and bl,00000011b
add dl,[cs:_2bitdecode+bx] ; Add in delta
pushf
cmp [cs:_2bitdecode+bx],0
jl short ??neg5
popf
jnc short ??ok5
mov dl,0FFh
jmp short ??ok5
??neg5:
popf
jc short ??ok5
xor dl,dl
??ok5:
mov dh,dl
ror edx,8
mov bl,ah
shr bx,6
and bl,00000011b
add dl,[cs:_2bitdecode+bx] ; Add in delta
pushf
cmp [cs:_2bitdecode+bx],0
jl short ??neg6
popf
jnc short ??ok6
mov dl,0FFh
jmp short ??ok6
??neg6:
popf
jc short ??ok6
xor dl,dl
??ok6:
;mov dh,dl
ror edx,8
; Output the two sample bytes.
mov [es:di],edx
sub cx,4
add di,4
; Put the correct 'previous' sample in DL where it belongs.
rol edx,8
; If there are more deltas to process then loop back.
dec al
jnz ??bit2loop
jmp ??mainloop
; There is a run of zero deltas. Zero deltas merely duplicate
; the 'previous' sample the requested number of times.
??zerodelta:
xor bh,bh
mov bl,al
mov al,dl
sub cx,bx
xchg cx,bx
rep stosb
mov cx,bx
jmp ??mainloop
; Final cleanup and exit.
??fini:
mov ax,[incount]
ret
ENDP Decompress_Frame
END
+11
View File
@@ -0,0 +1,11 @@
/Zi
/w+ICG
/w-PDC
/t
/w2
/ml
/w+
/v
/JIDEAL
/JP386N
/UT300
+5
View File
@@ -0,0 +1,5 @@
/Ld:\bc4\lib
/v
/c
/e
/Tde
+35
View File
@@ -0,0 +1,35 @@
-v
-y
-Vt
-Vb-
-a-
-b-
-3
-ml
-C-
-c
-Jg
-Id:\bc4\include
-P-
-w
-X-
-RT
-x
-k-
-vi
-Z
-Oi
-O
-Op
-Ov
-Og
-Oc
-Ol
-d
-r
-V
-dc-
-Ff
-K2-
-Oa
-R-
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
+675
View File
@@ -0,0 +1,675 @@
/*
** Command & Conquer Red Alert(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S **
***********************************************************************************************
* *
* Project Name : Data file creator. *
* *
* File Name : MIXFILE.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : August 6, 1994 *
* *
* Last Update : 10/27/94 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Calc_CRC -- Calculate the CRC value of a block of data. *
* compfunc -- Comparison function used by qsort(). *
* DataClass::DataClass -- Constructor for a data file object node. *
* DataClass::Process_Input -- Process the input file list and builds linked records. *
* DataClass::Process_Output -- Creates the output data file from the component source files.*
* DataClass::~DataClass -- Destructor for the data file object. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#pragma inline
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <dir.h>
#include <string.h>
#define FALSE 0
#define TRUE 1
long Calc_CRC(void const *data, long size);
/********************************************************************
** This is the data block controlling class. It is used for every data
** file as well as processing the entire data file list.
*/
class DataClass {
public:
long CRC;
static short Count;
static long TotalSize;
static char *ExtFrom[10];
static char *ExtTo[10];
static int ExtCount;
static char *AltPath[10];
static int AltPathCount;
DataClass(char const *filename);
~DataClass(void);
static void Process_Input(char const *infile, int quiet, int paths);
static void Process_Output(char const *outfile);
char const * Output_Filename(void);
char const * Input_Filename(void);
private:
DataClass *Next; // Pointer to next file in chain.
char *Filename; // Raw original filename.
long Size; // Size of data element.
long Offset; // Offset within mixfile for data start.
int Index; // Write order number.
static DataClass *First;
static int Quiet;
static int Paths;
};
char *DataClass::AltPath[10];
char *DataClass::ExtFrom[10];
char *DataClass::ExtTo[10];
int DataClass::ExtCount = 0;
int DataClass::AltPathCount = 0;
short DataClass::Count = 0;
DataClass * DataClass::First = 0;
int DataClass::Quiet = FALSE;
int DataClass::Paths = FALSE;
long DataClass::TotalSize = 0;
int main(int argc, char ** argv)
{
class UsageError{}; // Parameter error or usage display desired.
char *infile = 0;
char *outfile = 0;
int quiet = FALSE;
int paths = FALSE;
/*
** Banner message.
*/
printf("MIXFILE V1.4 (c)\n");
/*
** Process the parameter list and dispatch the packing function.
*/
try {
/*
** If not enough parameters were specified, then immediately
** display the usage instructions.
*/
if (argc < 2) throw UsageError();
try {
for (int index = 1; index < argc; index++) {
char *arg = argv[index];
switch (*arg) {
/*
** Process any command line switches.
*/
case '/':
case '-':
switch (toupper(arg[1])) {
case 'Q':
quiet = TRUE;
break;
case 'S':
paths = TRUE;
break;
case 'E':
if (DataClass::ExtCount >= sizeof(DataClass::ExtFrom)/sizeof(DataClass::ExtFrom[0])) {
throw "Too many extensions specified";
} else {
char * ptr = strupr(strtok(&arg[2], "="));
if (*ptr == '.') ptr++;
DataClass::ExtFrom[DataClass::ExtCount] = ptr;
ptr = strupr(strtok(NULL, "=\r\n"));
if (*ptr == '.') ptr++;
DataClass::ExtTo[DataClass::ExtCount] = ptr;
DataClass::ExtCount++;
}
break;
case 'I':
if (DataClass::AltPathCount >= sizeof(DataClass::AltPath)/sizeof(DataClass::AltPath[0])) {
throw "Too many paths specified";
} else {
char dir[MAXDIR];
strcpy(dir, &arg[2]);
if (dir[strlen(dir)-1] != '\\') {
strcat(dir, "\\");
}
DataClass::AltPath[DataClass::AltPathCount++] = strupr(strdup(dir));
}
break;
default:
throw "Unrecognized option flag";
}
break;
/*
** Process command line filenames for either input or output.
*/
default:
if (outfile) throw "Unrecognized parameter";
if (!infile) {
FILE *file = fopen(arg, "r");
if (!file) throw "Unable to open input file";
fclose(file);
infile = arg;
continue;
}
if (!outfile) {
outfile = arg;
}
break;
}
}
/*
** Perform a last minute check to make sure both an input and
** output filename was specified. If not, then throw an
** error.
*/
if (!outfile) throw "No output file specified";
if (!infile) throw "No input file specified";
/*
** Process the data.
*/
try {
DataClass::Process_Input(infile, quiet, paths);
DataClass::Process_Output(outfile);
printf("Created mix file '%s'\nEmbedded objects = %d\nTotal file size = %ld\n", outfile, DataClass::Count, DataClass::TotalSize);
}
catch (char *message) {
printf("\nERROR: %s.\n", message);
exit(EXIT_FAILURE);
}
}
/*
** This exception is called for any of the various fatal errors that
** can occur while parsing the parameters.
*/
catch(char *message) {
printf("\nERROR: %s.\n", message);
throw UsageError();
}
}
/*
** This exception is thrown when the utility can't proceed and the
** utility usage instructions are desired to be displayed.
*/
catch(UsageError) {
printf("\nUSAGE: DATFILE <controlfile> <datafile>\n"
"\n"
" <controlfile> : list of filenames to pack\n"
" <datafile> : output data filename\n"
" Options\n"
" -q : quiet operation\n"
" -i<path> : alternate to find files\n"
" -e<ext1>=<ext2> : changes file extensions from <ext1> to <ext2>\n"
" -s : record paths in ID\n");
exit(EXIT_FAILURE);
}
return EXIT_SUCCESS;
}
/***********************************************************************************************
* DataClass::Process_Input -- Process the input file list and builds linked records. *
* *
* This routine will process the list of files in the input file. It builds a linked *
* list of DataClass objects. This routine is the initial process of creating a packed *
* data file. * *
* *
* INPUT: infile -- Pointer to input filename. *
* *
* quiet -- Process quietly? *
* *
* paths -- Should the path of the filename be considered as part of its signature?*
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1994 JLB : Created. *
*=============================================================================================*/
void DataClass::Process_Input(char const *infile, int quiet, int paths)
{
FILE *file; // Input file.
static char buffer[MAXFILE];
Quiet = quiet;
Paths = paths;
if (!infile) throw "No input file specified";
file = fopen(infile, "ra");
if (!file) throw "Could not open input file";
if (!Quiet) {
printf("Processing '%s'.\n", infile);
}
/*
** Process the source file list.
*/
try {
for (;;) {
int result = fscanf(file, "%s", buffer);
if (result == EOF) break;
new DataClass(buffer);
}
}
/*
** This error handler is used if there are any errors that occur while
** parsing and verifying the data block filenames. Errors can include
** source filename errors as well as missing source files themselves.
*/
catch (char *message) {
fclose(file);
throw message;
}
fclose(file);
}
/***********************************************************************************************
* DataClass::DataClass -- Constructor for a data file object node. *
* *
* This constructs a data file object node and links it into the list of object nodes. *
* It performs a preliminary check on the existance of the the source file. *
* *
* INPUT: filename -- The filename of the object to add. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1994 JLB : Created. *
* 10/27/94 JLB : Handles multiple data paths. *
*=============================================================================================*/
DataClass::DataClass(char const *filename)
{
static char buffer[100];
if (!filename) throw "NULL filename";
Filename = strdup(filename);
strupr(Filename);
/*
** Try to find the data file.
*/
FILE *datafile = fopen(Filename, "rb");
if (!datafile) {
/*
** If the file couldn't be found in the current directory, check
** the alternate paths. If the alternate path is successful, then
** alter the pathname to match and continue.
*/
for (int index = 0; index < AltPathCount; index++) {
strcpy(buffer, AltPath[index]);
strcat(buffer, Filename);
datafile = fopen(buffer, "rb");
if (datafile) {
free(Filename);
Filename = strdup(buffer);
break;
}
}
if (!datafile) {
sprintf(buffer, "Could not find source file '%s'", Filename);
throw buffer;
}
}
/*
** Determine the CRC identifier for the filename, This can be either
** the base filename or the complete path (as indicated by the command
** line parameter).
*/
char const * name = Output_Filename();
CRC = Calc_CRC(name, strlen(name));
/*
** Find out the size of the source data file.
*/
fseek(datafile, 0, SEEK_END);
long size = ftell(datafile);
fclose(datafile);
if (size == -1) throw "Seek failure";
Size = size;
Index = Count;
Count++;
Next = First;
First = this;
}
/***********************************************************************************************
* DataClass::~DataClass -- Destructor for the data file object. *
* *
* This is the destructor for the data file object. It deallocates any memory allocated *
* and de-links it from the list of file objects. *
* *
* INPUT: none *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1994 JLB : Created. *
*=============================================================================================*/
DataClass::~DataClass(void)
{
if (Filename) {
free(Filename);
Filename = 0;
}
Count--;
DataClass *ptr = First;
DataClass *prev = 0;
while (ptr) {
if (ptr == this) {
if (prev) {
prev->Next = Next;
}
return;
}
prev = ptr;
ptr = ptr->Next;
}
}
/***********************************************************************************************
* compfunc -- Comparison function used by qsort(). *
* *
* This is a support function that compares two file data objects against their CRC *
* values. *
* *
* INPUT: ptr1 -- Pointer to object number 1. *
* *
* ptr2 -- Pointer to object number 2. *
* *
* OUTPUT: Returns with a logical comparison of object 1 to object 2. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1994 JLB : Created. *
*=============================================================================================*/
int compfunc(const void *ptr1, const void *ptr2)
{
DataClass const *obj1 = *(DataClass const **)ptr1;
DataClass const *obj2 = *(DataClass const **)ptr2;
if (obj1->CRC < obj2->CRC) {
return (-1);
}
if (obj1->CRC > obj2->CRC) {
return (1);
}
return(0);
}
/***********************************************************************************************
* DataClass::Process_Output -- Creates the output data file from the component source files. *
* *
* This is the final step in creation of the data output file. It writes the header *
* block and then appends the appropriate files to the output file. *
* *
* INPUT: outname -- Pointer to the filename to use for output. *
* *
* OUTPUT: none *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1994 JLB : Created. *
*=============================================================================================*/
void DataClass::Process_Output(char const *outname)
{
FILE *outfile;
if (Count) {
DataClass **array = new DataClass *[Count];
/*
** Open the output file for creation.
*/
if (!outname) throw "Missing output filename";
outfile = fopen(outname, "wb");
if (!outfile) {
throw "Unable to open output file";
}
/*
** Build a working array to the file objects.
*/
DataClass * ptr = First;
for (int index = 0; index < Count; index++) {
array[index] = ptr;
ptr->Index = index;
ptr = ptr->Next;
}
/*
** Precalculate the offset value for each data file will be.
** This value will be inserted into the header block. This is
** performed BEFORE the files are sorted because the data files
** are written to disk in the order that they were specified.
*/
TotalSize = 0;
for (index = 0; index < Count; index++) {
array[index]->Offset = TotalSize;
TotalSize += array[index]->Size;
}
/*
** Next, sort the data objects so that a binary search on CRC values
** can be used for file retrieval.
*/
qsort(array, Count, sizeof(array[0]), compfunc);
/*
** Output the header section of the data file. This contains
** the count of objects contained, the CRC, and offset for each.
*/
fwrite(&Count, sizeof(Count), 1, outfile);
fwrite(&TotalSize, sizeof(TotalSize), 1, outfile);
for (index = 0; index < Count; index++) {
fwrite(&array[index]->CRC, sizeof(array[index]->CRC), 1, outfile);
fwrite(&array[index]->Offset, sizeof(array[index]->Offset), 1, outfile);
fwrite(&array[index]->Size, sizeof(array[index]->Size), 1, outfile);
}
TotalSize += sizeof(Count) + sizeof(TotalSize) + (Count*12);
if (!Quiet) {
printf("size CRC Filename\n");
printf("------ -------- -------------------------\n");
}
/*
** Now write the actual data -- one file at a time in the order that they were
** originally specified.
*/
for (int order = 0; order < Count; order++) {
for (index = 0; index < Count; index++) {
DataClass * entry = array[index];
if (entry->Index == order) {
FILE *infile;
long size;
static char buffer[1024*30];
if (!Quiet) {
printf("%-8ld [%08lX] %s\n", entry->Size, entry->CRC, entry->Output_Filename());
}
size = entry->Size;
infile = fopen(entry->Input_Filename(), "rb");
while (size > 0) {
int count;
count = (size < sizeof(buffer)) ? (int)size : sizeof(buffer);
count = fread(buffer, sizeof(buffer[0]), count, infile);
fwrite(buffer, sizeof(buffer[0]), count, outfile);
size -= count;
if (!count) break; // Hmm..
}
fclose(infile);
break;
}
}
}
fclose(outfile);
}
}
/***********************************************************************************************
* Calc_CRC -- Calculate the CRC value of a block of data. *
* *
* This routine is used to create a CRC value from a string of data bytes. *
* *
* INPUT: data -- Pointer to the data bytes to calculate the CRC value for. *
* *
* size -- The number of bytes in the data block. *
* *
* OUTPUT: Returns with the CRC value of the buffer specified. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 08/06/1994 JLB : Created. *
*=============================================================================================*/
long Calc_CRC(void const *data, long size)
{
long crc = 0; // Accumulating CRC value.
long const *ptr = static_cast<long const *>(data);
/*
** Process the bulk of the data (4 bytes at a time).
*/
for (; size > sizeof(long); size -= sizeof(long)) {
long temp = *ptr++;
asm {
mov eax,crc
rol eax,1
add eax,temp
mov crc,eax
}
}
/*
** If there are any remainder bytes, then process them
** as a group of four, but the trailing left over bytes
** are forced to be NULL.
*/
if (size) {
long temp = 0;
memcpy(&temp, ptr, (size_t)size);
asm {
mov eax,crc
rol eax,1
add eax,temp
mov crc,eax
}
}
return (crc);
}
char const * DataClass::Output_Filename(void)
{
char file[MAXFILE];
char ext[MAXEXT];
char path[MAXPATH];
char drive[MAXDRIVE];
static char filename[255];
/*
** Break the original filename into its component parts.
*/
fnsplit(Filename, drive, path, file, ext);
/*
** Substitute the extension if a substitution is called for.
*/
for (int index = 0; index < ExtCount; index++) {
if (stricmp(ExtFrom[index], &ext[1]) == 0) {
strcpy(&ext[1], ExtTo[index]);
break;
}
}
/*
** Strip the path from the filename if path stripping is enabled.
*/
if (!Paths) {
fnmerge(filename, NULL, NULL, file, ext);
} else {
fnmerge(filename, drive, path, file, ext);
}
return(&filename[0]);
}
char const * DataClass::Input_Filename(void)
{
return(Filename);
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.