| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793 |
- /*
- ** 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/Tools/LevelEdit/stringsmgr.cpp $*
- * *
- * Author:: Patrick Smith *
- * *
- * $Modtime:: 2/12/02 6:16p $*
- * *
- * $Revision:: 14 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "stdafx.h"
- #include "stringsmgr.h"
- #include "filelocations.h"
- #include "filemgr.h"
- #include "assetdatabase.h"
- #include "chunkio.h"
- #include "rawfile.h"
- #include "saveload.h"
- #include "translatedb.h"
- #include "stringlibrarydialog.h"
- #include "excel.h"
- #include "audiblesound.h"
- #include "definitionmgr.h"
- #include "definitionclassids.h"
- #include "utils.h"
- /////////////////////////////////////////////////////////////////////////
- // Local constants
- /////////////////////////////////////////////////////////////////////////
- enum
- {
- COL_CATEGORY_NAME = 0,
- COL_STRING_ID,
- COL_SOUND_FILENAME,
- COL_ENGLISH_TEXT,
- COL_TRANSLATED_TEXT,
- COL_COMMENTS,
- COL_ERRORS,
- COL_SOUND_PRESET_NAME,
- };
- /////////////////////////////////////////////////////////////////////////
- //
- // Create_Database_If_Necessary
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Create_Database_If_Necessary (void)
- {
- FileMgrClass *file_mgr = ::Get_File_Mgr ();
- AssetDatabaseClass &asset_db = file_mgr->Get_Database_Interface ();
-
- //
- // Determine where the file should exist locally
- //
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
- //
- // Check to see if the file exists in VSS
- //
- if (asset_db.Does_File_Exist (filename) == false) {
-
- //
- // Save a copy of the database to disk and add it to VSS
- //
- Save_Translation_Database ();
- asset_db.Add_File (filename);
- } else {
-
- //
- // The file exists in VSS, so update our local copy
- //
- Get_Latest_Version ();
- }
-
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Save_Translation_Database
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Save_Translation_Database (void)
- {
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
- Save_Translation_Database (filename);
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Save_Translation_Database
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Save_Translation_Database (const char *full_path)
- {
- //
- // Create the file
- //
- HANDLE file = ::CreateFile (full_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
- 0L, NULL);
- ASSERT (file != INVALID_HANDLE_VALUE);
- if (file != INVALID_HANDLE_VALUE) {
- RawFileClass file_obj;
- file_obj.Attach (file);
- ChunkSaveClass chunk_save (&file_obj);
- //
- // Save the translation database subsystem
- //
- SaveLoadSystemClass::Save (chunk_save, _TheTranslateDB);
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Load_Translation_Database
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Load_Translation_Database (void)
- {
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
- //
- // Open the file
- //
- HANDLE file = ::CreateFile (filename, GENERIC_READ, FILE_SHARE_READ, NULL,
- OPEN_EXISTING, 0L, NULL);
- ASSERT (file != INVALID_HANDLE_VALUE);
- if (file != INVALID_HANDLE_VALUE) {
- RawFileClass file_obj;
- file_obj.Attach (file);
- ChunkLoadClass chunk_load (&file_obj);
- //
- // Let the save/load system handle the laod
- //
- SaveLoadSystemClass::Load (chunk_load);
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Import_Strings
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Import_Strings (void)
- {
- CFileDialog dialog (TRUE, ".txt", "strings.txt",
- OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
- "Text Files (*.txt)|*.txt||", ::AfxGetMainWnd ());
- dialog.m_ofn.lpstrTitle = "Import Strings";
- //
- // Ask the user what file they want to load
- //
- if (dialog.DoModal () == IDOK) {
- if (Check_Out ()) {
- //
- // Import the strings and save the database back to disk
- //
- TranslateDBClass::Import_Strings (dialog.GetPathName ());
- Save_Translation_Database ();
- Check_In ();
- }
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Import_IDs
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Import_IDs (void)
- {
- CFileDialog dialog (TRUE, ".h", "string_ids.h",
- OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
- "C Header Files (*.h)|*.h||", ::AfxGetMainWnd ());
- //
- // Ask the user what file they want to load
- //
- if (dialog.DoModal () == IDOK) {
- if (Check_Out ()) {
- //
- // Import the header and save the database back to disk
- //
- TranslateDBClass::Import_C_Header (dialog.GetPathName ());
- Save_Translation_Database ();
- Check_In ();
- }
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Export_IDs
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Export_IDs (void)
- {
- CFileDialog dialog (FALSE, ".h", "string_ids.h",
- OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT | OFN_EXPLORER,
- "C Header Files (*.h)|*.h||", ::AfxGetMainWnd ());
- //
- // Ask the user what file they want to create
- //
- if (dialog.DoModal () == IDOK) {
- //
- // Check to make sure the destination filename is not read-only
- //
- CString path = dialog.GetPathName ();
- DWORD file_attributes = ::GetFileAttributes (path);
- if (file_attributes != 0xFFFFFFFF && file_attributes & FILE_ATTRIBUTE_READONLY) {
- ::MessageBox (::AfxGetMainWnd ()->m_hWnd, "File is read-only, export operation can not complete.", "File Error", MB_ICONERROR | MB_ICONEXCLAMATION);
- } else {
- TranslateDBClass::Export_C_Header (path);
- }
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Get_Latest_Version
- //
- /////////////////////////////////////////////////////////////////////////
- bool
- StringsMgrClass::Get_Latest_Version (void)
- {
- FileMgrClass *file_mgr = ::Get_File_Mgr ();
- AssetDatabaseClass &asset_db = file_mgr->Get_Database_Interface ();
-
- //
- // Determine where the file should exist locally
- //
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
-
- //
- // Ask VSS to get the latest version of the file for us
- //
- return asset_db.Get (filename);
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Check_Out
- //
- /////////////////////////////////////////////////////////////////////////
- bool
- StringsMgrClass::Check_Out (void)
- {
- FileMgrClass *file_mgr = ::Get_File_Mgr ();
- AssetDatabaseClass &asset_db = file_mgr->Get_Database_Interface ();
-
- //
- // Determine where the file should exist locally
- //
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
-
- //
- // Ask VSS to check out the file to us
- //
- return asset_db.Check_Out_Ex (filename, ::AfxGetMainWnd ()->m_hWnd);
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Check_In
- //
- /////////////////////////////////////////////////////////////////////////
- bool
- StringsMgrClass::Check_In (void)
- {
- FileMgrClass *file_mgr = ::Get_File_Mgr ();
- AssetDatabaseClass &asset_db = file_mgr->Get_Database_Interface ();
-
- //
- // Determine where the file should exist locally
- //
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
-
- //
- // Ask VSS to check in the file for us
- //
- return asset_db.Check_In_Ex (filename, ::AfxGetMainWnd ()->m_hWnd);
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Undo_Check_Out
- //
- /////////////////////////////////////////////////////////////////////////
- bool
- StringsMgrClass::Undo_Check_Out (void)
- {
- FileMgrClass *file_mgr = ::Get_File_Mgr ();
- AssetDatabaseClass &asset_db = file_mgr->Get_Database_Interface ();
- bool retval = false;
- //
- // Determine where the file should exist locally
- //
- CString filename = ::Get_File_Mgr ()->Make_Full_Path (STRINGS_DB_PATH);
- //
- // We only undo the checkout if its checked out to us
- //
- if (asset_db.Get_File_Status (filename) == AssetDatabaseClass::CHECKED_OUT_TO_ME) {
- retval = asset_db.Undo_Check_Out (filename);
- }
- return retval;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Edit_Database
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Edit_Database (HWND parent_wnd)
- {
- CWaitCursor wait_cursor;
- //
- // Check out the strings database from VSS
- //
- if (StringsMgrClass::Check_Out ()) {
- //
- // Reload the database
- //
- StringsMgrClass::Load_Translation_Database ();
-
- //
- // Show a dialog to the user so then can edit the strings
- //
- StringLibraryDialogClass dialog (CWnd::FromHandle (parent_wnd));
- if (dialog.DoModal () == IDOK) {
- StringsMgrClass::Save_Translation_Database ();
- StringsMgrClass::Check_In ();
- } else {
- StringsMgrClass::Undo_Check_Out ();
- }
- }
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Export_For_Translation
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Export_For_Translation (const char *filename, uint32 lang_id)
- {
- CWaitCursor wait_cursor;
- if (ExcelClass::Initialize () == false) {
- ::MessageBox (::AfxGetMainWnd ()->m_hWnd, "Cannot Initialize Excel, this feature requires Excel installed on the machine.", "Export Error", MB_ICONERROR | MB_OK);
- return ;
- }
- //
- // Overwrite any existing files
- //
- if (GetFileAttributes (filename) != 0xFFFFFFFF) {
- ::DeleteFile (filename);
- }
- //
- // Lookup the path of the executable
- //
- char path[MAX_PATH] = { 0 };
- ::GetModuleFileName (NULL, path, sizeof (path));
- //
- // Strip off the filename
- //
- char *filename_portion = ::strrchr (path, '\\');
- if (filename_portion != NULL) {
- filename_portion[0] = 0;
- }
- //
- // Create the new excel workbook based on this template
- //
- StringClass template_path = Make_Path (path, "renegade.xlt");
- ExcelClass::New_Workbook (template_path);
- //
- // Loop over all the strings in the database
- //
- int count = TranslateDBClass::Get_Object_Count ();
- for (int index = 0; index < count; index ++) {
- TDBObjClass *object = TranslateDBClass::Get_Object (index);
- if (object != NULL && object->As_StringTwiddlerClass () == NULL) {
-
- //
- // Get the data for this string that we want to export
- //
- const StringClass &string = object->Get_English_String ();
- const StringClass &string_id = object->Get_ID_Desc ();
- int sound_preset_id = object->Get_Sound_ID ();
- int category_id = object->Get_Category_ID ();
- const WideStringClass &foreign_string = object->Get_String (lang_id);
- //
- // Dig out the filename from the sound object
- //
- WideStringClass wide_sound_filename;
- WideStringClass wide_sound_preset_name;
- AudibleSoundDefinitionClass *sound_def = (AudibleSoundDefinitionClass *)DefinitionMgrClass::Find_Definition (sound_preset_id, false);
- if (sound_def != NULL) {
- wide_sound_preset_name.Convert_From (sound_def->Get_Name ());
- CString ascii_filename = ::Get_Filename_From_Path (sound_def->Get_Filename ());
- wide_sound_filename.Convert_From ((const char *)ascii_filename);
- }
- //
- // Lookup the category name
- //
- WideStringClass category_name;
- TDBCategoryClass *category = TranslateDBClass::Find_Category (category_id);
- if (category != NULL) {
- category_name.Convert_From (category->Get_Name ());
- }
- //
- // Convert the data to wide character format
- //
- WideStringClass wide_string;
- WideStringClass wide_string_id;
- wide_string.Convert_From (string);
- wide_string_id.Convert_From (string_id);
- //
- // Convert any newline characters to string literals
- //
- Convert_Newline_To_Chars (wide_string);
- //
- // Put this data into the cells
- //
- ExcelClass::Set_String (index + 1, COL_CATEGORY_NAME, category_name);
- ExcelClass::Set_String (index + 1, COL_STRING_ID, wide_string_id);
- ExcelClass::Set_String (index + 1, COL_SOUND_FILENAME, wide_sound_filename);
- ExcelClass::Set_String (index + 1, COL_ENGLISH_TEXT, wide_string);
- ExcelClass::Set_String (index + 1, COL_SOUND_PRESET_NAME,wide_sound_preset_name);
- if (lang_id != TranslateDBClass::LANGID_ENGLISH && object->Contains_Translation (lang_id)) {
- ExcelClass::Set_String (index + 1, COL_TRANSLATED_TEXT, foreign_string);
- }
- }
- }
- //
- // Save our changes
- //
- ExcelClass::Save_Workbook (filename);
- ExcelClass::Shutdown ();
- return ;
- }
- /////////////////////////////////////////////////////////////////////////
- //
- // Import_From_Translation
- //
- /////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Import_From_Translation (const char *filename, uint32 lang_id)
- {
- CWaitCursor wait_cursor;
- if (ExcelClass::Initialize () == false) {
- ::MessageBox (::AfxGetMainWnd ()->m_hWnd, "Cannot Initialize Excel, this feature requires Excel installed on the machine.", "Export Error", MB_ICONERROR | MB_OK);
- return ;
- }
- if (Check_Out () == false) {
- return ;
- }
- //
- // Open the workbook
- //
- ExcelClass::Open_Workbook (filename);
- //
- // Keep reading until we don't have any more data to read
- //
- bool keep_going = true;
- for (int index = 0; keep_going; index ++) {
- //
- // Read these fields of data
- //
- WideStringClass category_name;
- WideStringClass string_id;
- WideStringClass english_string;
- WideStringClass string;
- WideStringClass preset_name;
- ExcelClass::Get_String (index + 1, COL_CATEGORY_NAME, category_name);
- ExcelClass::Get_String (index + 1, COL_STRING_ID, string_id);
- ExcelClass::Get_String (index + 1, COL_ENGLISH_TEXT, english_string);
- ExcelClass::Get_String (index + 1, COL_TRANSLATED_TEXT, string);
- ExcelClass::Get_String (index + 1, COL_SOUND_PRESET_NAME,preset_name);
- //
- // Convert any typed newline literals "\n" to characters '\n'
- //
- Convert_Chars_To_Newline (english_string);
- Convert_Chars_To_Newline (string);
- Apply_Characteristics (english_string, string);
- //
- // Did we find the data?
- //
- if (string_id.Is_Empty ()) {
- keep_going = false;
- } else {
-
- StringClass ascii_string_id;
- string_id.Convert_To (ascii_string_id);
- //
- // Find or add this object to our database
- //
- TDBObjClass *object = TranslateDBClass::Find_Object (ascii_string_id);
- if ((object == NULL) && (lang_id == TranslateDBClass::LANGID_ENGLISH)) {
- object = new TDBObjClass;
- object->Set_ID_Desc (ascii_string_id);
- TranslateDBClass::Add_Object (object);
- }
- if (object != NULL) {
- //
- // Set the string for this language
- //
- if (lang_id != TranslateDBClass::LANGID_ENGLISH) {
- object->Set_String (lang_id, string);
- } else {
- object->Set_String (TranslateDBClass::LANGID_ENGLISH, english_string);
- }
- //
- // Find or add the category
- //
- StringClass ascii_category_name;
- category_name.Convert_To (ascii_category_name);
- TDBCategoryClass *category = TranslateDBClass::Find_Category (ascii_category_name);
- if (category == NULL && ascii_category_name.Get_Length () > 0) {
- category = new TDBCategoryClass;
- category->Set_Name (ascii_category_name);
- TranslateDBClass::Add_Category (category, true);
- }
- //
- // Set the category
- //
- if (category != NULL) {
- object->Set_Category_ID (category->Get_ID ());
- }
- //
- // Find the sound preset
- //
- StringClass ascii_preset_name;
- preset_name.Convert_To (ascii_preset_name);
- DefinitionClass *definition = DefinitionMgrClass::Find_Typed_Definition (ascii_preset_name, CLASSID_SOUND, false);
- if (definition != NULL) {
- object->Set_Sound_ID (definition->Get_ID ());
- }
- }
- }
- }
- //
- // Let the user know how many strings were imported
- //
- CString message;
- message.Format ("Successfully imported %d strings.", index);
- ::MessageBox (::AfxGetMainWnd ()->m_hWnd, message, "String Import", MB_ICONEXCLAMATION | MB_OK);
- //
- // Close Excel and save the changes to the database
- //
- ExcelClass::Shutdown ();
- Save_Translation_Database ();
- Check_In ();
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Convert_Newline_To_Chars
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Convert_Newline_To_Chars (WideStringClass &string)
- {
- WideStringClass retval;
- //
- // Take a guess as to how large to make the final string
- //
- int count = string.Get_Length ();
- //
- // Copy characters between the strings
- //
- for (int index = 0; index < count; index ++) {
-
- if (string[index] == L'\n') {
- retval += L"\\n";
- } else if (string[index] == L'\t') {
- retval += L"\\t";
- } else {
- retval += string[index];
- }
- }
- string = retval;
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Convert_Chars_To_Newline
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Convert_Chars_To_Newline (WideStringClass &string)
- {
- WideStringClass retval;
-
- //
- // Take a guess as to how large to make the final string
- //
- int count = string.Get_Length ();
- //
- // Copy characters between the strings
- //
- for (int index = 0; index < count; index ++) {
-
- if (index + 1 < count && string[index] == L'\\' && string[index + 1] == L'n') {
- retval += L'\n';
- index ++;
- } else if (index + 1 < count && string[index] == L'\\' && string[index + 1] == L't') {
- retval += L'\t';
- index ++;
- } else {
- retval += string[index];
- }
- }
- string = retval;
- return ;
- }
- /////////////////////////////////////////////////////////////////////////////
- //
- // Apply_Characteristics
- //
- /////////////////////////////////////////////////////////////////////////////
- void
- StringsMgrClass::Apply_Characteristics
- (
- WideStringClass &english_string,
- WideStringClass &translated_string
- )
- {
- int english_len = english_string.Get_Length ();
- int trans_len = translated_string.Get_Length ();
- if (english_len == 0 || trans_len == 0) {
- return ;
- }
- /*if (english_len > 2 && trans_len > 2) {
- //
- // Check to see if the english string is commented out
- ///
- const WCHAR *buffer = english_string;
- if (buffer[0] == L'/' && buffer[1] == L'/') {
-
- //
- // Do we need to comment out the translated string as well?
- //
- const WCHAR *trans_buffer = translated_string;
- if (trans_buffer[0] != L'/' || trans_buffer[1] != L'/') {
-
- //
- // Prepend the forward slashes
- //
- WideStringClass temp_string = L"//";
- temp_string += translated_string;
- translated_string = temp_string;
- trans_len = translated_string.Get_Length ();
- }
- }
- }*/
- //
- // Concatenate a '\n' onto the end of the translated string, if
- // there's one at the end of the english string
- //
- const WCHAR *buffer = english_string;
- if (buffer[english_len - 1] == L'\n') {
- const WCHAR *trans_buffer = translated_string;
- if (trans_buffer[trans_len - 1] != L'\n') {
- translated_string += L"\n";
- }
- }
- return ;
- }
|