daedalus/Source/SysPSP/Utility/Translate.cpp
2022-05-03 22:20:05 +10:00

314 lines
7.8 KiB
C++

/*
Copyright (C) 2012 Salvy6735
Copyright (C) 2012 StrmnNrmn
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 2
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, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "BuildOptions.h"
#include "Base/Types.h"
#include <stdio.h>
#include <vector>
#include <string>
#include "System/IO.h"
#include "Utility/StringUtil.h"
#include "SysPSP/Utility/Translate.h"
#include "SysPSP/Utility/VolatileMem.h"
#include "Base/Macros.h"
#define TRANSLATE_DUMP_VALUE 0xDAEDDAED
//*****************************************************************************
//
//*****************************************************************************
struct pTranslate
{
u32 hash; // hash that corresponds to string
// u32 len; // lenght of the translated string
char *translated; // Translated string
};
pTranslate text[180];
std::vector<std::string> gLanguage;
//
// Hash was taken from http://stackoverflow.com/questions/98153/whats-the-best-hashing-algorithm-to-use-on-a-stl-string-when-using-hash-map
//
//*****************************************************************************
//
//*****************************************************************************
u32 HashString(const char* s)
{
u32 hash = 0;
while (*s)
{
hash = hash * 101 + *s++;
}
return hash;
}
//*****************************************************************************
//
//*****************************************************************************
const char * Translate_Strings(const char *original, u32 & len)
{
u32 hash = HashString(original);
if( hash == 0 )
return original;
for( u32 i=0; i < ARRAYSIZE(text); i++ )
{
// ToDo..
//DAEDALUS_ASSERT( text[i].translated != original, " String already translated" );
if( text[i].hash == hash )
{
if( text[i].translated )
{
len = strlen( text[i].translated );
return text[i].translated;
}
else
return original;
}
}
return original;
}
//*****************************************************************************
//
//*****************************************************************************
const char * Translate_String(const char *original)
{
u32 dummy;
return Translate_Strings( original, dummy );
}
//*****************************************************************************
//
//*****************************************************************************
void Translate_Unload()
{
// Clear translations
for( u32 i = 0; i < ARRAYSIZE(text); ++i )
{
if( text[i].translated != NULL )
{
free_volatile(text[i].translated);
text[i].translated = NULL;
}
}
}
//*****************************************************************************
//
//*****************************************************************************
bool Translate_Init()
{
// Init translations if available
Translate_Load("Languages/" );
return /*gLanguage.empty() == 0*/ true;
}
//*****************************************************************************
//
//*****************************************************************************
void Translate_Load( const char * p_dir )
{
// Set default language
gLanguage.push_back("English");
IO::FindHandleT find_handle;
IO::FindDataT find_data;
if(IO::FindFileOpen( p_dir, &find_handle, find_data ))
{
do
{
char * filename( find_data.Name );
char * last_period( strrchr( filename, '.' ) );
if(last_period != NULL)
{
if( strcasecmp(last_period, ".lng") == 0 )
{
IO::Path::RemoveExtension( filename );
gLanguage.push_back( filename );
}
}
}
while(IO::FindFileNext( find_handle, find_data ));
IO::FindFileClose( find_handle );
}
}
//*****************************************************************************
//
//*****************************************************************************
const char * Translate_Name(u32 idx)
{
if( idx < gLanguage.size())
{
return gLanguage[ idx ].c_str();
}
return "?";
}
//*****************************************************************************
//
//*****************************************************************************
u32 Translate_Number()
{
return gLanguage.size()-1;
}
//*****************************************************************************
//
//*****************************************************************************
u32 Translate_IndexFromName( const char * name )
{
for( u32 i = 0; i < gLanguage.size(); ++i )
{
if( strcasecmp( gLanguage[ i ].c_str(), name ) == 0 )
{
return i;
}
}
// Default language (English)
return 0;
}
//*****************************************************************************
//
//*****************************************************************************
const char * Translate_NameFromIndex( u32 idx )
{
if( idx < gLanguage.size())
{
return gLanguage[ idx ].c_str();
}
return "?";
}
//*****************************************************************************
// Restores escape characters which were removed when parsing
// Which are needed by line-breaking and back-slash
//*****************************************************************************
const char * Restore(char *s, u32 len)
{
for (u32 i = 0; i < len; i++)
{
if (s[i] == '\\')
{
if( s[i+1] == 'n' )
{
s[i+1] = '\b'; s[i] = '\n';
i++;
}
else if( s[i+1] == '\\' )
{
s[i+1] = '\b'; s[i] = '\\';
i++;
}
}
}
return s;
}
//*****************************************************************************
//
//*****************************************************************************
void Translate_Dump(const char *string, bool dump)
{
if(dump)
{
FILE * fh = fopen( "hash.txt", "a" );
if(fh)
{
fprintf( fh, "%08x,%s\n", HashString(string), string );
fclose(fh);
}
}
}
//*****************************************************************************
//
//*****************************************************************************
bool Translate_Read(u32 idx, const char * dir)
{
/// Always unload previous language file if available
Translate_Unload();
if( idx > gLanguage.size() )
return false;
const char * ext( ".lng" );
char line[1024];
IO::Filename path;
char *string;
FILE *stream;
u32 count = 0;
u32 hash = 0;
u32 len = 0;
// Build path where we'll load the translation file(s)
strcpy(path, dir);
strcat(path, gLanguage[ idx ].c_str());
strcat(path, ext);
stream = fopen(path,"r");
if( stream == NULL )
{
return false;
}
while( fgets(line, 1023, stream) )
{
// Strip spaces from end of lines
Tidy(line);
// Handle comments
if (line[0] == '/')
continue;
string = strchr(line,',');
if( string != NULL )
{
string++;
len = strlen( string );
sscanf( line,"%08x", &hash );
if( count < ARRAYSIZE(text) )
{
// Write translated string and hash to array
text[count].hash = hash;
Translate_Dump( string, hash == TRANSLATE_DUMP_VALUE );
text[count].translated = (char*)malloc_volatile(len+1); // Leave space for terminator
strcpy( text[count].translated, Restore( string, len ) );
count++;
}
}
}
fclose(stream);
return true;
}