sl@0: #ifndef __ENCDEC_H__ sl@0: #define __ENCDEC_H__/* sl@0: * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: * All rights reserved. sl@0: * This component and the accompanying materials are made available sl@0: * under the terms of the License "Eclipse Public License v1.0" sl@0: * which accompanies this distribution, and is available sl@0: * at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: * sl@0: * Initial Contributors: sl@0: * Nokia Corporation - initial contribution. sl@0: * sl@0: * Contributors: sl@0: * sl@0: * Description: sl@0: * sl@0: */ sl@0: sl@0: sl@0: #include sl@0: #include "filestream.h" sl@0: #include "logger.h" sl@0: sl@0: /** sl@0: * @file sl@0: * @internalComponent sl@0: */ sl@0: sl@0: typedef uint64_t TUint64; sl@0: typedef int64_t TInt64; sl@0: sl@0: typedef int TInt32; sl@0: typedef unsigned int TUint32; sl@0: sl@0: typedef short TInt16; sl@0: typedef unsigned short TUint16; sl@0: sl@0: typedef signed char TInt8; sl@0: typedef unsigned char TUint8; sl@0: sl@0: typedef TUint32 TChar; sl@0: sl@0: typedef int TBool; sl@0: sl@0: typedef void TAny; sl@0: sl@0: TUint8 fromHex(TUint8 ch); sl@0: TUint32 ReadUnsignedNumber(std::string &aStr, size_t aSize); sl@0: class RDecodeReadStream sl@0: { sl@0: public: sl@0: // Create store based stream in binary mode sl@0: RDecodeReadStream(CFileStore *aStore, RReadStream &aReadStream); sl@0: // Create a file based stream in human mode sl@0: RDecodeReadStream(const std::string &aCertBaseName, RReadStream &aReadStream); sl@0: sl@0: void RawRead(void *aPtr, TUint32 aLength); sl@0: sl@0: void CheckName(const std::string &aExpected); sl@0: TUint32 ReadUnsignedNumber(size_t aSize); sl@0: sl@0: // Return current token sl@0: const std::string &Token() const; sl@0: // Discard current token and read the next sl@0: void ReadNextToken(); sl@0: sl@0: // Return the token after the current token. sl@0: // The current token is not updated. sl@0: // This will only look ahead a single token. sl@0: const std::string &PeakToken(); sl@0: sl@0: bool HumanReadable() const; sl@0: void Close(); sl@0: sl@0: CFileStore *iStore; // Only used for STORE based streams ie. not human readable sl@0: std::string iCertBaseName; // Only used for file based streams ie. human readable sl@0: sl@0: RReadStream &iReadStream; sl@0: private: sl@0: bool iHumanReadable; sl@0: std::string iToken; sl@0: bool iPrefetchedTokenIsValid; sl@0: std::string iPrefetchedToken; sl@0: sl@0: void GetToken(std::string &aToken); sl@0: }; sl@0: sl@0: sl@0: class REncodeWriteStream sl@0: { sl@0: public: sl@0: // Construct stream based on a store in binary mode sl@0: REncodeWriteStream(CFileStore *aStore, RWriteStream &aWriteStream); // store stream sl@0: // Construct stream based on a file in human mode sl@0: REncodeWriteStream(const std::string &aCertBaseName, RWriteStream &aWriteStream); // file stream sl@0: // Create a human readable log sl@0: REncodeWriteStream(Log &aLog); sl@0: sl@0: /** sl@0: Write binary data to the output stream without escaping sl@0: it. This data is allowed to contain the NUL (0) character and sl@0: may be binary data for the store file or UTF-8 text for the sl@0: human readable config file output. sl@0: */ sl@0: void WriteBin(const void *aPtr, TUint32 aLength); sl@0: /** sl@0: Write a C style string to the output stream without escaping sl@0: it. It is NOT safe to write a generic UTF-8 string via this sl@0: this function, because such a string may contain embedded 0 sl@0: characters. A 7-bit ASCII string will work reliably. This sl@0: function is intended for writing 7-but ASCII strings to the sl@0: human readable config file, and should not be used for writing sl@0: data to a store file. sl@0: */ sl@0: void WriteQuotedUtf8(const void *aStr, TUint32 aLength); sl@0: /** sl@0: Write a single byte. sl@0: */ sl@0: void WriteByte(TUint8 aByte); sl@0: /** sl@0: Write a UTF-8 string quoting backslash and double quote characters. sl@0: sl@0: A backslash will be written as \\ sl@0: A quote character will be written as \" sl@0: sl@0: Note that all bytes in UTF-8 escape sequences have the top bit sl@0: set therefore the quoting technique used by this function will sl@0: not effect them. sl@0: */ sl@0: void WriteCStr(const void *aCstr); sl@0: sl@0: void WriteHexNumber(TUint32 aNumber); sl@0: sl@0: void WriteSpace(); sl@0: void WriteLineEnd(); sl@0: sl@0: void WriteIndent(); sl@0: void IncIndent(); sl@0: void DecIndent(); sl@0: sl@0: bool HumanReadable() const; sl@0: bool &PemOut(); sl@0: bool &Verbose(); sl@0: void Close(); sl@0: sl@0: bool Quiet() const; sl@0: sl@0: CFileStore *StoreObject(); sl@0: RWriteStream &StoreWriteStream(); sl@0: sl@0: std::string CertFileName(TUint32 aFormat, TUint32 aCertNumber); sl@0: sl@0: private: sl@0: CFileStore *iStore; // Only used for STORE based streams ie. not human readable sl@0: std::string iCertBaseName; // Only used for file based streams ie. human readable sl@0: sl@0: RWriteStream *iWriteStream; // STORE or file based stream, valid if iLogStream==0 sl@0: sl@0: std::ostream *iLogStream; sl@0: private: sl@0: bool iHumanReadable; sl@0: bool iPemOut; sl@0: bool iVerbose; sl@0: int iIndentLevel; sl@0: }; sl@0: sl@0: /** sl@0: A template which generates a class which can be sl@0: internalised/externalised via the REncodeWriteStream and sl@0: RDecodeReadStream templates. sl@0: sl@0: The constructor takes a C string constant which specifies the field sl@0: name. sl@0: sl@0: The optional aCommentOnlyInHumanMode parameter changes operation in human sl@0: mode only - The field will be written as a comment, and will not be sl@0: accepted whilst reading. sl@0: sl@0: Typical use is something like this:- sl@0: EncDecObject fieldCost("cost"); sl@0: sl@0: Typically this template will not require specialisations to handle sl@0: additional types. sl@0: */ sl@0: template class EncDecObject sl@0: { sl@0: public: sl@0: EncDecObject(const char *aName, bool aCommentOnlyInHumanMode = false) sl@0: : iName(aName), iCommentOnlyInHumanMode(aCommentOnlyInHumanMode), iValue() sl@0: { sl@0: } sl@0: sl@0: const std::string &Name() const { return iName; } sl@0: sl@0: const T &Value() const { return iValue; } sl@0: T &Value() { return iValue; } sl@0: sl@0: bool CommentOnlyInHumanMode() const { return iCommentOnlyInHumanMode; } sl@0: private: sl@0: std::string iName; sl@0: bool iCommentOnlyInHumanMode; sl@0: T iValue; sl@0: }; sl@0: sl@0: /** sl@0: Class for handling Enum values sl@0: */ sl@0: struct EnumEntry sl@0: { sl@0: const char *iName; sl@0: TUint32 iValue; sl@0: }; sl@0: sl@0: // This class should be template by a type which standard store can sl@0: // internalise/externalise ie TUint8/TUin16/TUint32 (probably not an enum) sl@0: templateclass EncDecEnum sl@0: { sl@0: public: sl@0: /** sl@0: Construct an object for handling an enum type. sl@0: aEnumEntries must be a pointer to a static array of EnumEntry sl@0: structs terminated by one with iName==0. sl@0: */ sl@0: EncDecEnum(const char *aName, const EnumEntry *aEnumEntries, bool aCommentOnlyInHumanMode = false); sl@0: sl@0: const std::string &Name() const { return iName; } sl@0: sl@0: const T &Value() const { return iValue; } sl@0: T &Value() { return iValue; } sl@0: sl@0: const char *ValueName() const { return ValueToName(iValue); } sl@0: sl@0: bool CommentOnlyInHumanMode() const { return iCommentOnlyInHumanMode; } sl@0: sl@0: void SetValue(const T &aValue); sl@0: void SetValue(const char *aName); sl@0: private: sl@0: const char *ValueToName(const T &aValue) const; sl@0: std::string iName; sl@0: TUint8 iWidth; sl@0: const EnumEntry *iEnumEntries; // Array terminated by entry with iName==0 sl@0: bool iCommentOnlyInHumanMode; sl@0: T iValue; sl@0: }; sl@0: sl@0: /* sl@0: The EncDecContainer class manages a set of objects which inherit sl@0: from the EncDecContainerItem base class. It can be sl@0: internalised/externalised via the REncodeWriteStream and sl@0: RDecodeReadStream templates. sl@0: sl@0: The constructor takes a C string constant which specifies the sl@0: container name. sl@0: sl@0: The binary form is a 32 bit count followed by a sequence of sl@0: EncDecContainerItem objects. sl@0: sl@0: In human readable form is a sequence of zero or more human readable sl@0: representations of T bracketed by StartX and EndX. Where X is the sl@0: container name. sl@0: */ sl@0: class EncDecContainerItem sl@0: { sl@0: public: sl@0: virtual ~EncDecContainerItem(); sl@0: sl@0: // Get the type name for the container. If 0 then do not bracket item with StartType/EndType sl@0: virtual const char *ItemType() const = 0; sl@0: // If ItemType()!=0 then ItemName will be included after StartType sl@0: virtual std::string ItemName() const; sl@0: virtual void SetItemName(const std::string &aName); sl@0: virtual void Encode(REncodeWriteStream &aWriteStream) = 0; sl@0: virtual void Decode(RDecodeReadStream &aReadStream) = 0; sl@0: }; sl@0: sl@0: typedef EncDecContainerItem *EncDecContainerItemFactoryFunc(); sl@0: sl@0: class EncDecContainer sl@0: { sl@0: public: sl@0: EncDecContainer(const char *aContainerName, EncDecContainerItemFactoryFunc *aFactory); sl@0: ~EncDecContainer(); sl@0: sl@0: void push_back(EncDecContainerItem *aItem); sl@0: const EncDecContainerItem &operator[](TUint32 aIndex) const; sl@0: EncDecContainerItem &operator[](TUint32 aIndex); sl@0: TUint32 size() const; sl@0: void reset(); sl@0: sl@0: void Encode(REncodeWriteStream &aWriteStream) const; sl@0: void Decode(RDecodeReadStream &aReadStream); sl@0: sl@0: private: sl@0: std::string iName; sl@0: EncDecContainerItemFactoryFunc *iFactory; sl@0: std::vector iArray; sl@0: }; sl@0: sl@0: void readContainer(const std::string &aFileName, bool aHuman, EncDecContainer &container); sl@0: void writeContainer(const char *aFileName, bool aHuman, bool aPemOut, bool aVerbose, const EncDecContainer &container); sl@0: sl@0: /* sl@0: The EncodeHuman template functions are used to convert a type to sl@0: human readable form. sl@0: sl@0: Do NOT try and write specialisations of these templates, it probably sl@0: will not work, instead just write a conventional function which is sl@0: selected via the norml overloading rules. See GOTW articles on the sl@0: web. sl@0: */ sl@0: sl@0: // The basic EncodeHuman template assumes that T is an unsigned sl@0: // integer and encodes it in hex. sl@0: template void EncodeHuman(REncodeWriteStream& aStream,const T &aUnsignedIntType) sl@0: { sl@0: aStream.WriteHexNumber(aUnsignedIntType); sl@0: } sl@0: sl@0: void EncodeHuman(REncodeWriteStream& aStream,const TUid &aUid); sl@0: void EncodeHuman(REncodeWriteStream& aStream,const TName &aName); sl@0: sl@0: /* sl@0: The DecodeHuman template functions are used to read in the human sl@0: readable form. sl@0: sl@0: Do NOT try and write specialisations of these templates, it probably sl@0: will not work, instead just write a conventional function which is sl@0: selected via the norml overloading rules. See GOTW articles on the sl@0: web. sl@0: */ sl@0: sl@0: // The basic DecodeHuman template assumes that T is an unsigned integer sl@0: // and decodes it from either decimal or hex (starting with 0x). The sl@0: // code calls RDecodeReadStream::ReadUnsignedNumber which will decode sl@0: // the number (max 32bits) and check it fits into specified type. sl@0: template void DecodeHuman(RDecodeReadStream& aStream,T &aUnsignedIntType) sl@0: { sl@0: aUnsignedIntType = (T) aStream.ReadUnsignedNumber(sizeof(aUnsignedIntType)); sl@0: } sl@0: sl@0: void DecodeHuman(RDecodeReadStream& aStream,TUid &aUid); sl@0: void DecodeHuman(RDecodeReadStream& aStream,TName &aName); sl@0: sl@0: /* sl@0: The following two template operators require the object which is sl@0: being internalised or externalised to provide a const Name function sl@0: (which returns the field name) and two Value functions (one const sl@0: and one not) which return a reference to an instance of the type sl@0: being handled. A function called CommentOnlyInHumanMode should sl@0: return true if the human output should be prefixed with # and should sl@0: be reject when reading. sl@0: sl@0: Typicaly types will be wrapped by the EncDecObject template to sl@0: provide the Name() and Value() functions required by these sl@0: templates. sl@0: sl@0: Do NOT try and write specialisations of these templates, it probably sl@0: will not work, instead just write a conventional function which is sl@0: selected via the norml overloading rules. See GOTW articles on the sl@0: web. sl@0: sl@0: Note: You probably only need to enhance the EncodeHuman/DecodeHuman sl@0: functions unless you are adding a new variable length container type. sl@0: */ sl@0: sl@0: /* sl@0: The externalise operator << first checks if the destination stream sl@0: is HumanReadable. If it is, it writes the Name(), followed by a sl@0: space, calls EncodeHuman, then WriteLineEnd. If the stream is not sl@0: HumanReadable it simply applies the << operator to the Value(). sl@0: */ sl@0: template sl@0: inline REncodeWriteStream& operator<<(REncodeWriteStream& aStream,const T& anObject); sl@0: sl@0: REncodeWriteStream& operator<<(REncodeWriteStream& aStream, const EncDecContainer &aContainer); sl@0: sl@0: template sl@0: REncodeWriteStream& operator<<(REncodeWriteStream& aStream, const EncDecEnum &aEncDecEnum); sl@0: sl@0: /* sl@0: The internalise operator >> first checks if the source stream is sl@0: HumanReadable. If it is, it reads/checks the field name then calls sl@0: DecodeHuman. If the stream is not HumanReadable sl@0: it simply applies the >> operator to the Value(). sl@0: */ sl@0: template sl@0: inline RDecodeReadStream& operator>>(RDecodeReadStream& aStream,T& anObject); sl@0: sl@0: RDecodeReadStream& operator>>(RDecodeReadStream& aStream,EncDecContainer &aContainer); sl@0: sl@0: template sl@0: RDecodeReadStream& operator>>(RDecodeReadStream& aStream, EncDecEnum &aEncDecEnum); sl@0: sl@0: #include "encdec.inl" sl@0: sl@0: sl@0: sl@0: #endif