diff -r 675a964f4eb5 -r 35751d3474b7 securityanddataprivacytools/securitytools/certapp/encdec/encdec.cpp --- a/securityanddataprivacytools/securitytools/certapp/encdec/encdec.cpp Tue Jul 21 01:04:32 2009 +0100 +++ b/securityanddataprivacytools/securitytools/certapp/encdec/encdec.cpp Thu Sep 10 14:01:51 2009 +0300 @@ -1,858 +1,858 @@ -/* -* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of the License "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: -* Nokia Corporation - initial contribution. -* -* Contributors: -* -* Description: -* -*/ - - -#include "encdec.h" -#include -#include -#include -#include "stringconv.h" -#include -#include "x509utils.h" - -RDecodeReadStream::RDecodeReadStream(CFileStore *aStore, RReadStream &aReadStream) - : iStore(aStore), iCertBaseName(), iReadStream(aReadStream), iHumanReadable(false), iToken(), - iPrefetchedTokenIsValid(false), iPrefetchedToken() -{ -} - -RDecodeReadStream::RDecodeReadStream(const std::string &aCertBaseName, RReadStream &aReadStream) - : iStore(0), iCertBaseName(aCertBaseName), iReadStream(aReadStream), iHumanReadable(true), iToken(), - iPrefetchedTokenIsValid(false), iPrefetchedToken() -{ -} - -void RDecodeReadStream::RawRead(void *aPtr, TUint32 aLength) -{ - iReadStream.ReadL((TUint8 *)aPtr, aLength); -} - -void RDecodeReadStream::CheckName(const std::string &aExpected) -{ - ReadNextToken(); - - if(iToken != aExpected) - { - dbg << Log::Indent() << "Expected token '" << aExpected <<"' but got token '" << iToken << "'" << Log::Endl(); - FatalError(); - } - -} - -TUint32 ReadUnsignedNumber(std::string &aStr, size_t aSize) -{ - TUint32 val; - std::istringstream ss(aStr); - - if((aStr.length() > 2) && - (aStr[0] == '0') && - ((aStr[1] == 'x') || (aStr[1] == 'X'))) - { - // Hex number starting with 0x - char ch; - ss >> ch >> ch; // Discard the 0x - ss >> std::hex >> val; - } - else - { - // Decimal number - ss >> val; - } - - // Now work out if we consumed the entire token without error - if(ss.fail()) - { - // Number decode failed - dbg << Log::Indent() << "Failed to decode '" << aStr << "' as a number" << Log::Endl(); - FatalError(); - } - - // Make sure we consumed all data - if(! ss.eof()) - { - // Trailing chars on numeric token - FatalError(); - } - - if(aSize != 4) - { - // Check range - // nb the following check would fail if aSize==4 because x>>32 == x if sizeof(x)==4 - if((val >> (8*aSize)) != 0) - { - // Higher order bits are set above the size of the variable we - // are returning into - FatalError(); - } - } -return val; -} - - -TUint32 RDecodeReadStream::ReadUnsignedNumber(size_t aSize) -{ -BULLSEYE_OFF - if((TUint32(aSize)>4)) - { - FatalError(); - } -BULLSEYE_RESTORE - - ReadNextToken(); - - return ::ReadUnsignedNumber(iToken, aSize); -} - -const std::string &RDecodeReadStream::Token() const -{ - return iToken; -} - -void RDecodeReadStream::ReadNextToken() -{ - if(iPrefetchedTokenIsValid) - { - // Copy prefetched token to current token - iToken = iPrefetchedToken; - iPrefetchedToken.clear(); - iPrefetchedTokenIsValid = false; - return; - } - - GetToken(iToken); -} - -const std::string &RDecodeReadStream::PeakToken() -{ - if(!iPrefetchedTokenIsValid) - { - GetToken(iPrefetchedToken); - iPrefetchedTokenIsValid = true; - } - - return iPrefetchedToken; -} - - - - - -bool RDecodeReadStream::HumanReadable() const -{ - return iHumanReadable; -} - - -void RDecodeReadStream::Close() -{ - iReadStream.Close(); -} - -void RDecodeReadStream::GetToken(std::string &aToken) -{ - aToken.clear(); - - TUint8 ch; - do - { - iReadStream >> ch; - if(ch == '#') - { - // Skip comment - ++ch; - while((ch != '\r') && (ch != '\n')) - { - iReadStream >> ch; - } - - } - } while((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')); - - if(ch == '"') - { - // Read a string - iReadStream >> ch; // read first char - while(ch != '"') - { - if(ch=='\\') - { - // \X causes X to always be saved (even if X is ") - iReadStream >> ch; - } - - aToken.push_back(ch); - iReadStream >> ch; - } - // At this point ch contains WS so it can be discarded. - return; - } - - // Read a non-string token - while((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) - { - aToken.push_back(ch); - iReadStream >> ch; - } - // At this point ch contains WS so it can be discarded. - return; -} - - - - - -REncodeWriteStream::REncodeWriteStream(CFileStore *aStore, RWriteStream &aWriteStream) - : iStore(aStore), - iCertBaseName(), // not used for STORE based streams - iWriteStream(&aWriteStream), - iLogStream(0), - iHumanReadable(false), iPemOut(false), iVerbose(false), iIndentLevel(0) -{ -} - -REncodeWriteStream::REncodeWriteStream(const std::string &aCertBaseName, RWriteStream &aWriteStream) - : iStore(0), iCertBaseName(aCertBaseName), iWriteStream(&aWriteStream), - iLogStream(0), - iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(0) -{ -} - -REncodeWriteStream::REncodeWriteStream(Log &aLog) - : iStore(0), iWriteStream(0), iLogStream(&aLog.Stream()), - iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(aLog.IndentLevel()) -{ -} - -void REncodeWriteStream::WriteBin(const void *aPtr, TUint32 aLength) -{ - if(iWriteStream) - { - iWriteStream->WriteL((TUint8 *)aPtr, aLength); - } - if(iLogStream) - { - iLogStream->write((const char *)aPtr, aLength); - iLogStream->flush(); - } -} - -void REncodeWriteStream::WriteQuotedUtf8(const void *aStr, TUint32 aLength) -{ - std::string tmp((const char *)aStr, aLength); - - // Insert a backslash before any backslash chars - size_t pos = 0; - while((pos = tmp.find('\\', pos)) != std::string::npos) - { - tmp.insert(pos, "\\", 1); - pos += 2; - } - - // Insert a backslash before any double quote chars - pos = 0; - while((pos = tmp.find('"', pos)) != std::string::npos) - { - tmp.insert(pos, "\\", 1); - pos += 2; - } - - if(iWriteStream) - { - iWriteStream->WriteL((TUint8 *)tmp.data(), tmp.size()); - } - if(iLogStream) - { - iLogStream->write(tmp.data(), tmp.size()); - iLogStream->flush(); - } -} - -void REncodeWriteStream::WriteByte(TUint8 aByte) -{ - WriteBin(&aByte, 1); -} - -void REncodeWriteStream::WriteCStr(const void *aCstr) -{ - WriteBin(aCstr, strlen((const char *)aCstr)); -} - -void REncodeWriteStream::WriteHexNumber(TUint32 aNumber) -{ - char buf[20]; - int len = sprintf(buf, "0x%x", aNumber); - WriteBin(buf, len); -} - - -void REncodeWriteStream::WriteSpace() -{ -BULLSEYE_OFF - if(!iHumanReadable) return; -BULLSEYE_RESTORE - WriteByte(' '); -} - -void REncodeWriteStream::WriteLineEnd() -{ -BULLSEYE_OFF - if(!iHumanReadable) return; -BULLSEYE_RESTORE -#ifdef linux - WriteByte('\n'); -#else - WriteBin("\r\n", 2); -#endif -} - - -void REncodeWriteStream::WriteIndent() -{ -BULLSEYE_OFF - if(!iHumanReadable) return; -BULLSEYE_RESTORE - for(int i=0; iClose(); - } -} - -CFileStore *REncodeWriteStream::StoreObject() -{ -BULLSEYE_OFF - if(iStore == 0) FatalError(); -BULLSEYE_RESTORE - return iStore; -} - -RWriteStream &REncodeWriteStream::StoreWriteStream() -{ -BULLSEYE_OFF - if(iWriteStream == 0) FatalError(); -BULLSEYE_RESTORE - return *iWriteStream; -} - -bool REncodeWriteStream::Quiet() const -{ - return iLogStream != 0; -} - -TUint8 fromHex(TUint8 ch) - /** - Convert a single hex char from ascii - */ -{ - // convert to lowercase - if((ch >= 'A') && (ch <= 'F')) - { - ch -= ('A' -'a'); - } - // Handle a-f - if((ch >= 'a') && (ch <= 'f')) - { - return ch - 'a' + 10; - } - - // Handle 0-9 - if((ch >= '0') && (ch <= '9')) - { - return ch - '0'; - } - - // Illegal - FatalError(); - return 0xff; -} - -EncDecContainerItem::~EncDecContainerItem() -{ -} - - -#ifdef _BullseyeCoverage -#pragma BullseyeCoverage off -#endif -std::string EncDecContainerItem::ItemName() const -{ - // Should never be called - exit(-1); - std::string tmp; - return tmp; -} - -void EncDecContainerItem::SetItemName(const std::string &) -{ - // Should never be called - exit(-1); -} -#ifdef _BullseyeCoverage -#pragma BullseyeCoverage restore -#endif - - - -EncDecContainer::EncDecContainer(const char *aContainerName, EncDecContainerItemFactoryFunc *aFactory) - : iName(aContainerName), iFactory(aFactory), iArray() -{ -} - -EncDecContainer::~EncDecContainer() -{ - reset(); -} - -void EncDecContainer::push_back(EncDecContainerItem *aItem) -{ - iArray.push_back(aItem); -} - -const EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) const -{ - return *iArray[aIndex]; -} - -EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) -{ - return *iArray[aIndex]; -} - -TUint32 EncDecContainer::size() const -{ - return iArray.size(); -} - -void EncDecContainer::reset() -{ - while(!iArray.empty()) - { - EncDecContainerItem *p = iArray.back(); - iArray.pop_back(); - delete p; - } -} - - - -void EncDecContainer::Encode(REncodeWriteStream &aWriteStream) const -{ - // Calculate Start/End container names - std::string startName("Start"); - startName.append(iName); - std::string endName("End"); - endName.append(iName); - - prog << Log::Indent() << "Writing " << startName << Log::Endl(); - - TUint32 arrayLength = iArray.size(); - - if(aWriteStream.HumanReadable()) - { - // Human - aWriteStream.WriteIndent(); - aWriteStream.WriteBin(startName.data(), startName.size()); - aWriteStream.WriteLineEnd(); - } - else - { - // Binary - // Write length of array - aWriteStream.WriteBin(&arrayLength, sizeof(arrayLength)); - } - - aWriteStream.IncIndent(); - - // Write array entries - for(TUint32 i=0; i < arrayLength; ++i) - { - std::ostringstream entryComment; - entryComment << "# Entry " << i+1; - prog << Log::Indent() << entryComment.str() << Log::Endl(); - - bool bracketItem = (iArray[i]->ItemType() != 0); - if(aWriteStream.HumanReadable()) - { - if(bracketItem) - { - std::ostringstream itemStart; - itemStart << "Start" << iArray[i]->ItemType() << " " << iArray[i]->ItemName(); - prog << Log::Indent() << itemStart.str() << Log::Endl(); - - aWriteStream.WriteIndent(); - aWriteStream.WriteCStr("Start"); - aWriteStream.WriteCStr(iArray[i]->ItemType()); - aWriteStream.WriteCStr(" \""); - aWriteStream.WriteQuotedUtf8(iArray[i]->ItemName().data(), iArray[i]->ItemName().size()); - aWriteStream.WriteCStr("\""); - aWriteStream.WriteLineEnd(); - } - else - { - aWriteStream.WriteIndent(); - aWriteStream.WriteBin(entryComment.str().data(), entryComment.str().size()); - aWriteStream.WriteLineEnd(); - } - } - aWriteStream.IncIndent(); - iArray[i]->Encode(aWriteStream); - aWriteStream.DecIndent(); - if(bracketItem && aWriteStream.HumanReadable()) - { - std::ostringstream tmp; - tmp << "End" << iArray[i]->ItemType(); - - prog << Log::Indent() << tmp.str() << Log::Endl(); - - aWriteStream.WriteIndent(); - aWriteStream.WriteBin(tmp.str().data(), tmp.str().size()); - aWriteStream.WriteLineEnd(); - } - } - - aWriteStream.DecIndent(); - - if(aWriteStream.HumanReadable()) - { - // Human - aWriteStream.WriteIndent(); - aWriteStream.WriteCStr("End"); - aWriteStream.WriteBin(iName.data(), iName.size()); - aWriteStream.WriteLineEnd(); - } - - prog << Log::Indent() << endName << Log::Endl(); - - return; -} - -void EncDecContainer::Decode(RDecodeReadStream &aReadStream) -{ - // Calculate Start/End container names - std::string startName("Start"); - startName.append(iName); - std::string endName("End"); - endName.append(iName); - - prog << Log::Indent() << "Reading " << startName << Log::Endl(); - - if(aReadStream.HumanReadable()) - { - // Human - - // Check/consume container StartX - aReadStream.CheckName(startName); - - prog.IncIndent(); - - // Create items until we find the container EndX - TUint32 entryNum=1; - while(aReadStream.PeakToken() != endName) - { - // Progress message - prog << Log::Indent() << "# Entry " << std::dec << entryNum++ << std::hex << Log::Endl(); - - EncDecContainerItem *item = iFactory(); - bool bracketedItem = (item->ItemType() != 0); - std::string itemName; - if(bracketedItem && aReadStream.HumanReadable()) - { - // Bracketed item, so read ItemType tag and ItemName - std::string itemStart("Start"); - itemStart.append(item->ItemType()); - aReadStream.CheckName(itemStart); - prog << Log::Indent() << itemStart; - - // Read item name - aReadStream.ReadNextToken(); - itemName = aReadStream.Token(); - } - - prog.IncIndent(); - item->Decode(aReadStream); - iArray.push_back(item); - prog.DecIndent(); - if(bracketedItem && aReadStream.HumanReadable()) - { - // Bracketed item, so read End ItemType tag - std::string itemEnd("End"); - itemEnd.append(item->ItemType()); - aReadStream.CheckName(itemEnd); - // and set item name - item->SetItemName(itemName); - } - } - - // Check/consume container EndX - aReadStream.CheckName(endName); - - prog.DecIndent(); - } - else - { - // Binary - // Read number of entries - TUint32 arrayLength; - aReadStream.RawRead(&arrayLength, sizeof(arrayLength)); - - prog.IncIndent(); - for(TUint32 i=0; i < arrayLength; ++i) - { - EncDecContainerItem *item = iFactory(); - prog << Log::Indent() << "# Entry " << std::dec << i+1 << std::hex << Log::Endl(); - prog.IncIndent(); - item->Decode(aReadStream); - prog.DecIndent(); - iArray.push_back(item); - } - prog.DecIndent(); - } - - prog << Log::Indent() << endName << Log::Endl(); - -} - - - - -REncodeWriteStream& operator<<(REncodeWriteStream& aStream, const EncDecContainer &aContainer) -{ - aContainer.Encode(aStream); - return aStream; -} - -RDecodeReadStream& operator>>(RDecodeReadStream& aStream,EncDecContainer &aContainer) -{ - aContainer.Decode(aStream); - return aStream; -} - -// -// TUid -// -void EncodeHuman(REncodeWriteStream& aStream,const TUid &aUid) -{ - aStream.WriteHexNumber(aUid.iUid); -} -void DecodeHuman(RDecodeReadStream& aStream,TUid &aUid) -{ - aUid.iUid = aStream.ReadUnsignedNumber(sizeof(aUid.iUid)); -} - -// -// TName -// -void EncodeHuman(REncodeWriteStream& aStream,const TName &aName) -{ - // Compress the internal UTF-16 to human readable UTF-8 - ; - TInt outputBytes = 0; - TUint8 *outBuf = cstrFromUtf16(aName.Ptr(), aName.Length(), outputBytes); - - aStream.WriteByte('"'); - aStream.WriteQuotedUtf8(outBuf, outputBytes); - aStream.WriteByte('"'); - - delete [] outBuf; -} -void DecodeHuman(RDecodeReadStream& aStream,TName &aName) -{ - aStream.ReadNextToken(); - - // Expand UTF-8 into internal UTF-16LE representation - TInt outputWords = 0; - TText *outputBuf = utf16FromUtf8((const TUint8 *)aStream.Token().data(), aStream.Token().size(), outputWords); - memcpy((void *)aName.Ptr(), outputBuf, outputWords*2); - aName.SetLength(outputWords); - delete [] outputBuf; -} - -void readContainer(const std::string &aFileName, bool aHuman, EncDecContainer &container) -{ - if(aHuman) - { - FileReadStream fileReadStream(aFileName, true); - std::string certBaseName(aFileName); - size_t dotLoc = certBaseName.rfind('.'); - if(dotLoc != std::string::npos) - { - certBaseName.erase(dotLoc); - } - certBaseName += '_'; - RDecodeReadStream inStream(certBaseName, fileReadStream); // human readable - inStream >> container; - inStream.Close(); - } - else - { - RFs fs; - User::LeaveIfError(fs.Connect()); - CleanupClosePushL(fs); - - CPermanentFileStore* store = CPermanentFileStore::OpenLC(fs, _L16(aFileName.c_str()),EFileShareAny | EFileRead); - store->SetTypeL(KPermanentFileStoreLayoutUid); - - RStoreReadStream rootStream; - rootStream.OpenLC(*store, store->Root()); - TUint32 dataStreamId; - rootStream >> dataStreamId; - CleanupStack::PopAndDestroy(&rootStream); - - RStoreReadStream dataStream; - dataStream.OpenLC(*store, dataStreamId); - - RDecodeReadStream readStream(store, dataStream); // binary store - - readStream >> container; - - CleanupStack::PopAndDestroy(&dataStream); - CleanupStack::PopAndDestroy(store); - CleanupStack::PopAndDestroy(&fs); - } -} - - -void writeContainer(const char *aFileName, bool aHuman, bool aPemOut, bool aVerbose, const EncDecContainer &container) -{ - prog << Log::Indent() << "Writing output file '" << aFileName << "'" << Log::Endl(); - prog.IncIndent(); - if(aHuman) - { - FileWriteStream fileWriteStream(aFileName); - // Calculate based name by striping last .xx extension and appending an underscore. - std::string certBaseName(aFileName); - size_t dotLoc = certBaseName.rfind('.'); - if(dotLoc != std::string::npos) - { - certBaseName.erase(dotLoc); - } - certBaseName += '_'; - - REncodeWriteStream outStream(certBaseName, fileWriteStream); // human readable - outStream.PemOut() = aPemOut; - outStream.Verbose() = aVerbose; - outStream << container; - outStream.Close(); - } - else - { - RFs fs; - User::LeaveIfError(fs.Connect()); - CleanupClosePushL(fs); - - CFileStore* store = CPermanentFileStore::ReplaceLC(fs,_L16(aFileName),EFileShareAny | EFileRead | EFileWrite); - store->SetTypeL(KPermanentFileStoreLayoutUid); - - RStoreWriteStream dataStream; - TStreamId dataStreamId = dataStream.CreateLC(*store); - - REncodeWriteStream outStream(store, dataStream); // binary - outStream << container; - outStream.Close(); - - dataStream.CommitL(); - dataStream.Close(); - - RStoreWriteStream rootStream; - TStreamId rootId = rootStream.CreateLC(*store); - rootStream << dataStreamId; - rootStream.CommitL(); - rootStream.Close(); - - - store->SetRootL(rootId); - store->CommitL(); - CleanupStack::PopAndDestroy(&dataStream); - CleanupStack::PopAndDestroy(store); - CleanupStack::PopAndDestroy(&fs); - } - prog.DecIndent(); -} - - -// End of file +/* +* Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of the License "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: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: +* +*/ + + +#include "encdec.h" +#include +#include +#include +#include "stringconv.h" +#include +#include "x509utils.h" + +RDecodeReadStream::RDecodeReadStream(CFileStore *aStore, RReadStream &aReadStream) + : iStore(aStore), iCertBaseName(), iReadStream(aReadStream), iHumanReadable(false), iToken(), + iPrefetchedTokenIsValid(false), iPrefetchedToken() +{ +} + +RDecodeReadStream::RDecodeReadStream(const std::string &aCertBaseName, RReadStream &aReadStream) + : iStore(0), iCertBaseName(aCertBaseName), iReadStream(aReadStream), iHumanReadable(true), iToken(), + iPrefetchedTokenIsValid(false), iPrefetchedToken() +{ +} + +void RDecodeReadStream::RawRead(void *aPtr, TUint32 aLength) +{ + iReadStream.ReadL((TUint8 *)aPtr, aLength); +} + +void RDecodeReadStream::CheckName(const std::string &aExpected) +{ + ReadNextToken(); + + if(iToken != aExpected) + { + dbg << Log::Indent() << "Expected token '" << aExpected <<"' but got token '" << iToken << "'" << Log::Endl(); + FatalError(); + } + +} + +TUint32 ReadUnsignedNumber(std::string &aStr, size_t aSize) +{ + TUint32 val; + std::istringstream ss(aStr); + + if((aStr.length() > 2) && + (aStr[0] == '0') && + ((aStr[1] == 'x') || (aStr[1] == 'X'))) + { + // Hex number starting with 0x + char ch; + ss >> ch >> ch; // Discard the 0x + ss >> std::hex >> val; + } + else + { + // Decimal number + ss >> val; + } + + // Now work out if we consumed the entire token without error + if(ss.fail()) + { + // Number decode failed + dbg << Log::Indent() << "Failed to decode '" << aStr << "' as a number" << Log::Endl(); + FatalError(); + } + + // Make sure we consumed all data + if(! ss.eof()) + { + // Trailing chars on numeric token + FatalError(); + } + + if(aSize != 4) + { + // Check range + // nb the following check would fail if aSize==4 because x>>32 == x if sizeof(x)==4 + if((val >> (8*aSize)) != 0) + { + // Higher order bits are set above the size of the variable we + // are returning into + FatalError(); + } + } +return val; +} + + +TUint32 RDecodeReadStream::ReadUnsignedNumber(size_t aSize) +{ +BULLSEYE_OFF + if((TUint32(aSize)>4)) + { + FatalError(); + } +BULLSEYE_RESTORE + + ReadNextToken(); + + return ::ReadUnsignedNumber(iToken, aSize); +} + +const std::string &RDecodeReadStream::Token() const +{ + return iToken; +} + +void RDecodeReadStream::ReadNextToken() +{ + if(iPrefetchedTokenIsValid) + { + // Copy prefetched token to current token + iToken = iPrefetchedToken; + iPrefetchedToken.clear(); + iPrefetchedTokenIsValid = false; + return; + } + + GetToken(iToken); +} + +const std::string &RDecodeReadStream::PeakToken() +{ + if(!iPrefetchedTokenIsValid) + { + GetToken(iPrefetchedToken); + iPrefetchedTokenIsValid = true; + } + + return iPrefetchedToken; +} + + + + + +bool RDecodeReadStream::HumanReadable() const +{ + return iHumanReadable; +} + + +void RDecodeReadStream::Close() +{ + iReadStream.Close(); +} + +void RDecodeReadStream::GetToken(std::string &aToken) +{ + aToken.clear(); + + TUint8 ch; + do + { + iReadStream >> ch; + if(ch == '#') + { + // Skip comment + ++ch; + while((ch != '\r') && (ch != '\n')) + { + iReadStream >> ch; + } + + } + } while((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')); + + if(ch == '"') + { + // Read a string + iReadStream >> ch; // read first char + while(ch != '"') + { + if(ch=='\\') + { + // \X causes X to always be saved (even if X is ") + iReadStream >> ch; + } + + aToken.push_back(ch); + iReadStream >> ch; + } + // At this point ch contains WS so it can be discarded. + return; + } + + // Read a non-string token + while((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n')) + { + aToken.push_back(ch); + iReadStream >> ch; + } + // At this point ch contains WS so it can be discarded. + return; +} + + + + + +REncodeWriteStream::REncodeWriteStream(CFileStore *aStore, RWriteStream &aWriteStream) + : iStore(aStore), + iCertBaseName(), // not used for STORE based streams + iWriteStream(&aWriteStream), + iLogStream(0), + iHumanReadable(false), iPemOut(false), iVerbose(false), iIndentLevel(0) +{ +} + +REncodeWriteStream::REncodeWriteStream(const std::string &aCertBaseName, RWriteStream &aWriteStream) + : iStore(0), iCertBaseName(aCertBaseName), iWriteStream(&aWriteStream), + iLogStream(0), + iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(0) +{ +} + +REncodeWriteStream::REncodeWriteStream(Log &aLog) + : iStore(0), iWriteStream(0), iLogStream(&aLog.Stream()), + iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(aLog.IndentLevel()) +{ +} + +void REncodeWriteStream::WriteBin(const void *aPtr, TUint32 aLength) +{ + if(iWriteStream) + { + iWriteStream->WriteL((TUint8 *)aPtr, aLength); + } + if(iLogStream) + { + iLogStream->write((const char *)aPtr, aLength); + iLogStream->flush(); + } +} + +void REncodeWriteStream::WriteQuotedUtf8(const void *aStr, TUint32 aLength) +{ + std::string tmp((const char *)aStr, aLength); + + // Insert a backslash before any backslash chars + size_t pos = 0; + while((pos = tmp.find('\\', pos)) != std::string::npos) + { + tmp.insert(pos, "\\", 1); + pos += 2; + } + + // Insert a backslash before any double quote chars + pos = 0; + while((pos = tmp.find('"', pos)) != std::string::npos) + { + tmp.insert(pos, "\\", 1); + pos += 2; + } + + if(iWriteStream) + { + iWriteStream->WriteL((TUint8 *)tmp.data(), tmp.size()); + } + if(iLogStream) + { + iLogStream->write(tmp.data(), tmp.size()); + iLogStream->flush(); + } +} + +void REncodeWriteStream::WriteByte(TUint8 aByte) +{ + WriteBin(&aByte, 1); +} + +void REncodeWriteStream::WriteCStr(const void *aCstr) +{ + WriteBin(aCstr, strlen((const char *)aCstr)); +} + +void REncodeWriteStream::WriteHexNumber(TUint32 aNumber) +{ + char buf[20]; + int len = sprintf(buf, "0x%x", aNumber); + WriteBin(buf, len); +} + + +void REncodeWriteStream::WriteSpace() +{ +BULLSEYE_OFF + if(!iHumanReadable) return; +BULLSEYE_RESTORE + WriteByte(' '); +} + +void REncodeWriteStream::WriteLineEnd() +{ +BULLSEYE_OFF + if(!iHumanReadable) return; +BULLSEYE_RESTORE +#ifdef linux + WriteByte('\n'); +#else + WriteBin("\r\n", 2); +#endif +} + + +void REncodeWriteStream::WriteIndent() +{ +BULLSEYE_OFF + if(!iHumanReadable) return; +BULLSEYE_RESTORE + for(int i=0; iClose(); + } +} + +CFileStore *REncodeWriteStream::StoreObject() +{ +BULLSEYE_OFF + if(iStore == 0) FatalError(); +BULLSEYE_RESTORE + return iStore; +} + +RWriteStream &REncodeWriteStream::StoreWriteStream() +{ +BULLSEYE_OFF + if(iWriteStream == 0) FatalError(); +BULLSEYE_RESTORE + return *iWriteStream; +} + +bool REncodeWriteStream::Quiet() const +{ + return iLogStream != 0; +} + +TUint8 fromHex(TUint8 ch) + /** + Convert a single hex char from ascii + */ +{ + // convert to lowercase + if((ch >= 'A') && (ch <= 'F')) + { + ch -= ('A' -'a'); + } + // Handle a-f + if((ch >= 'a') && (ch <= 'f')) + { + return ch - 'a' + 10; + } + + // Handle 0-9 + if((ch >= '0') && (ch <= '9')) + { + return ch - '0'; + } + + // Illegal + FatalError(); + return 0xff; +} + +EncDecContainerItem::~EncDecContainerItem() +{ +} + + +#ifdef _BullseyeCoverage +#pragma BullseyeCoverage off +#endif +std::string EncDecContainerItem::ItemName() const +{ + // Should never be called + exit(-1); + std::string tmp; + return tmp; +} + +void EncDecContainerItem::SetItemName(const std::string &) +{ + // Should never be called + exit(-1); +} +#ifdef _BullseyeCoverage +#pragma BullseyeCoverage restore +#endif + + + +EncDecContainer::EncDecContainer(const char *aContainerName, EncDecContainerItemFactoryFunc *aFactory) + : iName(aContainerName), iFactory(aFactory), iArray() +{ +} + +EncDecContainer::~EncDecContainer() +{ + reset(); +} + +void EncDecContainer::push_back(EncDecContainerItem *aItem) +{ + iArray.push_back(aItem); +} + +const EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) const +{ + return *iArray[aIndex]; +} + +EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) +{ + return *iArray[aIndex]; +} + +TUint32 EncDecContainer::size() const +{ + return iArray.size(); +} + +void EncDecContainer::reset() +{ + while(!iArray.empty()) + { + EncDecContainerItem *p = iArray.back(); + iArray.pop_back(); + delete p; + } +} + + + +void EncDecContainer::Encode(REncodeWriteStream &aWriteStream) const +{ + // Calculate Start/End container names + std::string startName("Start"); + startName.append(iName); + std::string endName("End"); + endName.append(iName); + + prog << Log::Indent() << "Writing " << startName << Log::Endl(); + + TUint32 arrayLength = iArray.size(); + + if(aWriteStream.HumanReadable()) + { + // Human + aWriteStream.WriteIndent(); + aWriteStream.WriteBin(startName.data(), startName.size()); + aWriteStream.WriteLineEnd(); + } + else + { + // Binary + // Write length of array + aWriteStream.WriteBin(&arrayLength, sizeof(arrayLength)); + } + + aWriteStream.IncIndent(); + + // Write array entries + for(TUint32 i=0; i < arrayLength; ++i) + { + std::ostringstream entryComment; + entryComment << "# Entry " << i+1; + prog << Log::Indent() << entryComment.str() << Log::Endl(); + + bool bracketItem = (iArray[i]->ItemType() != 0); + if(aWriteStream.HumanReadable()) + { + if(bracketItem) + { + std::ostringstream itemStart; + itemStart << "Start" << iArray[i]->ItemType() << " " << iArray[i]->ItemName(); + prog << Log::Indent() << itemStart.str() << Log::Endl(); + + aWriteStream.WriteIndent(); + aWriteStream.WriteCStr("Start"); + aWriteStream.WriteCStr(iArray[i]->ItemType()); + aWriteStream.WriteCStr(" \""); + aWriteStream.WriteQuotedUtf8(iArray[i]->ItemName().data(), iArray[i]->ItemName().size()); + aWriteStream.WriteCStr("\""); + aWriteStream.WriteLineEnd(); + } + else + { + aWriteStream.WriteIndent(); + aWriteStream.WriteBin(entryComment.str().data(), entryComment.str().size()); + aWriteStream.WriteLineEnd(); + } + } + aWriteStream.IncIndent(); + iArray[i]->Encode(aWriteStream); + aWriteStream.DecIndent(); + if(bracketItem && aWriteStream.HumanReadable()) + { + std::ostringstream tmp; + tmp << "End" << iArray[i]->ItemType(); + + prog << Log::Indent() << tmp.str() << Log::Endl(); + + aWriteStream.WriteIndent(); + aWriteStream.WriteBin(tmp.str().data(), tmp.str().size()); + aWriteStream.WriteLineEnd(); + } + } + + aWriteStream.DecIndent(); + + if(aWriteStream.HumanReadable()) + { + // Human + aWriteStream.WriteIndent(); + aWriteStream.WriteCStr("End"); + aWriteStream.WriteBin(iName.data(), iName.size()); + aWriteStream.WriteLineEnd(); + } + + prog << Log::Indent() << endName << Log::Endl(); + + return; +} + +void EncDecContainer::Decode(RDecodeReadStream &aReadStream) +{ + // Calculate Start/End container names + std::string startName("Start"); + startName.append(iName); + std::string endName("End"); + endName.append(iName); + + prog << Log::Indent() << "Reading " << startName << Log::Endl(); + + if(aReadStream.HumanReadable()) + { + // Human + + // Check/consume container StartX + aReadStream.CheckName(startName); + + prog.IncIndent(); + + // Create items until we find the container EndX + TUint32 entryNum=1; + while(aReadStream.PeakToken() != endName) + { + // Progress message + prog << Log::Indent() << "# Entry " << std::dec << entryNum++ << std::hex << Log::Endl(); + + EncDecContainerItem *item = iFactory(); + bool bracketedItem = (item->ItemType() != 0); + std::string itemName; + if(bracketedItem && aReadStream.HumanReadable()) + { + // Bracketed item, so read ItemType tag and ItemName + std::string itemStart("Start"); + itemStart.append(item->ItemType()); + aReadStream.CheckName(itemStart); + prog << Log::Indent() << itemStart; + + // Read item name + aReadStream.ReadNextToken(); + itemName = aReadStream.Token(); + } + + prog.IncIndent(); + item->Decode(aReadStream); + iArray.push_back(item); + prog.DecIndent(); + if(bracketedItem && aReadStream.HumanReadable()) + { + // Bracketed item, so read End ItemType tag + std::string itemEnd("End"); + itemEnd.append(item->ItemType()); + aReadStream.CheckName(itemEnd); + // and set item name + item->SetItemName(itemName); + } + } + + // Check/consume container EndX + aReadStream.CheckName(endName); + + prog.DecIndent(); + } + else + { + // Binary + // Read number of entries + TUint32 arrayLength; + aReadStream.RawRead(&arrayLength, sizeof(arrayLength)); + + prog.IncIndent(); + for(TUint32 i=0; i < arrayLength; ++i) + { + EncDecContainerItem *item = iFactory(); + prog << Log::Indent() << "# Entry " << std::dec << i+1 << std::hex << Log::Endl(); + prog.IncIndent(); + item->Decode(aReadStream); + prog.DecIndent(); + iArray.push_back(item); + } + prog.DecIndent(); + } + + prog << Log::Indent() << endName << Log::Endl(); + +} + + + + +REncodeWriteStream& operator<<(REncodeWriteStream& aStream, const EncDecContainer &aContainer) +{ + aContainer.Encode(aStream); + return aStream; +} + +RDecodeReadStream& operator>>(RDecodeReadStream& aStream,EncDecContainer &aContainer) +{ + aContainer.Decode(aStream); + return aStream; +} + +// +// TUid +// +void EncodeHuman(REncodeWriteStream& aStream,const TUid &aUid) +{ + aStream.WriteHexNumber(aUid.iUid); +} +void DecodeHuman(RDecodeReadStream& aStream,TUid &aUid) +{ + aUid.iUid = aStream.ReadUnsignedNumber(sizeof(aUid.iUid)); +} + +// +// TName +// +void EncodeHuman(REncodeWriteStream& aStream,const TName &aName) +{ + // Compress the internal UTF-16 to human readable UTF-8 + ; + TInt outputBytes = 0; + TUint8 *outBuf = cstrFromUtf16(aName.Ptr(), aName.Length(), outputBytes); + + aStream.WriteByte('"'); + aStream.WriteQuotedUtf8(outBuf, outputBytes); + aStream.WriteByte('"'); + + delete [] outBuf; +} +void DecodeHuman(RDecodeReadStream& aStream,TName &aName) +{ + aStream.ReadNextToken(); + + // Expand UTF-8 into internal UTF-16LE representation + TInt outputWords = 0; + TText *outputBuf = utf16FromUtf8((const TUint8 *)aStream.Token().data(), aStream.Token().size(), outputWords); + memcpy((void *)aName.Ptr(), outputBuf, outputWords*2); + aName.SetLength(outputWords); + delete [] outputBuf; +} + +void readContainer(const std::string &aFileName, bool aHuman, EncDecContainer &container) +{ + if(aHuman) + { + FileReadStream fileReadStream(aFileName, true); + std::string certBaseName(aFileName); + size_t dotLoc = certBaseName.rfind('.'); + if(dotLoc != std::string::npos) + { + certBaseName.erase(dotLoc); + } + certBaseName += '_'; + RDecodeReadStream inStream(certBaseName, fileReadStream); // human readable + inStream >> container; + inStream.Close(); + } + else + { + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + CPermanentFileStore* store = CPermanentFileStore::OpenLC(fs, _L16(aFileName.c_str()),EFileShareAny | EFileRead); + store->SetTypeL(KPermanentFileStoreLayoutUid); + + RStoreReadStream rootStream; + rootStream.OpenLC(*store, store->Root()); + TUint32 dataStreamId; + rootStream >> dataStreamId; + CleanupStack::PopAndDestroy(&rootStream); + + RStoreReadStream dataStream; + dataStream.OpenLC(*store, dataStreamId); + + RDecodeReadStream readStream(store, dataStream); // binary store + + readStream >> container; + + CleanupStack::PopAndDestroy(&dataStream); + CleanupStack::PopAndDestroy(store); + CleanupStack::PopAndDestroy(&fs); + } +} + + +void writeContainer(const char *aFileName, bool aHuman, bool aPemOut, bool aVerbose, const EncDecContainer &container) +{ + prog << Log::Indent() << "Writing output file '" << aFileName << "'" << Log::Endl(); + prog.IncIndent(); + if(aHuman) + { + FileWriteStream fileWriteStream(aFileName); + // Calculate based name by striping last .xx extension and appending an underscore. + std::string certBaseName(aFileName); + size_t dotLoc = certBaseName.rfind('.'); + if(dotLoc != std::string::npos) + { + certBaseName.erase(dotLoc); + } + certBaseName += '_'; + + REncodeWriteStream outStream(certBaseName, fileWriteStream); // human readable + outStream.PemOut() = aPemOut; + outStream.Verbose() = aVerbose; + outStream << container; + outStream.Close(); + } + else + { + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + + CFileStore* store = CPermanentFileStore::ReplaceLC(fs,_L16(aFileName),EFileShareAny | EFileRead | EFileWrite); + store->SetTypeL(KPermanentFileStoreLayoutUid); + + RStoreWriteStream dataStream; + TStreamId dataStreamId = dataStream.CreateLC(*store); + + REncodeWriteStream outStream(store, dataStream); // binary + outStream << container; + outStream.Close(); + + dataStream.CommitL(); + dataStream.Close(); + + RStoreWriteStream rootStream; + TStreamId rootId = rootStream.CreateLC(*store); + rootStream << dataStreamId; + rootStream.CommitL(); + rootStream.Close(); + + + store->SetRootL(rootId); + store->CommitL(); + CleanupStack::PopAndDestroy(&dataStream); + CleanupStack::PopAndDestroy(store); + CleanupStack::PopAndDestroy(&fs); + } + prog.DecIndent(); +} + + +// End of file