324 lines
8.1 KiB
C++
324 lines
8.1 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/Tools/LevelEdit/rcstringextractor.cpp $*
|
|
* *
|
|
* Author:: Patrick Smith *
|
|
* *
|
|
* $Modtime:: 10/29/01 11:08a $*
|
|
* *
|
|
* $Revision:: 2 $*
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "stdafx.h"
|
|
#include "rcstringextractor.h"
|
|
#include "translatedb.h"
|
|
#include "stringsmgr.h"
|
|
#include "textfile.h"
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// RCStringExtractorClass
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
RCStringExtractorClass::RCStringExtractorClass (void) :
|
|
CategoryIndex (0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_String
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
bool
|
|
RCStringExtractorClass::Find_String
|
|
(
|
|
StringClass & line,
|
|
const char * keyword,
|
|
const char * replacement,
|
|
StringClass & contents
|
|
)
|
|
{
|
|
bool retval = false;
|
|
|
|
StringClass new_line = line;
|
|
|
|
//
|
|
// Did we find the keyword?
|
|
//
|
|
char *buffer = ::strstr (new_line, keyword);
|
|
if (buffer != NULL) {
|
|
buffer += ::lstrlen (keyword);
|
|
|
|
//
|
|
// Skip to the start of the string
|
|
//
|
|
bool found_start = false;
|
|
while (buffer[0] != 0) {
|
|
if (buffer[0] == '\"') {
|
|
buffer ++;
|
|
found_start = true;
|
|
break;
|
|
}
|
|
|
|
buffer ++;
|
|
}
|
|
|
|
if (found_start) {
|
|
|
|
//
|
|
// Skip past any format specifiers
|
|
//
|
|
if (buffer[0] == '%') {
|
|
buffer += 2;
|
|
}
|
|
|
|
//
|
|
// Record the start and end of the string
|
|
//
|
|
bool found_end = false;
|
|
char *start = buffer;
|
|
while (buffer[0] != 0) {
|
|
if (buffer[0] == '\"') {
|
|
found_end = true;
|
|
break;
|
|
}
|
|
|
|
buffer ++;
|
|
}
|
|
|
|
if (found_end) {
|
|
char *end = buffer;
|
|
|
|
//
|
|
// Return the contents to the caller
|
|
//
|
|
end[0] = 0;
|
|
contents = start;
|
|
|
|
if (contents.Get_Length () > 0) {
|
|
|
|
//
|
|
// Check to ensure this isn't already a translation string
|
|
//
|
|
if (::strstr (contents, "IDS_") == NULL) {
|
|
|
|
//
|
|
// Now fill in the replacement
|
|
//
|
|
start[0] = 0;
|
|
line = new_line.Peek_Buffer ();
|
|
line += replacement;
|
|
line += "\"";
|
|
line += end + 1;
|
|
retval = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Process_Line
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
void
|
|
RCStringExtractorClass::Process_Line (StringClass &line, int ¤t_index)
|
|
{
|
|
StringClass contents;
|
|
|
|
const char *KEYWORDS[] =
|
|
{
|
|
"CAPTION",
|
|
"LTEXT",
|
|
"PUSHBUTTON",
|
|
"CONTROL",
|
|
"RTEXT",
|
|
"CTEXT"
|
|
};
|
|
|
|
const int KEYWORD_COUNT = sizeof (KEYWORDS) / sizeof (const char *);
|
|
|
|
//
|
|
// Make a string identifier from the prefix and the current index
|
|
//
|
|
StringClass string_id;
|
|
string_id.Format ("%s%.3d", Prefix.Peek_Buffer (), current_index);
|
|
|
|
//
|
|
// Check to see if this line is one of the ones we need to process
|
|
//
|
|
for (int index = 0; index < KEYWORD_COUNT; index ++) {
|
|
if (Find_String (line, KEYWORDS[index], string_id, contents)) {
|
|
|
|
//
|
|
// Create a new translation DB entry for this string
|
|
//
|
|
TDBObjClass *new_obj = new TDBObjClass;
|
|
new_obj->Set_English_String (contents);
|
|
new_obj->Set_ID_Desc (string_id);
|
|
new_obj->Set_Category_ID (CategoryIndex);
|
|
|
|
//
|
|
// Add the new object to the database
|
|
//
|
|
TranslateDBClass::Add_Object (new_obj);
|
|
current_index ++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set_Src_RC_Filename
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void
|
|
RCStringExtractorClass::Set_Src_RC_Filename (const char *full_path)
|
|
{
|
|
SrcFilename = full_path;
|
|
DestFilename = SrcFilename + "_extracted";
|
|
return ;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Extract_Strings
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void
|
|
RCStringExtractorClass::Extract_Strings (void)
|
|
{
|
|
//
|
|
// Check out the strings database
|
|
//
|
|
if (StringsMgrClass::Check_Out ()) {
|
|
|
|
CategoryIndex = 0;
|
|
|
|
//
|
|
// Try to find the category these strings are to be imported into
|
|
//
|
|
TDBCategoryClass *category = TranslateDBClass::Find_Category (CategoryName);
|
|
if (category != NULL) {
|
|
CategoryIndex = category->Get_ID ();
|
|
}
|
|
|
|
//
|
|
// Try to open the .RC file
|
|
//
|
|
TextFileClass file (SrcFilename);
|
|
TextFileClass output_file (DestFilename);
|
|
if (file.Open (RawFileClass::READ) && output_file.Open (RawFileClass::WRITE)) {
|
|
|
|
//
|
|
// Determine where to start our numbering scheme
|
|
//
|
|
int current_index = Find_Starting_Index ();
|
|
|
|
//
|
|
// Read each line from the file
|
|
//
|
|
StringClass curr_line;
|
|
while (file.Read_Line (curr_line)) {
|
|
|
|
Process_Line (curr_line, current_index);
|
|
|
|
curr_line += "\r\n";
|
|
output_file.Write (curr_line, ::lstrlen (curr_line));
|
|
}
|
|
|
|
//
|
|
// Close the files
|
|
//
|
|
file.Close ();
|
|
output_file.Close ();
|
|
}
|
|
|
|
//
|
|
// Save the translation database and check it back into VSS
|
|
//
|
|
StringsMgrClass::Save_Translation_Database ();
|
|
StringsMgrClass::Check_In ();
|
|
}
|
|
|
|
return ;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find_Starting_Index
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int
|
|
RCStringExtractorClass::Find_Starting_Index (void)
|
|
{
|
|
int max_index = 0;
|
|
|
|
int prefix_len = Prefix.Get_Length ();
|
|
|
|
//
|
|
// Loop over all the objects in the translation database
|
|
//
|
|
int count = TranslateDBClass::Get_Object_Count ();
|
|
for (int index = 0; index < count; index ++) {
|
|
TDBObjClass *obj = TranslateDBClass::Get_Object (index);
|
|
if (obj != NULL) {
|
|
|
|
//
|
|
// Is this one of the strings we care about?
|
|
//
|
|
const StringClass &string_desc = obj->Get_ID_Desc ();
|
|
if (::strnicmp (Prefix, string_desc, prefix_len) == 0) {
|
|
|
|
//
|
|
// Check to see if this is the largest index we've found yet
|
|
//
|
|
const char *suffix = (string_desc.Peek_Buffer () + prefix_len);
|
|
int number = ::atoi (suffix);
|
|
max_index = max (number, max_index);
|
|
}
|
|
}
|
|
}
|
|
|
|
return max_index + 1;
|
|
}
|