Update contrib.
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
4 * This component and the accompanying materials are made available
5 * under the terms of the License "Eclipse Public License v1.0"
6 * which accompanies this distribution, and is available
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
23 #include "stringconv.h"
25 #include "x509utils.h"
27 RDecodeReadStream::RDecodeReadStream(CFileStore *aStore, RReadStream &aReadStream)
28 : iStore(aStore), iCertBaseName(), iReadStream(aReadStream), iHumanReadable(false), iToken(),
29 iPrefetchedTokenIsValid(false), iPrefetchedToken()
33 RDecodeReadStream::RDecodeReadStream(const std::string &aCertBaseName, RReadStream &aReadStream)
34 : iStore(0), iCertBaseName(aCertBaseName), iReadStream(aReadStream), iHumanReadable(true), iToken(),
35 iPrefetchedTokenIsValid(false), iPrefetchedToken()
39 void RDecodeReadStream::RawRead(void *aPtr, TUint32 aLength)
41 iReadStream.ReadL((TUint8 *)aPtr, aLength);
44 void RDecodeReadStream::CheckName(const std::string &aExpected)
48 if(iToken != aExpected)
50 dbg << Log::Indent() << "Expected token '" << aExpected <<"' but got token '" << iToken << "'" << Log::Endl();
56 TUint32 ReadUnsignedNumber(std::string &aStr, size_t aSize)
59 std::istringstream ss(aStr);
61 if((aStr.length() > 2) &&
63 ((aStr[1] == 'x') || (aStr[1] == 'X')))
65 // Hex number starting with 0x
67 ss >> ch >> ch; // Discard the 0x
68 ss >> std::hex >> val;
76 // Now work out if we consumed the entire token without error
79 // Number decode failed
80 dbg << Log::Indent() << "Failed to decode '" << aStr << "' as a number" << Log::Endl();
84 // Make sure we consumed all data
87 // Trailing chars on numeric token
94 // nb the following check would fail if aSize==4 because x>>32 == x if sizeof(x)==4
95 if((val >> (8*aSize)) != 0)
97 // Higher order bits are set above the size of the variable we
106 TUint32 RDecodeReadStream::ReadUnsignedNumber(size_t aSize)
109 if((TUint32(aSize)>4))
117 return ::ReadUnsignedNumber(iToken, aSize);
120 const std::string &RDecodeReadStream::Token() const
125 void RDecodeReadStream::ReadNextToken()
127 if(iPrefetchedTokenIsValid)
129 // Copy prefetched token to current token
130 iToken = iPrefetchedToken;
131 iPrefetchedToken.clear();
132 iPrefetchedTokenIsValid = false;
139 const std::string &RDecodeReadStream::PeakToken()
141 if(!iPrefetchedTokenIsValid)
143 GetToken(iPrefetchedToken);
144 iPrefetchedTokenIsValid = true;
147 return iPrefetchedToken;
154 bool RDecodeReadStream::HumanReadable() const
156 return iHumanReadable;
160 void RDecodeReadStream::Close()
165 void RDecodeReadStream::GetToken(std::string &aToken)
177 while((ch != '\r') && (ch != '\n'))
183 } while((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n'));
188 iReadStream >> ch; // read first char
193 // \X causes X to always be saved (even if X is ")
197 aToken.push_back(ch);
200 // At this point ch contains WS so it can be discarded.
204 // Read a non-string token
205 while((ch != ' ') && (ch != '\t') && (ch != '\r') && (ch != '\n'))
207 aToken.push_back(ch);
210 // At this point ch contains WS so it can be discarded.
218 REncodeWriteStream::REncodeWriteStream(CFileStore *aStore, RWriteStream &aWriteStream)
220 iCertBaseName(), // not used for STORE based streams
221 iWriteStream(&aWriteStream),
223 iHumanReadable(false), iPemOut(false), iVerbose(false), iIndentLevel(0)
227 REncodeWriteStream::REncodeWriteStream(const std::string &aCertBaseName, RWriteStream &aWriteStream)
228 : iStore(0), iCertBaseName(aCertBaseName), iWriteStream(&aWriteStream),
230 iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(0)
234 REncodeWriteStream::REncodeWriteStream(Log &aLog)
235 : iStore(0), iWriteStream(0), iLogStream(&aLog.Stream()),
236 iHumanReadable(true), iPemOut(false), iVerbose(false), iIndentLevel(aLog.IndentLevel())
240 void REncodeWriteStream::WriteBin(const void *aPtr, TUint32 aLength)
244 iWriteStream->WriteL((TUint8 *)aPtr, aLength);
248 iLogStream->write((const char *)aPtr, aLength);
253 void REncodeWriteStream::WriteQuotedUtf8(const void *aStr, TUint32 aLength)
255 std::string tmp((const char *)aStr, aLength);
257 // Insert a backslash before any backslash chars
259 while((pos = tmp.find('\\', pos)) != std::string::npos)
261 tmp.insert(pos, "\\", 1);
265 // Insert a backslash before any double quote chars
267 while((pos = tmp.find('"', pos)) != std::string::npos)
269 tmp.insert(pos, "\\", 1);
275 iWriteStream->WriteL((TUint8 *)tmp.data(), tmp.size());
279 iLogStream->write(tmp.data(), tmp.size());
284 void REncodeWriteStream::WriteByte(TUint8 aByte)
289 void REncodeWriteStream::WriteCStr(const void *aCstr)
291 WriteBin(aCstr, strlen((const char *)aCstr));
294 void REncodeWriteStream::WriteHexNumber(TUint32 aNumber)
297 int len = sprintf(buf, "0x%x", aNumber);
302 void REncodeWriteStream::WriteSpace()
305 if(!iHumanReadable) return;
310 void REncodeWriteStream::WriteLineEnd()
313 if(!iHumanReadable) return;
323 void REncodeWriteStream::WriteIndent()
326 if(!iHumanReadable) return;
328 for(int i=0; i<iIndentLevel; ++i)
334 void REncodeWriteStream::IncIndent()
339 if(iIndentLevel < 0) FatalError();
343 void REncodeWriteStream::DecIndent()
348 if(iIndentLevel < 0) FatalError();
352 bool REncodeWriteStream::HumanReadable() const
354 return iHumanReadable;
357 bool &REncodeWriteStream::PemOut()
362 bool &REncodeWriteStream::Verbose()
369 std::string REncodeWriteStream::CertFileName(TUint32 aFormat, TUint32 aCertNumber)
371 std::stringstream ss;
375 if(aFormat == EX509Certificate)
396 void REncodeWriteStream::Close()
402 iWriteStream->Close();
406 CFileStore *REncodeWriteStream::StoreObject()
409 if(iStore == 0) FatalError();
414 RWriteStream &REncodeWriteStream::StoreWriteStream()
417 if(iWriteStream == 0) FatalError();
419 return *iWriteStream;
422 bool REncodeWriteStream::Quiet() const
424 return iLogStream != 0;
427 TUint8 fromHex(TUint8 ch)
429 Convert a single hex char from ascii
432 // convert to lowercase
433 if((ch >= 'A') && (ch <= 'F'))
438 if((ch >= 'a') && (ch <= 'f'))
440 return ch - 'a' + 10;
444 if((ch >= '0') && (ch <= '9'))
454 EncDecContainerItem::~EncDecContainerItem()
459 #ifdef _BullseyeCoverage
460 #pragma BullseyeCoverage off
462 std::string EncDecContainerItem::ItemName() const
464 // Should never be called
470 void EncDecContainerItem::SetItemName(const std::string &)
472 // Should never be called
475 #ifdef _BullseyeCoverage
476 #pragma BullseyeCoverage restore
481 EncDecContainer::EncDecContainer(const char *aContainerName, EncDecContainerItemFactoryFunc *aFactory)
482 : iName(aContainerName), iFactory(aFactory), iArray()
486 EncDecContainer::~EncDecContainer()
491 void EncDecContainer::push_back(EncDecContainerItem *aItem)
493 iArray.push_back(aItem);
496 const EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex) const
498 return *iArray[aIndex];
501 EncDecContainerItem &EncDecContainer::operator[](TUint32 aIndex)
503 return *iArray[aIndex];
506 TUint32 EncDecContainer::size() const
508 return iArray.size();
511 void EncDecContainer::reset()
513 while(!iArray.empty())
515 EncDecContainerItem *p = iArray.back();
523 void EncDecContainer::Encode(REncodeWriteStream &aWriteStream) const
525 // Calculate Start/End container names
526 std::string startName("Start");
527 startName.append(iName);
528 std::string endName("End");
529 endName.append(iName);
531 prog << Log::Indent() << "Writing " << startName << Log::Endl();
533 TUint32 arrayLength = iArray.size();
535 if(aWriteStream.HumanReadable())
538 aWriteStream.WriteIndent();
539 aWriteStream.WriteBin(startName.data(), startName.size());
540 aWriteStream.WriteLineEnd();
545 // Write length of array
546 aWriteStream.WriteBin(&arrayLength, sizeof(arrayLength));
549 aWriteStream.IncIndent();
551 // Write array entries
552 for(TUint32 i=0; i < arrayLength; ++i)
554 std::ostringstream entryComment;
555 entryComment << "# Entry " << i+1;
556 prog << Log::Indent() << entryComment.str() << Log::Endl();
558 bool bracketItem = (iArray[i]->ItemType() != 0);
559 if(aWriteStream.HumanReadable())
563 std::ostringstream itemStart;
564 itemStart << "Start" << iArray[i]->ItemType() << " " << iArray[i]->ItemName();
565 prog << Log::Indent() << itemStart.str() << Log::Endl();
567 aWriteStream.WriteIndent();
568 aWriteStream.WriteCStr("Start");
569 aWriteStream.WriteCStr(iArray[i]->ItemType());
570 aWriteStream.WriteCStr(" \"");
571 aWriteStream.WriteQuotedUtf8(iArray[i]->ItemName().data(), iArray[i]->ItemName().size());
572 aWriteStream.WriteCStr("\"");
573 aWriteStream.WriteLineEnd();
577 aWriteStream.WriteIndent();
578 aWriteStream.WriteBin(entryComment.str().data(), entryComment.str().size());
579 aWriteStream.WriteLineEnd();
582 aWriteStream.IncIndent();
583 iArray[i]->Encode(aWriteStream);
584 aWriteStream.DecIndent();
585 if(bracketItem && aWriteStream.HumanReadable())
587 std::ostringstream tmp;
588 tmp << "End" << iArray[i]->ItemType();
590 prog << Log::Indent() << tmp.str() << Log::Endl();
592 aWriteStream.WriteIndent();
593 aWriteStream.WriteBin(tmp.str().data(), tmp.str().size());
594 aWriteStream.WriteLineEnd();
598 aWriteStream.DecIndent();
600 if(aWriteStream.HumanReadable())
603 aWriteStream.WriteIndent();
604 aWriteStream.WriteCStr("End");
605 aWriteStream.WriteBin(iName.data(), iName.size());
606 aWriteStream.WriteLineEnd();
609 prog << Log::Indent() << endName << Log::Endl();
614 void EncDecContainer::Decode(RDecodeReadStream &aReadStream)
616 // Calculate Start/End container names
617 std::string startName("Start");
618 startName.append(iName);
619 std::string endName("End");
620 endName.append(iName);
622 prog << Log::Indent() << "Reading " << startName << Log::Endl();
624 if(aReadStream.HumanReadable())
628 // Check/consume container StartX
629 aReadStream.CheckName(startName);
633 // Create items until we find the container EndX
635 while(aReadStream.PeakToken() != endName)
638 prog << Log::Indent() << "# Entry " << std::dec << entryNum++ << std::hex << Log::Endl();
640 EncDecContainerItem *item = iFactory();
641 bool bracketedItem = (item->ItemType() != 0);
642 std::string itemName;
643 if(bracketedItem && aReadStream.HumanReadable())
645 // Bracketed item, so read ItemType tag and ItemName
646 std::string itemStart("Start");
647 itemStart.append(item->ItemType());
648 aReadStream.CheckName(itemStart);
649 prog << Log::Indent() << itemStart;
652 aReadStream.ReadNextToken();
653 itemName = aReadStream.Token();
657 item->Decode(aReadStream);
658 iArray.push_back(item);
660 if(bracketedItem && aReadStream.HumanReadable())
662 // Bracketed item, so read End ItemType tag
663 std::string itemEnd("End");
664 itemEnd.append(item->ItemType());
665 aReadStream.CheckName(itemEnd);
667 item->SetItemName(itemName);
671 // Check/consume container EndX
672 aReadStream.CheckName(endName);
679 // Read number of entries
681 aReadStream.RawRead(&arrayLength, sizeof(arrayLength));
684 for(TUint32 i=0; i < arrayLength; ++i)
686 EncDecContainerItem *item = iFactory();
687 prog << Log::Indent() << "# Entry " << std::dec << i+1 << std::hex << Log::Endl();
689 item->Decode(aReadStream);
691 iArray.push_back(item);
696 prog << Log::Indent() << endName << Log::Endl();
703 REncodeWriteStream& operator<<(REncodeWriteStream& aStream, const EncDecContainer &aContainer)
705 aContainer.Encode(aStream);
709 RDecodeReadStream& operator>>(RDecodeReadStream& aStream,EncDecContainer &aContainer)
711 aContainer.Decode(aStream);
718 void EncodeHuman(REncodeWriteStream& aStream,const TUid &aUid)
720 aStream.WriteHexNumber(aUid.iUid);
722 void DecodeHuman(RDecodeReadStream& aStream,TUid &aUid)
724 aUid.iUid = aStream.ReadUnsignedNumber(sizeof(aUid.iUid));
730 void EncodeHuman(REncodeWriteStream& aStream,const TName &aName)
732 // Compress the internal UTF-16 to human readable UTF-8
734 TInt outputBytes = 0;
735 TUint8 *outBuf = cstrFromUtf16(aName.Ptr(), aName.Length(), outputBytes);
737 aStream.WriteByte('"');
738 aStream.WriteQuotedUtf8(outBuf, outputBytes);
739 aStream.WriteByte('"');
743 void DecodeHuman(RDecodeReadStream& aStream,TName &aName)
745 aStream.ReadNextToken();
747 // Expand UTF-8 into internal UTF-16LE representation
748 TInt outputWords = 0;
749 TText *outputBuf = utf16FromUtf8((const TUint8 *)aStream.Token().data(), aStream.Token().size(), outputWords);
750 memcpy((void *)aName.Ptr(), outputBuf, outputWords*2);
751 aName.SetLength(outputWords);
755 void readContainer(const std::string &aFileName, bool aHuman, EncDecContainer &container)
759 FileReadStream fileReadStream(aFileName, true);
760 std::string certBaseName(aFileName);
761 size_t dotLoc = certBaseName.rfind('.');
762 if(dotLoc != std::string::npos)
764 certBaseName.erase(dotLoc);
767 RDecodeReadStream inStream(certBaseName, fileReadStream); // human readable
768 inStream >> container;
774 User::LeaveIfError(fs.Connect());
775 CleanupClosePushL(fs);
777 CPermanentFileStore* store = CPermanentFileStore::OpenLC(fs, _L16(aFileName.c_str()),EFileShareAny | EFileRead);
778 store->SetTypeL(KPermanentFileStoreLayoutUid);
780 RStoreReadStream rootStream;
781 rootStream.OpenLC(*store, store->Root());
782 TUint32 dataStreamId;
783 rootStream >> dataStreamId;
784 CleanupStack::PopAndDestroy(&rootStream);
786 RStoreReadStream dataStream;
787 dataStream.OpenLC(*store, dataStreamId);
789 RDecodeReadStream readStream(store, dataStream); // binary store
791 readStream >> container;
793 CleanupStack::PopAndDestroy(&dataStream);
794 CleanupStack::PopAndDestroy(store);
795 CleanupStack::PopAndDestroy(&fs);
800 void writeContainer(const char *aFileName, bool aHuman, bool aPemOut, bool aVerbose, const EncDecContainer &container)
802 prog << Log::Indent() << "Writing output file '" << aFileName << "'" << Log::Endl();
806 FileWriteStream fileWriteStream(aFileName);
807 // Calculate based name by striping last .xx extension and appending an underscore.
808 std::string certBaseName(aFileName);
809 size_t dotLoc = certBaseName.rfind('.');
810 if(dotLoc != std::string::npos)
812 certBaseName.erase(dotLoc);
816 REncodeWriteStream outStream(certBaseName, fileWriteStream); // human readable
817 outStream.PemOut() = aPemOut;
818 outStream.Verbose() = aVerbose;
819 outStream << container;
825 User::LeaveIfError(fs.Connect());
826 CleanupClosePushL(fs);
828 CFileStore* store = CPermanentFileStore::ReplaceLC(fs,_L16(aFileName),EFileShareAny | EFileRead | EFileWrite);
829 store->SetTypeL(KPermanentFileStoreLayoutUid);
831 RStoreWriteStream dataStream;
832 TStreamId dataStreamId = dataStream.CreateLC(*store);
834 REncodeWriteStream outStream(store, dataStream); // binary
835 outStream << container;
838 dataStream.CommitL();
841 RStoreWriteStream rootStream;
842 TStreamId rootId = rootStream.CreateLC(*store);
843 rootStream << dataStreamId;
844 rootStream.CommitL();
848 store->SetRootL(rootId);
850 CleanupStack::PopAndDestroy(&dataStream);
851 CleanupStack::PopAndDestroy(store);
852 CleanupStack::PopAndDestroy(&fs);