mirror of
https://github.com/electronicarts/CnC_Generals_Zero_Hour.git
synced 2025-12-16 23:51:41 -05:00
Initial commit of Command & Conquer Generals and Command & Conquer Generals Zero Hour source code.
This commit is contained in:
656
GeneralsMD/Code/Tools/Babylon/loadsave.cpp
Normal file
656
GeneralsMD/Code/Tools/Babylon/loadsave.cpp
Normal file
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
** Command & Conquer Generals Zero Hour(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/>.
|
||||
*/
|
||||
|
||||
//
|
||||
// loadsave.cpp
|
||||
//
|
||||
|
||||
#include "stdAfx.h"
|
||||
#include "iff.h"
|
||||
#include "TransDB.h"
|
||||
#include "Babylondlg.h"
|
||||
|
||||
#define FORM_BABYLONDB MakeID ('N','X','D','B')
|
||||
#define FORM_LABEL MakeID ('N','L','B','L')
|
||||
#define FORM_TEXT MakeID ('N','T','X','T')
|
||||
#define FORM_TRANS MakeID ('N','T','R','N')
|
||||
#define CHUNK_COMMENT MakeID ('C','M','N','T')
|
||||
#define CHUNK_CONTEXT MakeID ('C','T','X','T')
|
||||
#define CHUNK_SPEAKER MakeID ('S','P','K','R')
|
||||
#define CHUNK_LISTENER MakeID ('L','T','N','R')
|
||||
#define CHUNK_TEXT MakeID ('T','E','X','T')
|
||||
#define CHUNK_WAVE MakeID ('W','A','V','E')
|
||||
#define CHUNK_WAVE_INFO MakeID ('W','V','I','N')
|
||||
#define CHUNK_INFO MakeID ('I','N','F','O')
|
||||
#define CHUNK_NAME MakeID ('N','A','M','E')
|
||||
|
||||
#define MAX_BUFFER (100*1024)
|
||||
|
||||
static OLECHAR buffer[MAX_BUFFER];
|
||||
typedef struct
|
||||
{
|
||||
int num_labels;
|
||||
int next_id;
|
||||
|
||||
} DBINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int max_len;
|
||||
|
||||
} LBINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int id;
|
||||
int revision;
|
||||
|
||||
} TXINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
LangID lang;
|
||||
int revision;
|
||||
|
||||
} TRINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int valid;
|
||||
DWORD lo;
|
||||
DWORD hi;
|
||||
|
||||
} WVINFO;
|
||||
|
||||
|
||||
static int writeString ( IFF_FILE *iff, OLECHAR *string, int chunk_id )
|
||||
{
|
||||
int len = (wcslen ( string ) );
|
||||
int bytes = (len+1)*sizeof(OLECHAR);
|
||||
|
||||
if ( len )
|
||||
{
|
||||
IFF_NEWCHUNK ( iff, chunk_id, error );
|
||||
IFF_WRITE ( iff, string, bytes, error);
|
||||
IFF_CloseChunk ( iff );
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int readString ( IFF_FILE *iff, OLECHAR *string )
|
||||
{
|
||||
|
||||
*string = 0;
|
||||
|
||||
IFF_READ ( iff, string, iff->ChunkSize, error);
|
||||
|
||||
return TRUE;
|
||||
|
||||
error:
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int writeTransForm ( IFF_FILE *iff, Translation *trans )
|
||||
{
|
||||
TRINFO trinfo;
|
||||
WVINFO wvinfo;
|
||||
|
||||
if ( !IFF_NewForm ( iff, FORM_TRANS ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
trinfo.lang = trans->GetLangID ();
|
||||
trinfo.revision = trans->Revision ();
|
||||
|
||||
if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFF_Write ( iff, &trinfo, sizeof ( trinfo ));
|
||||
|
||||
IFF_CloseChunk ( iff );
|
||||
|
||||
writeString ( iff, trans->Get (), CHUNK_TEXT );
|
||||
writeString ( iff, trans->Comment (), CHUNK_COMMENT );
|
||||
|
||||
if ( (wvinfo.valid = trans->WaveInfo.Valid()) )
|
||||
{
|
||||
wvinfo.lo = trans->WaveInfo.Lo ();
|
||||
wvinfo.hi = trans->WaveInfo.Hi ();
|
||||
|
||||
if ( !IFF_NewChunk ( iff, CHUNK_WAVE_INFO ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFF_Write ( iff, &wvinfo, sizeof ( wvinfo ));
|
||||
|
||||
IFF_CloseChunk ( iff );
|
||||
}
|
||||
|
||||
IFF_CloseForm ( iff );
|
||||
|
||||
return TRUE;
|
||||
error:
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
static int writeTextForm ( IFF_FILE *iff, BabylonText *text )
|
||||
{
|
||||
TXINFO txinfo;
|
||||
WVINFO wvinfo;
|
||||
|
||||
if ( !IFF_NewForm ( iff, FORM_TEXT ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
txinfo.id = text->ID ();
|
||||
txinfo.revision = text->Revision ();
|
||||
|
||||
if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFF_Write ( iff, &txinfo, sizeof ( txinfo ));
|
||||
|
||||
IFF_CloseChunk ( iff );
|
||||
writeString ( iff, text->Get (), CHUNK_TEXT );
|
||||
writeString ( iff, text->Wave (), CHUNK_WAVE );
|
||||
|
||||
if ( (wvinfo.valid = text->WaveInfo.Valid()) )
|
||||
{
|
||||
wvinfo.lo = text->WaveInfo.Lo ();
|
||||
wvinfo.hi = text->WaveInfo.Hi ();
|
||||
|
||||
if ( !IFF_NewChunk ( iff, CHUNK_WAVE_INFO ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFF_Write ( iff, &wvinfo, sizeof ( wvinfo ));
|
||||
|
||||
IFF_CloseChunk ( iff );
|
||||
}
|
||||
|
||||
IFF_CloseForm ( iff );
|
||||
|
||||
return TRUE;
|
||||
error:
|
||||
|
||||
return FALSE;
|
||||
|
||||
}
|
||||
|
||||
int WriteMainDB(TransDB *db, const char *filename, CBabylonDlg *dlg )
|
||||
{
|
||||
BabylonText *text;
|
||||
BabylonLabel *label;
|
||||
ListSearch sh_label;
|
||||
ListSearch sh_text;
|
||||
int count = 0;
|
||||
IFF_FILE *iff = NULL;
|
||||
DBINFO dbinfo;
|
||||
int ok = FALSE;
|
||||
|
||||
if ( dlg )
|
||||
{
|
||||
dlg->InitProgress ( db->NumLabels ());
|
||||
}
|
||||
|
||||
|
||||
if ( !( iff = IFF_New ( filename )))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ( !IFF_NewForm ( iff, FORM_BABYLONDB ) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
dbinfo.next_id = db->ID ();
|
||||
dbinfo.num_labels = db->NumLabels ();
|
||||
|
||||
if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFF_Write ( iff, &dbinfo, sizeof ( dbinfo ));
|
||||
|
||||
IFF_CloseChunk ( iff );
|
||||
IFF_CloseForm ( iff );
|
||||
|
||||
text = db->FirstObsolete ( sh_text );
|
||||
|
||||
while ( text )
|
||||
{
|
||||
if ( !writeTextForm ( iff, text ) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
text = db->NextObsolete ( sh_text );
|
||||
}
|
||||
|
||||
|
||||
|
||||
label = db->FirstLabel ( sh_label );
|
||||
|
||||
while ( label )
|
||||
{
|
||||
LBINFO lbinfo;
|
||||
|
||||
if ( !IFF_NewForm ( iff, FORM_LABEL ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
lbinfo.max_len = label->MaxLen ();
|
||||
|
||||
if ( !IFF_NewChunk ( iff, CHUNK_INFO ))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
IFF_Write ( iff, &lbinfo, sizeof ( lbinfo ));
|
||||
|
||||
IFF_CloseChunk ( iff );
|
||||
|
||||
writeString ( iff, label->Name (), CHUNK_NAME );
|
||||
writeString ( iff, label->Comment (), CHUNK_COMMENT );
|
||||
writeString ( iff, label->Context (), CHUNK_CONTEXT );
|
||||
writeString ( iff, label->Speaker (), CHUNK_SPEAKER );
|
||||
writeString ( iff, label->Listener (), CHUNK_LISTENER );
|
||||
IFF_CloseForm ( iff );
|
||||
|
||||
text = label->FirstText ( sh_text );
|
||||
|
||||
while ( text )
|
||||
{
|
||||
Translation *trans;
|
||||
ListSearch sh_trans;
|
||||
if ( !writeTextForm ( iff, text ) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
trans = text->FirstTranslation ( sh_trans );
|
||||
|
||||
while ( trans )
|
||||
{
|
||||
if ( !writeTransForm ( iff, trans ) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
trans = text->NextTranslation ( sh_trans );
|
||||
}
|
||||
|
||||
text = label->NextText ( sh_text );
|
||||
}
|
||||
|
||||
count++;
|
||||
if ( dlg )
|
||||
{
|
||||
dlg->SetProgress ( count );
|
||||
}
|
||||
label = db->NextLabel ( sh_label );
|
||||
}
|
||||
|
||||
ok = TRUE;
|
||||
db->ClearChanges ();
|
||||
|
||||
error:
|
||||
if ( iff )
|
||||
{
|
||||
IFF_Close ( iff );
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int LoadMainDB(TransDB *db, const char *filename, void (*cb) (void) )
|
||||
{
|
||||
BabylonLabel *label = NULL;
|
||||
BabylonText *text = NULL;
|
||||
Translation *trans = NULL;
|
||||
int count = 0;
|
||||
IFF_FILE *iff = NULL;
|
||||
DBINFO dbinfo;
|
||||
int ok = FALSE;
|
||||
|
||||
|
||||
if ( !(iff = IFF_Load ( filename ) ) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ( !IFF_NextForm ( iff ) || iff->FormID != FORM_BABYLONDB )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
dbinfo.next_id = -1;
|
||||
dbinfo.num_labels = 0;
|
||||
|
||||
while ( IFF_NextChunk ( iff ))
|
||||
{
|
||||
switch (iff->ChunkID )
|
||||
{
|
||||
case CHUNK_INFO:
|
||||
IFF_READ ( iff, &dbinfo, sizeof ( dbinfo ), error );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
db->SetID ( dbinfo.next_id );
|
||||
|
||||
while ( IFF_NextForm ( iff ) )
|
||||
{
|
||||
switch ( iff->FormID )
|
||||
{
|
||||
case FORM_LABEL:
|
||||
{
|
||||
LBINFO lbinfo;
|
||||
// new label
|
||||
|
||||
if ( text )
|
||||
{
|
||||
if ( label )
|
||||
{
|
||||
label->AddText ( text );
|
||||
}
|
||||
else
|
||||
{
|
||||
db->AddObsolete ( text );
|
||||
}
|
||||
|
||||
text = NULL;
|
||||
}
|
||||
|
||||
if ( label )
|
||||
{
|
||||
count++;
|
||||
db->AddLabel ( label );
|
||||
label = NULL;
|
||||
if ( cb )
|
||||
{
|
||||
cb ();
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! (label = new BabylonLabel ()))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ( IFF_NextChunk ( iff ))
|
||||
{
|
||||
switch ( iff->ChunkID )
|
||||
{
|
||||
case CHUNK_INFO:
|
||||
IFF_READ ( iff, &lbinfo, sizeof (lbinfo), error );
|
||||
label->SetMaxLen ( lbinfo.max_len );
|
||||
break;
|
||||
case CHUNK_COMMENT:
|
||||
readString ( iff, buffer );
|
||||
label->SetComment ( buffer );
|
||||
break;
|
||||
case CHUNK_CONTEXT:
|
||||
readString ( iff, buffer );
|
||||
label->SetContext ( buffer );
|
||||
break;
|
||||
case CHUNK_SPEAKER:
|
||||
readString ( iff, buffer );
|
||||
label->SetSpeaker ( buffer );
|
||||
break;
|
||||
case CHUNK_LISTENER:
|
||||
readString ( iff, buffer );
|
||||
label->SetListener ( buffer );
|
||||
break;
|
||||
case CHUNK_NAME:
|
||||
readString ( iff, buffer );
|
||||
label->SetName ( buffer );
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FORM_TEXT:
|
||||
{
|
||||
TXINFO txinfo;
|
||||
|
||||
if ( text )
|
||||
{
|
||||
if ( label )
|
||||
{
|
||||
label->AddText ( text );
|
||||
}
|
||||
else
|
||||
{
|
||||
db->AddObsolete ( text );
|
||||
}
|
||||
|
||||
text = NULL;
|
||||
}
|
||||
|
||||
if ( ! (text = new BabylonText ()))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ( IFF_NextChunk ( iff ))
|
||||
{
|
||||
switch ( iff->ChunkID )
|
||||
{
|
||||
case CHUNK_INFO:
|
||||
IFF_READ ( iff, &txinfo, sizeof (txinfo), error );
|
||||
text->SetID ( txinfo.id );
|
||||
text->SetRevision ( txinfo.revision );
|
||||
break;
|
||||
case CHUNK_TEXT:
|
||||
readString ( iff, buffer );
|
||||
text->Set ( buffer );
|
||||
break;
|
||||
|
||||
case CHUNK_WAVE:
|
||||
readString ( iff, buffer );
|
||||
text->SetWave ( buffer );
|
||||
break;
|
||||
case CHUNK_WAVE_INFO:
|
||||
{
|
||||
WVINFO wvinfo;
|
||||
IFF_READ ( iff, &wvinfo, sizeof (wvinfo), error );
|
||||
text->WaveInfo.SetValid ( wvinfo.valid );
|
||||
text->WaveInfo.SetLo ( wvinfo.lo );
|
||||
text->WaveInfo.SetHi ( wvinfo.hi );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FORM_TRANS:
|
||||
{
|
||||
TRINFO trinfo;
|
||||
|
||||
if ( ! (trans = new Translation ()))
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
while ( IFF_NextChunk ( iff ))
|
||||
{
|
||||
switch ( iff->ChunkID )
|
||||
{
|
||||
case CHUNK_INFO:
|
||||
IFF_READ ( iff, &trinfo, sizeof (trinfo), error );
|
||||
trans->SetLangID ( trinfo.lang );
|
||||
trans->SetRevision ( trinfo.revision );
|
||||
break;
|
||||
case CHUNK_TEXT:
|
||||
readString ( iff, buffer );
|
||||
trans->Set ( buffer );
|
||||
break;
|
||||
|
||||
case CHUNK_COMMENT:
|
||||
readString ( iff, buffer );
|
||||
trans->SetComment ( buffer );
|
||||
break;
|
||||
case CHUNK_WAVE_INFO:
|
||||
{
|
||||
WVINFO wvinfo;
|
||||
IFF_READ ( iff, &wvinfo, sizeof (wvinfo), error );
|
||||
trans->WaveInfo.SetValid ( wvinfo.valid );
|
||||
trans->WaveInfo.SetLo ( wvinfo.lo );
|
||||
trans->WaveInfo.SetHi ( wvinfo.hi );
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
if ( text )
|
||||
{
|
||||
text->AddTranslation ( trans );
|
||||
}
|
||||
else
|
||||
{
|
||||
delete trans;
|
||||
}
|
||||
trans = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( text )
|
||||
{
|
||||
if ( label )
|
||||
{
|
||||
label->AddText ( text );
|
||||
}
|
||||
else
|
||||
{
|
||||
db->AddObsolete ( text );
|
||||
}
|
||||
|
||||
text = NULL;
|
||||
}
|
||||
|
||||
if ( label )
|
||||
{
|
||||
count++;
|
||||
db->AddLabel ( label );
|
||||
label = NULL;
|
||||
if ( cb )
|
||||
{
|
||||
cb ();
|
||||
}
|
||||
}
|
||||
|
||||
ok = TRUE;
|
||||
|
||||
error:
|
||||
|
||||
if ( label )
|
||||
{
|
||||
delete label;
|
||||
}
|
||||
|
||||
if ( text )
|
||||
{
|
||||
delete text;
|
||||
}
|
||||
|
||||
if ( trans )
|
||||
{
|
||||
delete trans;
|
||||
}
|
||||
|
||||
if ( iff )
|
||||
{
|
||||
IFF_Close ( iff );
|
||||
}
|
||||
|
||||
db->ClearChanges ();
|
||||
|
||||
if ( !ok )
|
||||
{
|
||||
db->Clear ();
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
int GetLabelCountDB ( char *filename )
|
||||
{
|
||||
IFF_FILE *iff = NULL;
|
||||
DBINFO dbinfo;
|
||||
int count = 0;
|
||||
|
||||
|
||||
if ( !(iff = IFF_Open ( filename ) ) )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
if ( !IFF_NextForm ( iff ) || iff->FormID != FORM_BABYLONDB )
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
dbinfo.next_id = -1;
|
||||
dbinfo.num_labels = 0;
|
||||
|
||||
while ( IFF_NextChunk ( iff ))
|
||||
{
|
||||
switch (iff->ChunkID )
|
||||
{
|
||||
case CHUNK_INFO:
|
||||
IFF_READ ( iff, &dbinfo, sizeof ( dbinfo ), error );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
count = dbinfo.num_labels;
|
||||
|
||||
error:
|
||||
if ( iff )
|
||||
{
|
||||
IFF_Close ( iff );
|
||||
}
|
||||
return count;
|
||||
}
|
||||
Reference in New Issue
Block a user