This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/wwtranslatedb/translatedb.cpp

1376 lines
32 KiB
C++

/*
** Command & Conquer Renegade(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 : LevelEdit *
* *
* $Archive:: /Commando/Code/wwtranslatedb/translatedb.cpp $*
* *
* Author:: Patrick Smith *
* *
* $Modtime:: 1/28/02 4:05p $*
* *
* $Revision:: 18 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "translatedb.h"
#include <windows.h>
#include <string.h>
#include "persist.h"
#include "persistfactory.h"
#include "chunkio.h"
#include "translatedbids.h"
#include "rawfile.h"
#include "textfile.h"
#include "tdbcategories.h"
#include "definition.h"
#include "definitionmgr.h"
#include "definitionclassids.h"
///////////////////////////////////////////////////////////////////////
// Local prototypes
///////////////////////////////////////////////////////////////////////
static int Build_List_From_String (const char *buffer, const char *delimiter, StringClass **string_list);
///////////////////////////////////////////////////////////////////////
// Global singleton instance
///////////////////////////////////////////////////////////////////////
TranslateDBClass _TheTranslateDB;
///////////////////////////////////////////////////////////////////////
// Static member initialization
///////////////////////////////////////////////////////////////////////
TDB_OBJ_LIST TranslateDBClass::m_ObjectList;
HashTemplateClass<StringClass,TDBObjClass*> TranslateDBClass::m_ObjectHash;
TDB_CATEGORY_LIST TranslateDBClass::m_CategoryList;
uint32 TranslateDBClass::m_VersionNumber = 100;
uint32 TranslateDBClass::m_LanguageID = TranslateDBClass::LANGID_ENGLISH;
bool TranslateDBClass::IsSingleLanguageExport = false;
TranslateDBClass::FILTER_OPT TranslateDBClass::FilterType = FILTER_DISABLED;
uint32 TranslateDBClass::FilterCategoryID = 0xFFFFFFFF;
///////////////////////////////////////////////////////////////////////
// Constants
///////////////////////////////////////////////////////////////////////
enum
{
CHUNKID_VARIABLES = 0x07141200,
CHUNKID_OBJECTS,
CHUNKID_CATEGORIES
};
enum
{
VARID_VERSION_NUMBER = 0x01,
VARID_LANGUAGE_ID
};
const WCHAR * STRING_NOT_FOUND = L"TDBERR";
const char * ENGLISH_STRING_NOT_FOUND = "TDBERR";
///////////////////////////////////////////////////////////////////////
//
// Chunk_ID
//
///////////////////////////////////////////////////////////////////////
uint32
TranslateDBClass::Chunk_ID (void) const
{
return CHUNKID_TRANSLATE_DB;
}
///////////////////////////////////////////////////////////////////////
//
// Initialize
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Initialize (void)
{
m_ObjectList.Set_Growth_Step (1000);
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Shutdown
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Shutdown (void)
{
Free_Objects ();
Free_Categories ();
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Free_Categories
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Free_Categories (void)
{
//
// Loop over and free all the translation categories
//
for (int index = 0; index < m_CategoryList.Count (); index ++) {
TDBCategoryClass *category = m_CategoryList[index];
if (category != NULL) {
delete category;
}
}
m_CategoryList.Delete_All ();
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Free_Objects
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Free_Objects (void)
{
//
// Loop over and free all the translation objects
//
for (int index = 0; index < m_ObjectList.Count (); index ++) {
TDBObjClass *translate_obj = m_ObjectList[index];
if (translate_obj != NULL) {
delete translate_obj;
}
}
m_ObjectList.Delete_All ();
// Remove the stuff from the hash table as well..
m_ObjectHash.Remove_All();
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Contains_Data
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Contains_Data (void) const
{
return true;
}
///////////////////////////////////////////////////////////////////////
//
// Save
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Save (ChunkSaveClass &csave)
{
bool retval = true;
csave.Begin_Chunk (CHUNKID_VARIABLES);
WRITE_MICRO_CHUNK (csave, VARID_VERSION_NUMBER, m_VersionNumber);
WRITE_MICRO_CHUNK (csave, VARID_LANGUAGE_ID, m_LanguageID);
csave.End_Chunk ();
csave.Begin_Chunk (CHUNKID_CATEGORIES);
//
// Loop over and save all the translation categories
//
for (int index = 0; index < m_CategoryList.Count (); index ++) {
TDBCategoryClass *category = m_CategoryList[index];
//
// Save this category
//
if (category != NULL) {
csave.Begin_Chunk (category->Get_Factory ().Chunk_ID ());
category->Get_Factory ().Save (csave, category);
csave.End_Chunk ();
}
}
csave.End_Chunk ();
csave.Begin_Chunk (CHUNKID_OBJECTS);
//
// Loop over and save all the translation objects
//
for (index = 0; index < m_ObjectList.Count (); index ++) {
TDBObjClass *translate_obj = m_ObjectList[index];
//
// Save this translation object
//
if (translate_obj != NULL) {
//
// Check to ensure this category isn't filtered out...
//
bool is_equal = (translate_obj->Get_Category_ID () == FilterCategoryID);
if ( FilterType == FILTER_DISABLED ||
(FilterType == FILTER_IF_EQUAL && is_equal == false) ||
(FilterType == FILTER_IF_NOT_EQUAL && is_equal))
{
csave.Begin_Chunk (translate_obj->Get_Factory ().Chunk_ID ());
translate_obj->Get_Factory ().Save (csave, translate_obj);
csave.End_Chunk ();
}
}
}
csave.End_Chunk ();
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Load
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Load (ChunkLoadClass &cload)
{
Free_Objects ();
Free_Categories ();
bool retval = true;
while (cload.Open_Chunk ()) {
switch (cload.Cur_Chunk_ID ()) {
//
// Load all the presets from this chunk
//
case CHUNKID_VARIABLES:
retval &= Load_Variables (cload);
break;
case CHUNKID_OBJECTS:
retval &= Load_Objects (cload);
break;
case CHUNKID_CATEGORIES:
retval &= Load_Categories (cload);
break;
}
cload.Close_Chunk ();
}
Validate_Data ();
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Load_Categories
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Load_Categories (ChunkLoadClass &cload)
{
bool retval = true;
while (cload.Open_Chunk ()) {
//
// Load this object from the chunk (if possible)
//
PersistFactoryClass *factory = SaveLoadSystemClass::Find_Persist_Factory (cload.Cur_Chunk_ID ());
if (factory != NULL) {
TDBCategoryClass *category = (TDBCategoryClass *)factory->Load (cload);
if (category != NULL) {
Add_Category (category, false);
}
}
cload.Close_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Load_Objects
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Load_Objects (ChunkLoadClass &cload)
{
bool retval = true;
while (cload.Open_Chunk ()) {
//
// Load this object from the chunk (if possible)
//
PersistFactoryClass *factory = SaveLoadSystemClass::Find_Persist_Factory (cload.Cur_Chunk_ID ());
if (factory != NULL) {
TDBObjClass *translate_obj = (TDBObjClass *)factory->Load (cload);
if (translate_obj != NULL) {
Add_Object (translate_obj);
}
}
cload.Close_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Load_Variables
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Load_Variables (ChunkLoadClass &cload)
{
bool retval = true;
while (cload.Open_Micro_Chunk ()) {
switch (cload.Cur_Micro_Chunk_ID ()) {
READ_MICRO_CHUNK (cload, VARID_VERSION_NUMBER, m_VersionNumber);
READ_MICRO_CHUNK (cload, VARID_LANGUAGE_ID, m_LanguageID);
}
cload.Close_Micro_Chunk ();
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Validate_Data
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Validate_Data (void)
{
if (m_CategoryList.Count () == 0) {
//
// Create the default category
//
TDBCategoryClass *category = new TDBCategoryClass;
category->Set_Name ("Default");
m_CategoryList.Add (category);
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Export_Table
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Export_Table (const char *filename)
{
//
// Create the file
//
HANDLE file = ::CreateFile (filename,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0L,
NULL);
WWASSERT (file != INVALID_HANDLE_VALUE);
if (file != INVALID_HANDLE_VALUE) {
TextFileClass file_obj;
file_obj.Attach (file);
//
// Loop over all the translation objects and write a tab delimited
// entry for each one
//
for (int index = 0; index < m_ObjectList.Count (); index ++) {
TDBObjClass *object = m_ObjectList[index];
if (object != NULL && object->As_StringTwiddlerClass () == NULL) {
StringClass english_string = object->Get_English_String ();
int length = english_string.Get_Length ();
for (int index = 0; index < length; index ++) {
if (english_string[index] == '\n') {
english_string[index] = ' ';
}
}
//
// Lookup the string's category
//
StringClass category_name;
TDBCategoryClass *category = Find_Category (object->Get_Category_ID ());
if (category != NULL) {
category_name = category->Get_Name ();
}
//
// Lookup the string's sound preset
//
StringClass sound_preset_name;
DefinitionClass *definition = DefinitionMgrClass::Find_Definition (object->Get_Sound_ID (), false);
if (definition != NULL) {
sound_preset_name = definition->Get_Name ();
}
//
// Write a tab delimited entry for this object
//
StringClass text_entry;
text_entry = category_name;
text_entry += "\t";
text_entry += object->Get_ID_Desc ();
text_entry += "\t";
text_entry += english_string;
text_entry += "\t";
text_entry += sound_preset_name;
file_obj.Write_Line (text_entry);
}
}
//
// Close the file
//
file_obj.Detach ();
::CloseHandle (file);
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Export_C_Header
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Export_C_Header (const char *filename)
{
//
// Create the file
//
HANDLE file = ::CreateFile (filename,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
0L,
NULL);
WWASSERT (file != INVALID_HANDLE_VALUE);
if (file != INVALID_HANDLE_VALUE) {
TextFileClass file_obj;
file_obj.Attach (file);
//
// Wtite the 'C' style header framework
//
file_obj.Write_Line ("#if defined(_MSC_VER)");
file_obj.Write_Line ("#pragma once");
file_obj.Write_Line ("#endif");
file_obj.Write_Line ("");
file_obj.Write_Line ("#ifndef __STRING_IDS_H");
file_obj.Write_Line ("#define __STRING_IDS_H");
file_obj.Write_Line ("");
StringClass version_line;
version_line.Format ("#define STRINGS_VER %d", m_VersionNumber);
file_obj.Write_Line (version_line);
file_obj.Write_Line ("");
file_obj.Write_Line ("// TRANSLATEDB: Begin ID Block");
//
// Loop over all the translation objects and write a #define to the
// header file for each one...
//
for (int index = 0; index < m_ObjectList.Count (); index ++) {
TDBObjClass *object = m_ObjectList[index];
if (object != NULL) {
//
// Write a #define for this object's ID
//
StringClass id_entry;
id_entry.Format ("#define %s %d", (const char *)object->Get_ID_Desc (), object->Get_ID ());
file_obj.Write_Line (id_entry);
}
}
file_obj.Write_Line ("// TRANSLATEDB: End ID Block");
file_obj.Write_Line ("");
file_obj.Write_Line ("#endif //__STRING_IDS_H");
//
// Close the file
//
file_obj.Detach ();
::CloseHandle (file);
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Import_C_Header
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Import_C_Header (const char *filename)
{
//
// Create the file
//
HANDLE file = ::CreateFile (filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0L,
NULL);
WWASSERT (file != INVALID_HANDLE_VALUE);
if (file != INVALID_HANDLE_VALUE) {
TextFileClass file_obj;
file_obj.Attach (file);
StringClass line;
bool found_id_block = false;
//
// Look for the start of the ID block
//
while (found_id_block == false && file_obj.Read_Line (line)) {
found_id_block = (line.Compare_No_Case ("// TRANSLATEDB: Begin ID Block") == 0);
}
if (found_id_block) {
//
// Read each ID define from the header file
//
bool found_end_block = false;
while (found_end_block == false && file_obj.Read_Line (line)) {
if (::strnicmp (line, "#define ", 8) == 0) {
//
// Break the #define into its parts
//
int word_breaks[4] = { 0 };
int curr_break = 0;
//
// Find out where each word begins and ends
//
int count = line.Get_Length ();
for (int index = 8; curr_break < 4 && index < count; index ++) {
bool is_whitespace = (line[index] == ' ' || line[index] == '\t');
if (is_whitespace == (curr_break & 1) || index == count - 1) {
word_breaks[curr_break ++] = index;
}
}
//
// Did we encounter the right number of words?
//
if (curr_break == 4) {
//
// Isolate the words
//
char id_desc_text[64] = { 0 };
char id_text[64] = { 0 };
::strncpy (id_desc_text, line.Peek_Buffer () + word_breaks[0], word_breaks[1] - word_breaks[0]);
::strncpy (id_text, line.Peek_Buffer () + word_breaks[2], word_breaks[3] - word_breaks[2]);
//
// Convert the ID string to a number
//
uint32 id = ::atoi (id_text);
//
// Do we already have this object?
//
TDBObjClass *object = Find_Object (id);
if (object == NULL) {
object = Find_Object (id_desc_text);
if (object == NULL) {
//
// If we didn't already have this object, then create
// a new object and add it to the system
//
object = new TDBObjClass;
object->Set_ID_Desc (id_desc_text);
Add_Object (object);
}
}
}
} else {
//
// Check for block-end conditions
//
found_end_block = (line.Compare_No_Case ("// TRANSLATEDB: End ID Block") == 0);
}
}
}
//
// Close the file
//
file_obj.Detach ();
::CloseHandle (file);
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Get_Object_Count
//
///////////////////////////////////////////////////////////////////////
int
TranslateDBClass::Get_Object_Count (void)
{
return m_ObjectList.Count ();
}
///////////////////////////////////////////////////////////////////////
//
// Get_Object
//
///////////////////////////////////////////////////////////////////////
TDBObjClass *
TranslateDBClass::Get_Object (int index)
{
TDBObjClass *object = NULL;
WWASSERT (index >= 0 && index < m_ObjectList.Count ());
if (index >= 0 && index < m_ObjectList.Count ()) {
object = m_ObjectList[index];
}
return object;
}
///////////////////////////////////////////////////////////////////////
//
// Find_Unique_ID
//
///////////////////////////////////////////////////////////////////////
uint32
TranslateDBClass::Find_Unique_ID (void)
{
uint32 new_id = ID_MIN + m_ObjectList.Count ();
//
// Return the 'id' of the first empty slot in the list
//
for (int index = 0; index < m_ObjectList.Count (); index ++) {
if (m_ObjectList[index] == NULL) {
new_id = (ID_MIN + index);
break;
}
}
return new_id;
}
///////////////////////////////////////////////////////////////////////
//
// Add_Category
//
///////////////////////////////////////////////////////////////////////
TDBCategoryClass *
TranslateDBClass::Add_Category (const char *name)
{
//
// Create the new category
//
TDBCategoryClass *category = new TDBCategoryClass;
category->Set_Name (name);
//
// Add the category to our list and return a pointer to the caller
//
Add_Category (category);
return category;
}
///////////////////////////////////////////////////////////////////////
//
// Add_Category
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Add_Category (TDBCategoryClass *new_category, bool assign_id)
{
bool retval = false;
WWASSERT (new_category != NULL);
if (new_category != NULL) {
//
// Assign this category an ID (if necessary)
//
if (assign_id && new_category->Get_ID () == 0) {
uint32 new_id = 1;
for (int index = 0; index < m_CategoryList.Count (); index ++) {
uint32 curr_id = m_CategoryList[index]->Get_ID ();
new_id = max (curr_id + 1, new_id);
}
new_category->Set_ID (new_id);
}
//
// Add the new category to our list
//
m_CategoryList.Add (new_category);
retval = true;
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Remove_Category
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Remove_Category (int index)
{
bool retval = false;
//
// Make sure this index is in our range
//
WWASSERT (index >= 0 && index < m_CategoryList.Count ());
if (index >= 0 && index < m_CategoryList.Count ()) {
//
// Free the object that was in this slot
//
TDBCategoryClass *category = m_CategoryList[index];
if (category != NULL) {
//
// Remove all objects from the category
//
int category_id = category->Get_ID ();
for ( TDBObjClass *object = Get_First_Object (category_id);
object != NULL;
object = Get_Next_Object (category_id, object))
{
object->Set_Category_ID (CATEGORY_DEFAULT);
}
delete category;
}
//
// Remove the entry from our list
//
m_CategoryList.Delete (index);
retval = true;
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Add_Object
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Add_Object (TDBObjClass *new_obj)
{
bool retval = false;
WWASSERT (new_obj != NULL);
if (new_obj != NULL) {
//
// Try to find an unused ID for the object (if necessary)
//
if (new_obj->Get_ID () < ID_MIN) {
new_obj->Set_ID (Find_Unique_ID ());
}
//
// Determine where in the list this object should
// be inserted
//
int new_id = new_obj->Get_ID ();
int obj_index = new_id - ID_MIN;
//
// Grow the list up to the number of elements we need
//
while (m_ObjectList.Count () <= obj_index) {
m_ObjectList.Add (NULL);
}
//
// Add the object to our list
//
m_ObjectList[obj_index] = new_obj;
// Insert object to the hash table as well...
StringClass lower_case_name(new_obj->Get_ID_Desc(),true);
_strlwr(lower_case_name.Peek_Buffer());
m_ObjectHash.Insert(lower_case_name,new_obj);
retval = true;
}
return retval;
}
///////////////////////////////////////////////////////////////////////
//
// Remove_Object
//
///////////////////////////////////////////////////////////////////////
bool
TranslateDBClass::Remove_Object (int index)
{
bool retval = false;
//
// Make sure this index is in our range
//
WWASSERT (index >= 0 && index < m_ObjectList.Count ());
if (index >= 0 && index < m_ObjectList.Count ()) {
//
// Free the object that was in this slot
//
TDBObjClass *object = m_ObjectList[index];
if (object != NULL) {
// Remove the object from the hash table
StringClass lower_case_name(object->Get_ID_Desc(),true);
_strlwr(lower_case_name.Peek_Buffer());
m_ObjectHash.Remove(lower_case_name);
delete object;
}
//
// Remove the pointer from the list and re-assign IDs
//
m_ObjectList[index] = NULL;
retval = true;
}
return retval;
}
//////////////////////////////////////////////////////////////
//
// Remove_All
//
//////////////////////////////////////////////////////////////
void
TranslateDBClass::Remove_All (void)
{
Free_Objects ();
return ;
}
//////////////////////////////////////////////////////////////
//
// Get_Version_Number
//
//////////////////////////////////////////////////////////////
uint32
TranslateDBClass::Get_Version_Number (void)
{
return m_VersionNumber;
}
//////////////////////////////////////////////////////////////
//
// Update_Version
//
//////////////////////////////////////////////////////////////
void
TranslateDBClass::Update_Version (void)
{
m_VersionNumber ++;
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Get_Category_Count
//
///////////////////////////////////////////////////////////////////////
int
TranslateDBClass::Get_Category_Count (void)
{
return m_CategoryList.Count ();
}
///////////////////////////////////////////////////////////////////////
//
// Get_Category
//
///////////////////////////////////////////////////////////////////////
TDBCategoryClass *
TranslateDBClass::Get_Category (int index)
{
TDBCategoryClass *category = NULL;
WWASSERT (index >= 0 && index < m_CategoryList.Count ());
if (index >= 0 && index < m_CategoryList.Count ()) {
category = m_CategoryList[index];
}
return category;
}
///////////////////////////////////////////////////////////////////////
//
// Find_Category
//
///////////////////////////////////////////////////////////////////////
TDBCategoryClass *
TranslateDBClass::Find_Category (uint32 id)
{
TDBCategoryClass *category = NULL;
//
// Loop over all the categories until we've found a matching ID
//
for (int index = 0; index < m_CategoryList.Count (); index ++) {
if (m_CategoryList[index]->Get_ID () == id) {
category = m_CategoryList[index];
break;
}
}
return category;
}
///////////////////////////////////////////////////////////////////////
//
// Find_Category
//
///////////////////////////////////////////////////////////////////////
TDBCategoryClass *
TranslateDBClass::Find_Category (const char *name)
{
TDBCategoryClass *category = NULL;
//
// Loop over all the categories until we've found a matching name
//
for (int index = 0; index < m_CategoryList.Count (); index ++) {
if (m_CategoryList[index]->Get_Name ().Compare_No_Case (name) == 0) {
category = m_CategoryList[index];
break;
}
}
return category;
}
///////////////////////////////////////////////////////////////////////
//
// Get_First_Object
//
///////////////////////////////////////////////////////////////////////
TDBObjClass *
TranslateDBClass::Get_First_Object (uint32 category_id)
{
TDBObjClass *object = NULL;
//
// Loop over the objects we know about and return the first
// one that matches the given category ID
//
for (int index = 0; index < m_ObjectList.Count (); index ++) {
TDBObjClass *curr_obj = m_ObjectList[index];
if (curr_obj != NULL) {
//
// Does this object belong to the category we are enumerating?
//
if (curr_obj->Get_Category_ID () == category_id) {
object = curr_obj;
break;
}
}
}
return object;
}
///////////////////////////////////////////////////////////////////////
//
// Get_Next_Object
//
///////////////////////////////////////////////////////////////////////
TDBObjClass *
TranslateDBClass::Get_Next_Object (uint32 category_id, TDBObjClass *curr_obj)
{
//
// Sanity check
//
if (curr_obj == NULL) {
return NULL;
}
TDBObjClass *object = NULL;
//
// Determine where in the list to start looking
//
int start_index = (curr_obj->Get_ID () - ID_MIN) + 1;
//
// Loop over the objects we know about and return the first
// one that matches the given category ID
//
for (int index = start_index; index < m_ObjectList.Count (); index ++) {
TDBObjClass *curr_obj = m_ObjectList[index];
if (curr_obj != NULL) {
//
// Does this object belong to the category we are enumerating?
//
if (curr_obj->Get_Category_ID () == category_id) {
object = curr_obj;
break;
}
}
}
return object;
}
/////////////////////////////////////////////////////////////////////////////
//
// Convert_Chars_To_Newline
//
/////////////////////////////////////////////////////////////////////////////
void
Convert_Chars_To_Newline (StringClass &string)
{
StringClass retval;
int count = string.Get_Length ();
//
// Copy characters between the strings
//
for (int index = 0; index < count; index ++) {
if (index + 1 < count && string[index] == '\\' && string[index + 1] == 'n') {
retval += '\n';
index ++;
} else {
retval += string[index];
}
}
string = retval;
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Import_Strings
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Import_Strings (const char *filename)
{
//
// Open the file
//
HANDLE file = ::CreateFile ( filename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
0L,
NULL);
WWASSERT (file != INVALID_HANDLE_VALUE);
if (file != INVALID_HANDLE_VALUE) {
//
// Attach this file to a text file class for easier parsing
//
TextFileClass file_obj;
file_obj.Attach (file);
//
// Keep reading data from the file until we've reached the end
// of the file or the data becomes corrupt
//
bool keep_going = true;
StringClass line;
while (keep_going && file_obj.Read_Line (line)) {
//
// Convert the string to an array of values
//
StringClass *value_array = NULL;
int value_count = Build_List_From_String (line, "\t", &value_array);
//
// We can't keep going unless we've got at least 3 columns of information
//
if (value_count >= 3) {
//
// Lookup the category this entry belongs to
//
TDBCategoryClass *category = Find_Category (value_array[0]);
//
// Create the entry
//
TDBObjClass *new_obj = new TDBObjClass;
new_obj->Set_Category_ID (category ? category->Get_ID () : 0);
new_obj->Set_ID_Desc (value_array[1]);
//
// Set the english string
//
StringClass english_string = value_array[2];
::Convert_Chars_To_Newline (english_string);
new_obj->Set_English_String (english_string);
//
// If necessary, lookup the sound definition that goes with this new entry
// and plug in its ID.
//
if (value_count >= 4) {
DefinitionClass *definition = DefinitionMgrClass::Find_Typed_Definition (value_array[3], CLASSID_SOUND, false);
if (definition != NULL) {
new_obj->Set_Sound_ID (definition->Get_ID ());
}
}
//
// Add this object to the database
//
Add_Object (new_obj);
}
//
// Cleanup
//
if (value_array != NULL) {
delete [] value_array;
value_array = NULL;
}
}
}
return ;
}
///////////////////////////////////////////////////////////////////////
//
// Build_List_From_String
//
///////////////////////////////////////////////////////////////////////
int Build_List_From_String
(
const char * buffer,
const char * delimiter,
StringClass ** string_list
)
{
int count = 0;
WWASSERT (buffer != NULL);
WWASSERT (delimiter != NULL);
WWASSERT (string_list != NULL);
if ((buffer != NULL) &&
(delimiter != NULL) &&
(string_list != NULL))
{
int delim_len = ::strlen (delimiter);
//
// Determine how many entries there will be in the list
//
for (const char *entry = buffer;
(entry != NULL) && (entry[1] != 0);
entry = ::strstr (entry, delimiter))
{
//
// Move past the current delimiter (if necessary)
//
if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
entry += delim_len;
}
// Increment the count of entries
count ++;
}
if (count > 0) {
//
// Allocate enough StringClass objects to hold all the strings in the list
//
(*string_list) = new StringClass[count];
//
// Parse the string and pull out its entries.
//
count = 0;
for (entry = buffer;
(entry != NULL) && (entry[1] != 0);
entry = ::strstr (entry, delimiter))
{
//
// Move past the current delimiter (if necessary)
//
if ((::strnicmp (entry, delimiter, delim_len) == 0) && (count > 0)) {
entry += delim_len;
}
//
// Copy this entry into its own string
//
StringClass entry_string = entry;
char *delim_start = ::strstr (entry_string, delimiter);
if (delim_start != NULL) {
delim_start[0] = 0;
}
//
// Add this entry to our list
//
if ((entry_string.Get_Length () > 0) || (count == 0)) {
(*string_list)[count++] = entry_string;
}
}
} else if (delim_len > 0) {
count = 1;
(*string_list) = new StringClass[count];
(*string_list)[0] = buffer;
}
}
//
// Return the number of entries in our list
//
return count;
}
///////////////////////////////////////////////////////////////////////
//
// Set_Export_Filter
//
///////////////////////////////////////////////////////////////////////
void
TranslateDBClass::Set_Export_Filter (FILTER_OPT filter, uint32 category_id)
{
FilterType = filter;
FilterCategoryID = category_id;
return ;
}