First submission to Symbian Foundation staging server.
// rez.cpp
//
// Copyright (c) 2010 Accenture. All rights reserved.
// This component and the accompanying materials are made available
// under the terms of the "Eclipse Public License v1.0"
// which accompanies this distribution, and is available
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
//
// Initial Contributors:
// Accenture - Initial contribution
//
#include <fshell/ltkutils.h>
#include <f32file.h>
#include <bautils.h>
#include <barsc.h>
// Horrible variadic macro to avoid leaving from within a variadic function, because GCCE doesn't like that
#define LeaveIfErr(err, errBuf, fmt...) \
do \
{ \
TInt __err = (err); \
if (__err < 0 && errBuf) \
{ \
*errBuf = HBufC::NewL(512); \
FormatIntoBuf(*errBuf, fmt); \
} \
User::LeaveIfError(__err); \
} \
while (0)
void FormatIntoBuf(HBufC* aErrBuf, TRefByValue<const TDesC> aFmt, ...)
{
VA_LIST list;
VA_START(list, aFmt);
TPtr ptr = aErrBuf->Des();
ptr.FormatList(aFmt, list);
VA_END(list);
}
EXPORT_C HBufC8* LtkUtils::Rez8L(const TDesC& aIdentifier, RFs* aFs, HBufC** aErrBuf)
{
TPtrC id(aIdentifier);
if (aIdentifier.Left(2) != _L("R:"))
{
// Just return the string as-is, ie unlocalised
HBufC8* result = HBufC8::NewL(aIdentifier.Length());
result->Des().Copy(aIdentifier);
return result;
}
RFs stackfs;
if (!aFs)
{
CleanupClosePushL(stackfs);
LeaveIfErr(stackfs.Connect(), aErrBuf, _L("Couldn't connect to RFs"));
aFs = &stackfs;
}
else
{
CleanupStack::PushL((CBase*)NULL); // Just so the cleanup stack is the same depth in both cases - this is ok to destroy
}
RFs& fs = *aFs;
id.Set(id.Mid(2));
TInt colon = id.Locate(':');
if (colon == KErrNotFound || colon == 0)
{
LeaveIfErr(KErrArgument, aErrBuf, _L("Resource identifier must include a resource id - R:FILENAME:ID[:OFFSET]"));
}
TPtrC resname(id.Left(colon));
id.Set(id.Mid(colon+1));
colon = id.Locate(':');
TPtrC offset;
if (colon != KErrNotFound)
{
offset.Set(id.Mid(colon+1));
id.Set(id.Left(colon));
}
TFileName resFileName = resname;
resFileName.Insert(0, _L("\\Resource\\"));
resFileName.Append(_L(".rsc")); // Seems daft but you have to have this to keep Bafl happy
BaflUtils::NearestLanguageFile(fs, resFileName);
RResourceFile resFile;
CleanupClosePushL(resFile);
TRAPD(err, resFile.OpenL(fs, resFileName));
LeaveIfErr(err, aErrBuf, _L("Couldn't open resource file %S"), &resFileName);
TRAP(err, resFile.ConfirmSignatureL());
LeaveIfErr(err, aErrBuf, _L("Failed to confirm signature"));
TBool hex = EFalse;
if (id.Left(2) == _L("0x"))
{
id.Set(id.Mid(2));
hex = ETrue;
}
TUint resourceId;
TLex lex(id);
LeaveIfErr(lex.Val(resourceId, hex ? EHex : EDecimal), aErrBuf, _L("Couldn't parse resource id from %S"), &id);
HBufC8* resdata = NULL;
TRAP(err, resdata = resFile.AllocReadL(resourceId));
LeaveIfErr(err, aErrBuf, _L("Couldn't read resource %d from %S"), resourceId, &resFileName);
CleanupStack::PushL(resdata);
TPtrC8 result(*resdata);
if (offset.Length())
{
char last = (char)offset[offset.Length() - 1];
if (last != 'd' && last != 'D')
{
LeaveIfErr(KErrArgument, aErrBuf, _L("Offset '%S' does not end in a 'd' or a 'D'. This is needed to indicate whether the actual target is 8-bit or 16-bit"), &offset);
}
TResourceReader reader;
reader.SetBuffer(resdata);
TLex lex(offset);
while (!lex.Eos())
{
TChar ch = lex.Get();
if (ch == 'd')
{
result.Set(reader.ReadTPtrC8());
}
else if (ch == 'D')
{
TPtrC16 wptr = reader.ReadTPtrC16();
result.Set(TPtrC8((TUint8*)wptr.Ptr(), wptr.Size()));
}
else
{
lex.UnGet();
TInt amountToSkip;
LeaveIfErr(lex.Val(amountToSkip), aErrBuf, _L("Error lexing offset"));
reader.Advance(amountToSkip);
}
}
}
HBufC8* resultBuf = result.AllocL();
CleanupStack::PopAndDestroy(3); // resData, resFile, fs
return resultBuf;
}
EXPORT_C HBufC* LtkUtils::RezL(const TDesC& aIdentifier, RFs* aFs, HBufC** aErrBuf)
{
if (aIdentifier.Left(2) != _L("R:"))
{
// Just return the string as-is, ie unlocalised
return aIdentifier.AllocL();
}
HBufC8* buf8 = Rez8L(aIdentifier, aFs, aErrBuf);
CleanupStack::PushL(buf8);
TPtrC16 wptr((TUint16*)buf8->Ptr(), buf8->Size()/2);
HBufC* result = wptr.AllocL();
CleanupStack::PopAndDestroy(buf8);
return result;
}
EXPORT_C HBufC* LtkUtils::RezLC(const TDesC& aIdentifier, RFs* aFs, HBufC** aErrBuf)
{
HBufC* res = RezL(aIdentifier, aFs, aErrBuf);
CleanupStack::PushL(res);
return res;
}
EXPORT_C HBufC8* LtkUtils::Rez8LC(const TDesC& aIdentifier, RFs* aFs, HBufC** aErrBuf)
{
HBufC8* res = Rez8L(aIdentifier, aFs, aErrBuf);
CleanupStack::PushL(res);
return res;
}