2009-05-08 13:28:41 +00:00
|
|
|
/*
|
|
|
|
* OpenClonk, http://www.openclonk.org
|
|
|
|
*
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 1998-2000, 2004 Matthes Bender
|
|
|
|
* Copyright (c) 2002-2004 Peter Wortmann
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2005, 2007-2009 Günther Brammer
|
2009-06-05 13:41:20 +00:00
|
|
|
* Copyright (c) 2005, 2007 Sven Eberhardt
|
2010-12-23 00:01:24 +00:00
|
|
|
* Copyright (c) 2009 David Dormagen
|
|
|
|
* Copyright (c) 2010 Armin Burgmeier
|
2009-05-08 13:28:41 +00:00
|
|
|
* Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
|
|
|
|
*
|
|
|
|
* Portions might be copyrighted by other authors who have contributed
|
|
|
|
* to OpenClonk.
|
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
* See isc_license.txt for full license and disclaimer.
|
|
|
|
*
|
|
|
|
* "Clonk" is a registered trademark of Matthes Bender.
|
|
|
|
* See clonk_trademark_license.txt for full license.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* Holds a single text file component from a group */
|
|
|
|
|
|
|
|
#include <C4Include.h>
|
|
|
|
#include <C4ComponentHost.h>
|
|
|
|
#include <C4Application.h>
|
|
|
|
#include <C4Language.h>
|
|
|
|
#include <StdRegistry.h>
|
|
|
|
|
|
|
|
C4ComponentHost::C4ComponentHost()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Default();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
C4ComponentHost::~C4ComponentHost()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Clear();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4ComponentHost::Default()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Data.Clear();
|
|
|
|
Name[0]=0;
|
|
|
|
Filename[0]=0;
|
|
|
|
FilePath[0]=0;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
void C4ComponentHost::Clear()
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Data.Clear();
|
2010-09-04 20:41:59 +00:00
|
|
|
OnLoad();
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4ComponentHost::Load(const char *szName,
|
2010-03-28 18:58:01 +00:00
|
|
|
C4Group &hGroup,
|
|
|
|
const char *szFilename,
|
|
|
|
const char *szLanguage)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Clear any old stuff
|
|
|
|
Clear();
|
|
|
|
// Store name & filename
|
|
|
|
SCopy(szName, Name);
|
|
|
|
SCopy(szFilename, Filename);
|
|
|
|
// Load component - try all segmented filenames
|
|
|
|
char strEntry[_MAX_FNAME+1], strEntryWithLanguage[_MAX_FNAME+1];
|
|
|
|
for (int iFilename = 0; SCopySegment(Filename, iFilename, strEntry, '|'); iFilename++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Try to insert all language codes provided into the filename
|
|
|
|
char strCode[3] = "";
|
|
|
|
for (int iLang = 0; SCopySegment(szLanguage ? szLanguage : "", iLang, strCode, ',', 2); iLang++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Insert language code
|
|
|
|
sprintf(strEntryWithLanguage, strEntry, strCode);
|
|
|
|
if (hGroup.LoadEntryString(strEntryWithLanguage, Data))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-06-28 20:53:32 +00:00
|
|
|
Data.EnsureUnicode();
|
|
|
|
// Skip those stupid "zero width no-break spaces" (also known as Byte Order Marks)
|
|
|
|
if (Data[0] == '\xEF' && Data[1] == '\xBB' && Data[2] == '\xBF')
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-06-28 20:53:32 +00:00
|
|
|
Data.Move(3,Data.getSize()-3);
|
|
|
|
Data.Shrink(3);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Store actual filename
|
|
|
|
hGroup.FindEntry(strEntryWithLanguage, Filename);
|
|
|
|
CopyFilePathFromGroup(hGroup);
|
2010-09-04 20:41:59 +00:00
|
|
|
// Notify
|
|
|
|
OnLoad();
|
2009-05-08 13:28:41 +00:00
|
|
|
// Got it
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Couldn't insert language code anyway - no point in trying other languages
|
|
|
|
if (!SSearch(strEntry, "%s")) break;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Truncate any additional segments from stored filename
|
|
|
|
SReplaceChar(Filename, '|', 0);
|
|
|
|
CopyFilePathFromGroup(hGroup);
|
|
|
|
// Not loaded
|
2009-08-15 18:50:32 +00:00
|
|
|
return false;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4ComponentHost::Load(const char *szName,
|
2010-03-28 18:58:01 +00:00
|
|
|
C4GroupSet &hGroupSet,
|
|
|
|
const char *szFilename,
|
|
|
|
const char *szLanguage)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Clear any old stuff
|
|
|
|
Clear();
|
|
|
|
// Store name & filename
|
|
|
|
SCopy(szName, Name);
|
|
|
|
SCopy(szFilename, Filename);
|
|
|
|
// Load component - try all segmented filenames
|
|
|
|
char strEntry[_MAX_FNAME+1], strEntryWithLanguage[_MAX_FNAME+1];
|
|
|
|
for (int iFilename = 0; SCopySegment(Filename, iFilename, strEntry, '|'); iFilename++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Try to insert all language codes provided into the filename
|
|
|
|
char strCode[3] = "";
|
|
|
|
for (int iLang = 0; SCopySegment(szLanguage ? szLanguage : "", iLang, strCode, ',', 2); iLang++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Insert language code
|
|
|
|
sprintf(strEntryWithLanguage, strEntry, strCode);
|
|
|
|
if (hGroupSet.LoadEntryString(strEntryWithLanguage, Data))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-06-28 20:53:32 +00:00
|
|
|
Data.EnsureUnicode();
|
2009-05-08 13:28:41 +00:00
|
|
|
// Store actual filename
|
|
|
|
C4Group *pGroup = hGroupSet.FindEntry(strEntryWithLanguage);
|
|
|
|
pGroup->FindEntry(strEntryWithLanguage, Filename);
|
|
|
|
CopyFilePathFromGroup(*pGroup);
|
2010-09-04 20:41:59 +00:00
|
|
|
// Notify
|
|
|
|
OnLoad();
|
2009-05-08 13:28:41 +00:00
|
|
|
// Got it
|
2009-08-15 18:50:32 +00:00
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Couldn't insert language code anyway - no point in trying other languages
|
|
|
|
if (!SSearch(strEntry, "%s")) break;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
// Truncate any additional segments from stored filename
|
|
|
|
SReplaceChar(Filename, '|', 0);
|
2010-03-27 16:05:02 +00:00
|
|
|
// skip full path (unknown)
|
|
|
|
FilePath[0] = 0;
|
2009-05-08 13:28:41 +00:00
|
|
|
// Not loaded
|
2009-08-15 18:50:32 +00:00
|
|
|
return false;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4ComponentHost::LoadEx(const char *szName,
|
2010-03-28 18:58:01 +00:00
|
|
|
C4Group &hGroup,
|
|
|
|
const char *szFilename,
|
|
|
|
const char *szLanguage)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
// Load from a group set containing the provided group and
|
|
|
|
// alternative groups for cross-loading from a language pack
|
|
|
|
C4GroupSet hGroups;
|
|
|
|
hGroups.RegisterGroup(hGroup, false, 1000, C4GSCnt_Component); // Provided group gets highest priority
|
|
|
|
hGroups.RegisterGroups(Languages.GetPackGroups(pConfig->AtRelativePath(hGroup.GetFullName().getData())), C4GSCnt_Language);
|
|
|
|
// Load from group set
|
|
|
|
return Load(szName, hGroups, szFilename, szLanguage);
|
|
|
|
}
|
|
|
|
|
2009-08-15 18:50:32 +00:00
|
|
|
bool C4ComponentHost::LoadAppend(const char *szName,
|
2010-03-28 18:58:01 +00:00
|
|
|
C4Group &hGroup, const char *szFilename,
|
|
|
|
const char *szLanguage)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
Clear();
|
|
|
|
|
|
|
|
// Store name & filename
|
|
|
|
SCopy(szName,Name);
|
|
|
|
SCopy(szFilename,Filename);
|
|
|
|
|
|
|
|
// Load component (segmented filename)
|
|
|
|
char str1[_MAX_FNAME+1],str2[_MAX_FNAME+1];
|
|
|
|
int iFileCnt = 0, iFileSizeSum = 0;
|
|
|
|
int cseg, clseg;
|
|
|
|
for (cseg=0; SCopySegment(Filename,cseg,str1,'|'); cseg++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
char szLang[3] = "";
|
2010-03-28 18:58:01 +00:00
|
|
|
for (clseg=0; SCopySegment(szLanguage ? szLanguage : "", clseg, szLang, ',', 2); clseg++)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
sprintf(str2,str1,szLang);
|
|
|
|
// Check existance
|
|
|
|
size_t iFileSize;
|
2010-03-28 18:58:01 +00:00
|
|
|
if (hGroup.FindEntry(str2, NULL, &iFileSize))
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
iFileCnt++;
|
|
|
|
iFileSizeSum += 1 + iFileSize;
|
|
|
|
break;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!SSearch(str1, "%s")) break;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// No matching files found?
|
2010-03-28 18:58:01 +00:00
|
|
|
if (!iFileCnt) return false;
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Allocate memory
|
|
|
|
Data.SetLength(iFileSizeSum);
|
|
|
|
|
|
|
|
// Search files to read contents
|
|
|
|
char *pPos = Data.getMData(); *pPos = 0;
|
|
|
|
for (cseg=0; SCopySegment(Filename,cseg,str1,'|'); cseg++)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
char szLang[3] = "";
|
2010-03-28 18:58:01 +00:00
|
|
|
for (clseg=0; SCopySegment(szLanguage ? szLanguage : "", clseg, szLang, ',', 2); clseg++)
|
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
sprintf(str2,str1,szLang);
|
|
|
|
// Load data
|
|
|
|
char *pTemp;
|
|
|
|
if (hGroup.LoadEntry(str2,&pTemp,NULL,1))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
*pPos++ = '\n';
|
|
|
|
SCopy(pTemp, pPos, Data.getPtr(Data.getLength()) - pPos);
|
|
|
|
pPos += SLen(pPos);
|
|
|
|
delete[] pTemp;
|
|
|
|
break;
|
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
delete [] pTemp;
|
|
|
|
if (!SSearch(str1, "%s")) break;
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
SReplaceChar(Filename,'|',0);
|
|
|
|
CopyFilePathFromGroup(hGroup);
|
2010-09-04 20:41:59 +00:00
|
|
|
OnLoad();
|
2009-05-08 13:28:41 +00:00
|
|
|
return !! iFileCnt;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
// Construct full path
|
|
|
|
void C4ComponentHost::CopyFilePathFromGroup(const C4Group &hGroup)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
SCopy(pConfig->AtRelativePath(hGroup.GetFullName().getData()), FilePath, _MAX_PATH - 1);
|
|
|
|
SAppendChar(DirectorySeparator, FilePath);
|
|
|
|
SAppend(Filename, FilePath, _MAX_PATH);
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
|
|
|
|
bool C4ComponentHost::GetLanguageString(const char *szLanguage, StdStrBuf &rTarget)
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
const char *cptr;
|
|
|
|
// No good parameters
|
|
|
|
if (!szLanguage || !Data) return false;
|
|
|
|
// Search for two-letter language identifier in text body, i.e. "DE:"
|
|
|
|
char langindex[4] = "";
|
2010-03-28 18:58:01 +00:00
|
|
|
for (int clseg=0; SCopySegment(szLanguage ? szLanguage : "", clseg, langindex, ',', 2); clseg++)
|
2009-05-08 13:28:41 +00:00
|
|
|
{
|
|
|
|
SAppend(":",langindex);
|
2010-01-25 04:00:59 +00:00
|
|
|
if ((cptr = SSearch(Data.getData(),langindex)))
|
2010-03-28 18:58:01 +00:00
|
|
|
{
|
2009-05-08 13:28:41 +00:00
|
|
|
// Return the according string
|
|
|
|
int iEndPos = SCharPos('\r', cptr);
|
|
|
|
if (iEndPos<0) iEndPos = SCharPos('\n', cptr);
|
|
|
|
if (iEndPos<0) iEndPos = strlen(cptr);
|
|
|
|
rTarget.Copy(cptr, iEndPos);
|
|
|
|
return true;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|
2009-05-08 13:28:41 +00:00
|
|
|
}
|
|
|
|
// Language string not found
|
|
|
|
return false;
|
2010-03-28 18:58:01 +00:00
|
|
|
}
|