1377 lines
32 KiB
C++
1377 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 ;
|
||
|
}
|