Index: ext/libicpf/src/libicpf-tests/config-test.cpp =================================================================== diff -u -r1504b5e9af0cbbc688765c3530ee3443cb04fc01 -r21847bff9bc6958b98f3fe8bac319590b790fc0f --- ext/libicpf/src/libicpf-tests/config-test.cpp (.../config-test.cpp) (revision 1504b5e9af0cbbc688765c3530ee3443cb04fc01) +++ ext/libicpf/src/libicpf-tests/config-test.cpp (.../config-test.cpp) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) @@ -49,7 +49,23 @@ THROW(_t("Comparing string values failed"), 0, 0, 0); // store values in the file - Report(_t("Storing properties in the file '") TSTRFMT _t("'"), strPath.c_str()); + Report(_t("Storing properties in the file '") TSTRFMT _t("'\n"), strPath.c_str()); cfg.write(strPath.c_str()); + // read stored values + Report(_t("Reading properties from the file '") TSTRFMT _t("'\n"), strPath.c_str()); + cfg.read(strPath.c_str()); + + tstring_t strFile2; + pszName=_ttmpnam(NULL); + if(!pszName) + THROW(_t("Cannot generate the temporary file name"), 0, 0, 0); + tstring_t strPath2(_t(".")); + strPath2 += pszName; + strPath += _t("cfg"); + + Report(_t("Storing properties in the file '") TSTRFMT _t("'\n"), strPath2.c_str()); + cfg.write(strPath2.c_str()); + + ReportS(_t("Test finished.\n")); } Index: ext/libicpf/src/libicpf/cfg.cpp =================================================================== diff -u -rb337c059691a6940b52a86388ff427c734be8eb6 -r21847bff9bc6958b98f3fe8bac319590b790fc0f --- ext/libicpf/src/libicpf/cfg.cpp (.../cfg.cpp) (revision b337c059691a6940b52a86388ff427c734be8eb6) +++ ext/libicpf/src/libicpf/cfg.cpp (.../cfg.cpp) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) @@ -151,6 +151,7 @@ */ void config::read(const tchar_t* pszPath) { + assert(pszPath); m_lock.lock(); try { @@ -638,7 +639,7 @@ size_t tCount=(*it).get_count(); for (size_t t=0;t != tCount;t++) { - m_pCfgBase->set_value((*it).get_name(), (*it).get_value(szBuffer, 128, t));; + m_pCfgBase->set_value((*it).get_name(), (*it).get_value(szBuffer, 128, t)); } } Index: ext/libicpf/src/libicpf/cfg_xml.cpp =================================================================== diff -u -r6eab6a2aa6bb49edaf1fcbcb9c9d8bc2d7795bb0 -r21847bff9bc6958b98f3fe8bac319590b790fc0f --- ext/libicpf/src/libicpf/cfg_xml.cpp (.../cfg_xml.cpp) (revision 6eab6a2aa6bb49edaf1fcbcb9c9d8bc2d7795bb0) +++ ext/libicpf/src/libicpf/cfg_xml.cpp (.../cfg_xml.cpp) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) @@ -35,9 +35,18 @@ /// Standard constructor xml_node() : m_mNodes(), m_mAttr(), m_pParentNode(NULL) { }; /// Constructor defining the parent node - xml_node(xml_node* pParentNode) : m_mNodes(), m_mAttr(), m_pParentNode(pParentNode) { }; + xml_node(xml_node* pParentNode) : m_mNodes(), m_mAttr(), m_pParentNode(pParentNode) { }; /**@}*/ + /// Clears the node + void clear(bool bClearParent = false) + { + m_mNodes.clear(); + m_mAttr.clear(); + if(bClearParent) + m_pParentNode = NULL; + } + public: xml_storage m_mNodes; ///< Additional nodes inside of this one attr_storage m_mAttr; ///< String pairs belonging to this node @@ -87,39 +96,48 @@ void xml_cfg::element_start(void *userData, const tchar_t *name, const tchar_t **attrs) { XMLSTATE* pState=(XMLSTATE*)userData; + assert(pState); + assert(pState->pNode); - bool bContainer=true; + // temp + tchar_t szData[512]; + _sntprintf(szData, 512, _t("Opening Name: %s\n"), name); + OutputDebugString(szData); + // /temp - for (size_t t=0;attrs[t] != NULL;t+=2) + // parse node attributes + for(size_t t=0;attrs[t] != NULL;t+=2) { - if (_tcscmp(attrs[t], _t("value")) == 0) + if(_tcscmp(attrs[t], _t("value")) == 0) { // this is the value type tag pState->pNode->m_mAttr.insert(attr_storage::value_type(tstring_t(name), tstring_t(attrs[t+1]))); - bContainer=false; } } - if (bContainer) - { - std::pair pr; - assert(pState->pNode); - pr=pState->pNode->m_mNodes.insert(xml_storage::value_type(tstring_t(name), xml_node(pState->pNode))); - pState->pNode=&((*pr.first).second); - } + std::pair pr; + pr=pState->pNode->m_mNodes.insert(xml_storage::value_type(tstring_t(name), xml_node(pState->pNode))); + pState->pNode=&((*pr.first).second); } /** Expat handler for closing tag. * * \param[in] userData - user defined parameter * \param[in] name - name of the tag being closed */ -void xml_cfg::element_end(void *userData, const tchar_t* /*name*/) +void xml_cfg::element_end(void *userData, const tchar_t* name) { XMLSTATE* pState=(XMLSTATE*)userData; + assert(pState); + // temp + tchar_t szData[512]; + _sntprintf(szData, 512, _t("Closing Name: %s\n"), name); + OutputDebugString(szData); + // /temp + // go up one level - if (pState->pNode) + if(pState->pNode) pState->pNode=pState->pNode->m_pParentNode; else THROW(_t("Trying to close non-existent tag."), 0, 0, 0); @@ -138,20 +156,23 @@ */ void xml_cfg::read(const tchar_t* pszPath) { + // clear current contents + clear(); + // read the data from file in 64kB portions and feed it to the expat xml parser FILE* pFile=_tfopen(pszPath, _t("rb")); - if (pFile == NULL) + if(pFile == NULL) THROW(icpf::exception::format(_t("Cannot open the file ") TSTRFMT _t(" for reading."), pszPath), 0, errno, 0); // create the parser XML_Parser parser=XML_ParserCreate(NULL); XML_SetElementHandler(parser, element_start, element_end); // XML_SetCharacterDataHandler(parser, element_content); - XMLSTATE xs = { this, NULL }; + XMLSTATE xs = { this, m_pMainNode }; XML_SetUserData(parser, &xs); - for (;;) + for(;;) { bool bLast=false; @@ -160,25 +181,25 @@ // read some data to it size_t tSize=fread(pBuffer, 1, XML_BUFFER, pFile); - if (tSize < XML_BUFFER) + if(tSize < XML_BUFFER) { // check for errors int iErr=0; - if ( (iErr=ferror(pFile)) != 0) + if( (iErr=ferror(pFile)) != 0) THROW(icpf::exception::format(_t("Error reading from the file ") TSTRFMT _t("."), pszPath), 0, iErr, 0); else bLast=true; } // parse - if (!XML_ParseBuffer(parser, (int)tSize, bLast)) + if(!XML_ParseBuffer(parser, (int)tSize, bLast)) { // parser error THROW(icpf::exception::format(_t("Error encountered while parsing the xml file ") STRFMT _t(" - ") STRFMT _t("."), pszPath, XML_ErrorString(XML_GetErrorCode(parser))), 0, 0, 0); } // end of processing ? - if (bLast) + if(bLast) break; } @@ -197,26 +218,25 @@ */ void xml_cfg::save(const tchar_t* pszPath) { - // read the data from file in 64kB portions and feed it to the expat xml parser FILE* pFile=_tfopen(pszPath, _t("wb")); - if (pFile == NULL) + if(pFile == NULL) THROW(icpf::exception::format(_t("Cannot open the file ") TSTRFMT _t(" for writing."), pszPath), 0, errno, 0); // put BOM into the file -#if defined(_UNICODE) && (defined(_WIN32) || defined(_WIN64)) +#if(defined(_WIN32) || defined(_WIN64)) // utf-16le - uint_t uiBOM=0x0000feff; - uint_t uiCount=2; + const uint_t uiBOM=0x0000feff; + const uint_t uiCount=2; #else // utf-8 - uint_t uiBOM=0x00bfbbef; - uint_t uiCount=3; + const uint_t uiBOM=0x00bfbbef; + const uint_t uiCount=3; #endif try { // write bom, check if it succeeded - if (fwrite(&uiBOM, 1, uiCount, pFile) != uiCount) + if(fwrite(&uiBOM, 1, uiCount, pFile) != uiCount) THROW(_t("Cannot write the BOM to the file '") TSTRFMT _t("'"), 0, errno, 0); // and write @@ -237,31 +257,30 @@ xml_node* pNode=(xml_node*)pNodePtr; // attributes first - for (attr_storage::iterator it=pNode->m_mAttr.begin();it != pNode->m_mAttr.end();it++) + const tchar_t *pszFmt = _t("<") TSTRFMT _t(" value=\"") TSTRFMT _t("\"/>") ENDL; + for(attr_storage::iterator it=pNode->m_mAttr.begin();it != pNode->m_mAttr.end();it++) { - const tchar_t pszFmt[]=_t("<") TSTRFMT _t(" value=\"") TSTRFMT _t("\"/>") ENDL; - - int_t iSize=_sctprintf(pszFmt, (*it).first.c_str(), (*it).second.c_str()); - - if (_ftprintf(pFile, pszFmt, (*it).first.c_str(), (*it).second.c_str()) < 0) - THROW(_t("Cannot write requested data to the file"), 0, errno, 0); + fprintf_encoded(pFile, pszFmt, (*it).first.c_str(), (*it).second.c_str()); } // sub-nodes - for (xml_storage::iterator it=pNode->m_mNodes.begin();it != pNode->m_mNodes.end();it++) + for(xml_storage::iterator it=pNode->m_mNodes.begin();it != pNode->m_mNodes.end();it++) { - // tag opening - if (_ftprintf(pFile, _t("<") TSTRFMT _t(">") ENDL, (*it).first.c_str()) < 0) - THROW(_t("Cannot write requested data to the file"), 0, errno, 0); + xml_node& rNode = (*it).second; + if(!rNode.m_mNodes.empty() || !rNode.m_mAttr.empty()) + { + // opening tag + fprintf_encoded(pFile, _t("<") TSTRFMT _t(">") ENDL, (*it).first.c_str()); - save_node(pFile, &(*it).second); + save_node(pFile, &(*it).second); - if (_ftprintf(pFile, _t("") ENDL, (*it).first.c_str()) < 0) - THROW(_t("Cannot write requested data to the file"), 0, errno, 0); + // closing tag + fprintf_encoded(pFile, _t("") ENDL, (*it).first.c_str()); + } } } -void xml_cfg::fprintf_utf8(FILE* pFile, const tchar_t* pszFmt, ...) +void xml_cfg::fprintf_encoded(FILE* pFile, const tchar_t* pszFmt, ...) { va_list va; va_start(va, pszFmt); @@ -272,21 +291,37 @@ // make a formatted string va_start(va, pszFmt); - _vsntprintf(pszFormatted, iCount, pszFmt, va); + _vsntprintf(pszFormatted, iCount + 1, pszFmt, va); +#if(!defined(UNICODE) && (defined(_WIN32) || defined(_WIN64))) + // convert to unicode + iCount = lstrlen(pszFormatted); + int iWideCount = MultiByteToWideChar(CP_ACP, 0, pszFormatted, iCount, NULL, 0); + if(iWideCount) + { + wchar_t* pszWideString = new wchar_t[iWideCount]; + iWideCount = MultiByteToWideChar(CP_ACP, 0, pszFormatted, iCount, pszWideString, iWideCount); + fwrite(pszWideString, 1, iWideCount*sizeof(wchar_t), pFile); + delete [] pszWideString; + } + else + THROW(_t("Cannot convert string to wide characters."), 0, GetLastError(), 0); +#else + fwrite(pszFormatted, 1, iCount, pFile); +#endif + delete [] pszFormatted; va_end(va); - } /** Function starts a search operation. Given the name of the property - * to be searched for (ie. "ch/program/startup"), funtion searches for + * to be searched for(ie. "ch/program/startup"), funtion searches for * it and returns a handle that can be used by subsequent calls to the * find_next(). Free the handle using find_close() after finish. * - * \param[in] pszName - name of the property to search for (in the form of + * \param[in] pszName - name of the property to search for(in the form of * "ch/program/startup" for xml such as this: * * @@ -314,19 +349,19 @@ // parse the name const tchar_t* pSign=_tcschr(pszName, _t('/')); - if (pSign) + if(pSign) { // locate the xml_node associated with the name xml_storage::iterator it=pNode->m_mNodes.find(tstring_t(pszName, pSign-pszName)); - if (it != pNode->m_mNodes.end()) + if(it != pNode->m_mNodes.end()) return find(&(*it).second, pSign+1); else return NULL; } else { std::pair pr=pNode->m_mAttr.equal_range(pszName); - if (pr.first != pNode->m_mAttr.end() && pr.second != pNode->m_mAttr.end()) + if(pr.first != pNode->m_mAttr.end() && pr.second != pNode->m_mAttr.end()) { XMLFINDHANDLE* pfh=new XMLFINDHANDLE; pfh->it=pr.first; @@ -348,7 +383,7 @@ const tchar_t* xml_cfg::find_next(ptr_t pFindHandle) { XMLFINDHANDLE* pfh=(XMLFINDHANDLE*)pFindHandle; - if (pfh->it != pfh->itEnd) + if(pfh->it != pfh->itEnd) return (*pfh->it++).second.c_str(); else return NULL; @@ -388,10 +423,10 @@ xml_node* pNode=(xml_node*)pNodePtr; const tchar_t* pszSign=_tcschr(pszName, _t('/')); - if (pszSign != NULL) + if(pszSign != NULL) { xml_storage::iterator it=pNode->m_mNodes.find(tstring_t(pszName, pszSign-pszName)); - if (it != pNode->m_mNodes.end()) + if(it != pNode->m_mNodes.end()) set_value(&(*it).second, pszSign+1, pszValue, a); else { @@ -424,6 +459,15 @@ clear(m_pMainNode, pszName); } +/** Clears the contents of this class +* +* \param[in] pszName - name of the property to clear the values for +*/ +void xml_cfg::clear() +{ + m_pMainNode->clear(true); +} + /** Recursive clear function - searches recursively for a proper node * and finally clears the string map. * @@ -436,11 +480,11 @@ // parse the name const tchar_t* pSign=_tcschr(pszName, _t('/')); - if (pSign) + if(pSign) { // locate the xml_node associated with the name xml_storage::iterator it=pNode->m_mNodes.find(tstring_t(pszName, pSign-pszName)); - if (it != pNode->m_mNodes.end()) + if(it != pNode->m_mNodes.end()) clear(&(*it).second, pSign+1); } else Index: ext/libicpf/src/libicpf/cfg_xml.h =================================================================== diff -u -r6eab6a2aa6bb49edaf1fcbcb9c9d8bc2d7795bb0 -r21847bff9bc6958b98f3fe8bac319590b790fc0f --- ext/libicpf/src/libicpf/cfg_xml.h (.../cfg_xml.h) (revision 6eab6a2aa6bb49edaf1fcbcb9c9d8bc2d7795bb0) +++ ext/libicpf/src/libicpf/cfg_xml.h (.../cfg_xml.h) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) @@ -17,7 +17,7 @@ /** \name Construction/destruction/operators */ /**@{*/ xml_cfg(); ///< Standard constructor - xml_cfg(const xml_cfg& rSrc); ///< Copy construtor + xml_cfg(const xml_cfg& rSrc); ///< Copy constructor virtual ~xml_cfg(); ///< Standard destructor /**@}*/ @@ -42,28 +42,29 @@ virtual void set_value(const tchar_t* pszName, const tchar_t* pszValue, actions a=action_add); /// Clear values for a given property name virtual void clear(const tchar_t* pszName); + /// Clears all entries + virtual void clear(); /**@}*/ private: /// Find helper - recursively searches for a specific key node ptr_t find(ptr_t pNodePtr, const tchar_t* pszName); /// Set value helper - searches for a specific node and sets the value void set_value(ptr_t pNodePtr, const tchar_t* pszName, const tchar_t* pszValue, actions a=action_add); - /// Clear helper - clears the appropriate attribures + /// Clear helper - clears the appropriate attributes void clear(ptr_t pNodePtr, const tchar_t* pszName); /// Saves the specific node into the file void save_node(FILE* pFile, ptr_t pNodePtr); /// Stores the string to the file converted to utf8 - void fprintf_utf8(FILE* pFile, const tchar_t* pszFmt, ...); + void fprintf_encoded(FILE* pFile, const tchar_t* pszFmt, ...); static void element_start(void *userData, const tchar_t *name, const tchar_t **attrs); - static void element_end(void *userData, const tchar_t* /*name*/); + static void element_end(void *userData, const tchar_t* name); protected: ptr_t m_hMainNode; ///< Handle to the internal xml storage - tchar_t* m_pszBuffer; ///< Internal buffer to use for formatting data }; END_ICPF_NAMESPACE Index: ext/libicpf/src/libicpf/str_help.cpp =================================================================== diff -u -rb337c059691a6940b52a86388ff427c734be8eb6 -r21847bff9bc6958b98f3fe8bac319590b790fc0f --- ext/libicpf/src/libicpf/str_help.cpp (.../str_help.cpp) (revision b337c059691a6940b52a86388ff427c734be8eb6) +++ ext/libicpf/src/libicpf/str_help.cpp (.../str_help.cpp) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) @@ -28,7 +28,7 @@ * \param[in] ch - character to check * \return True if the character is a whitespace one, false otherwise. */ -LIBICPF_API bool is_whitespace(char_t ch) +bool string_tool::is_whitespace(char_t ch) { return ((ch >= 0x09) && (ch <= 0x0d)) || (ch == 0x20); } Index: ext/libicpf/src/libicpf/str_help.h =================================================================== diff -u -rb337c059691a6940b52a86388ff427c734be8eb6 -r21847bff9bc6958b98f3fe8bac319590b790fc0f --- ext/libicpf/src/libicpf/str_help.h (.../str_help.h) (revision b337c059691a6940b52a86388ff427c734be8eb6) +++ ext/libicpf/src/libicpf/str_help.h (.../str_help.h) (revision 21847bff9bc6958b98f3fe8bac319590b790fc0f) @@ -36,8 +36,12 @@ #define wcsnicmp wcsncasecmp #endif -/// Checks if a given character is a whitespace character -LIBICPF_API bool is_whitespace(char_t ch); +class LIBICPF_API string_tool +{ +public: + /// Checks if a given character is a whitespace character + static bool is_whitespace(tchar_t ch); +}; END_ICPF_NAMESPACE