Exemple #1
0
bool pws_os::RegDeleteEntry(const TCHAR *name)
{
  HKEY hSubkey;
  DWORD dwResult, dwType;
  bool bRetVal;

  // Keys in registry are in:
  // "HKEY_CURRENT_USER\Software\Password Safe\Password Safe\"
  const stringT csSubkey = _T("Software\\") + 
    stringT(::AfxGetApp()->m_pszRegistryKey)
    + _T("\\") +
    stringT(::AfxGetApp()->m_pszRegistryKey);

  dwResult = RegOpenKeyEx(HKEY_CURRENT_USER,
                          csSubkey.c_str(),
                          NULL,
                          KEY_ALL_ACCESS,
                          &hSubkey);

  if (dwResult != ERROR_SUCCESS)
    return false; // may have been called due to OldPrefs

  dwResult = RegQueryValueEx(hSubkey, name, NULL, &dwType, NULL, NULL);
  if (dwResult == ERROR_SUCCESS) {
    // Was there - now delete it
    dwResult = RegDeleteValue(hSubkey, name);
    ASSERT(dwResult == ERROR_SUCCESS);
    bRetVal = (dwResult == ERROR_SUCCESS);
  } else
    bRetVal = true;

  dwResult = RegCloseKey(hSubkey);
  ASSERT(dwResult == ERROR_SUCCESS);
  return bRetVal;
}
Exemple #2
0
bool CXMLprefs::RemoveHostnameUsername(const stringT &sHost, const stringT &sUser,
                                       bool &bNoMoreNodes)
{
  // If all OK, after removal of supplied hostname/username, then 
  // bNoMoreNodes indicates if there still remain more nodes (hostname/username)
  // in the configuration file
  bNoMoreNodes = false;

  // Validate parameters
  if (sHost.empty() || sUser.empty())
    return false;

  if (m_pXMLDoc == NULL)
    return false;

  stringT sPath = stringT(_T("Pwsafe_Settings//")) + sHost;
  pugi::xml_node node = m_pXMLDoc->first_element_by_path(sPath.c_str(), _T('\\'));
  
  if (node == NULL)
    return false;
  
  if (!node.remove_child(sUser.c_str()))
    return false;

  // Check if more children
  bNoMoreNodes = node.first_child() == NULL;
  return true;
}
Exemple #3
0
stringT pws_os::getsafedir(void)
{
  stringT sDrive, sDir, sName, sExt, retval;

  pws_os::splitpath(getexecdir(), sDrive, sDir, sName, sExt);
  const stringT sDriveT = sDrive + _T("\\"); // Trailing slash required.

  const UINT uiDT = ::GetDriveType(sDriveT.c_str());
  if (uiDT == DRIVE_REMOVABLE) { 
    stringT::size_type index = sDir.rfind(_T("Program\\"));
    if (index != stringT::npos) {
      sDir.replace(index, 8, stringT(_T("Safes\\")));
      retval = sDrive + sDir;
      if (PathFileExists(retval.c_str()) == TRUE)
        return retval;
    }
  }
  stringT sLocalSafePath;
  if (GetLocalDir(CSIDL_PERSONAL, sLocalSafePath)) {
    retval = sLocalSafePath + _T("\\My Safes");
    if (PathFileExists(retval.c_str()) == FALSE)
      if (_tmkdir(retval.c_str()) != 0)
        retval = _T(""); // couldn't create dir!?
  }
  return retval;
}
XMLFileValidation::XMLFileValidation()
{
  for (int i = 0; i < XLE_ELEMENTS; i++) {
    m_element_map.insert(file_element_pair(stringT(m_file_elements[i].name),
                                           m_file_elements[i].file_element_data));
  }
}
Exemple #5
0
stringT pws_os::getexecdir()
{
  // returns the directory part of ::GetModuleFileName()
  TCHAR acPath[MAX_PATH + 1];

  if (GetModuleFileName(NULL, acPath, MAX_PATH + 1) != 0) {
    // guaranteed file name of at least one character after path '\'
    *(_tcsrchr(acPath, _T('\\')) + 1) = _T('\0');
  } else {
    acPath[0] = TCHAR('\\'); acPath[1] = TCHAR('\0');
  }
  return stringT(acPath);
}
bool pws_os::RegCheckExists(const TCHAR *stree)
{
  if (stree == NULL)
    stree = ::AfxGetApp()->m_pszRegistryKey;

  const stringT csSubkey = _T("Software\\") + stringT(stree);
  HKEY hSubkey;
  bool bExists = ::RegOpenKeyEx(HKEY_CURRENT_USER, csSubkey.c_str(), 0L,
                                KEY_READ, &hSubkey) == ERROR_SUCCESS;
  if (bExists)
    ::RegCloseKey(hSubkey);
  return bExists;
}
Exemple #7
0
void pws_os::Logit(LPCTSTR lpszFormat, ...)
{
  va_list args;
  va_start(args, lpszFormat);

  TCHAR szBuffer[1024];
  int nBuf = _vsntprintf_s(szBuffer, sizeof(szBuffer) / sizeof(TCHAR), _TRUNCATE,
                           lpszFormat, args);
#ifdef DEBUG
  ASSERT(nBuf > 0);
#else
  UNREFERENCED_PARAMETER(nBuf); // In Release build only otherwise MS Compiler warning
#endif
  PWSLog::GetLog()->Add(stringT(szBuffer));
  va_end(args);
}
Exemple #8
0
bool pws_os::RegCheckExists(const TCHAR *stree)
{
  if (stree == NULL) {
    CWinApp *app = ::AfxGetApp();
    if (app == NULL) // can happen in unit test framework
      return false;
    stree = app->m_pszRegistryKey;
  }

  const stringT csSubkey = _T("Software\\") + stringT(stree);
  HKEY hSubkey;
  bool bExists = ::RegOpenKeyEx(HKEY_CURRENT_USER, csSubkey.c_str(), 0L,
                                KEY_READ, &hSubkey) == ERROR_SUCCESS;
  if (bExists)
    ::RegCloseKey(hSubkey);
  return bExists;
}
Exemple #9
0
stringT pws_os::getxmldir(void)
{
  stringT sDrive, sDir, sName, sExt;

  pws_os::splitpath(getexecdir(), sDrive, sDir, sName, sExt);
  const stringT sDriveT = sDrive + _T("\\"); // Trailing slash required.

  const UINT uiDT = ::GetDriveType(sDriveT.c_str());
  if (uiDT == DRIVE_REMOVABLE) { 
    stringT::size_type index = sDir.rfind(_T("Program\\"));
    if (index != stringT::npos) {
      sDir.replace(index, 8, stringT(_T("xml\\")));
      stringT retval = sDrive + sDir;
      if (PathFileExists(retval.c_str()) == TRUE)
        return retval;
    }
  }
  return getexecdir();
}
Exemple #10
0
/*
 * GetStringTFromURLRef
 * 
 * Converts a URLRef (something on the filesystem, as far as this file is concerned) to a
 * wchar_t string without making any assumptions about the encoding of CFURLRef
 *
 */
static stringT GetStringTFromURLRef(CFURLRef url)
{
  stringT retval;
  CFStringRef cfpath = CFURLCopyFileSystemPath(url, kCFURLPOSIXPathStyle);
  if (cfpath) {
    CFIndex numChars = CFStringGetLength(cfpath);
    wchar_t* wPath = new wchar_t[numChars+1]; //any alignment issues?
    CFIndex numBytesWritten = 0;
    assert(sizeof(wchar_t) == 4); //kCFStringEncodingUTF32 hardcoded below
    CFIndex numConverted = CFStringGetBytes(cfpath, CFRangeMake(0, numChars), 
                                            kCFStringEncodingUTF32, 0, false, reinterpret_cast<UInt8 *>(wPath), 
                                            sizeof(wchar_t) * numChars, &numBytesWritten);
    assert(static_cast<CFIndex>(numConverted*sizeof(wchar_t)) == numBytesWritten);
    retval = stringT(wPath, numConverted);
    delete [] wPath;
    CFRelease(cfpath);
  }
  return retval;
}
Exemple #11
0
void pws_os::Logit(LPCTSTR lpszFormat, ...)
{
  va_list args;
  va_start(args, lpszFormat);

  TCHAR *szbuffer = 0;
  int nwritten, len = STARTING_LOG_STATEMENT;
  do {
    len *= 2;
    delete [] szbuffer;
    szbuffer = new TCHAR[len + 1];
    memset(szbuffer, 0, sizeof(TCHAR) * (len + 1));
    nwritten = vstprintf(szbuffer, len, lpszFormat, args);
    //apple's documentation doesn't say if nwritten is +ve, -ve, 0 or if errno is set in case of overflow
  }
  while(!(nwritten > 0 && nwritten < len) && len <= MAX_LOG_STATEMENT);

  PWSLog::GetLog()->Add(stringT(szbuffer));
  delete[] szbuffer;
  va_end(args);
}
// ---------------------------------------------------------------------------
bool XFileXMLProcessor::Process(const bool &bvalidation, const stringT &ImportedPrefix,
                                const stringT &strXMLFileName, const stringT &strXSDFileName,
                                const bool &bImportPSWDsOnly)
{
  USES_XMLCH_STR

  bool bErrorOccurred = false;
  bool b_into_empty = false;
  stringT cs_validation;
  LoadAString(cs_validation, IDSC_XMLVALIDATION);
  stringT cs_import;
  LoadAString(cs_import, IDSC_XMLIMPORT);
  stringT strResultText(_T(""));
  m_bValidation = bvalidation;  // Validate or Import

  XSecMemMgr sec_mm;

  // Initialize the XML4C2 system
  try
  {
    XMLPlatformUtils::Initialize(XMLUni::fgXercescDefaultLocale, 0, 0, &sec_mm);
  }
  catch (const XMLException& toCatch)
  {
    strResultText = stringT(_X2ST(toCatch.getMessage()));
    return false;
  }

  const XMLCh* xmlfilename = _W2X(strXMLFileName.c_str());
  const XMLCh* schemafilename = _W2X(strXSDFileName.c_str());

  //  Create a SAX2 parser object.
  SAX2XMLReader* pSAX2Parser = XMLReaderFactory::createXMLReader(&sec_mm);

  // Set non-default features
  pSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true);
  pSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
  pSAX2Parser->setFeature(XMLUni::fgXercesDynamic, false);
  pSAX2Parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
  pSAX2Parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false);
  pSAX2Parser->setFeature(XMLUni::fgXercesSkipDTDValidation, true);

  // Set properties
  pSAX2Parser->setProperty(XMLUni::fgXercesScannerName,
                           const_cast<void*>(reinterpret_cast<const void*>(XMLUni::fgSGXMLScanner)));
  pSAX2Parser->setInputBufferSize(4096);

  // Set schema file name (also via property)
  pSAX2Parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation,
                           const_cast<void*>(reinterpret_cast<const void*>(schemafilename)));

  // Create SAX handler object and install it on the pSAX2Parser, as the
  // document and error pSAX2Handler.
  XFileSAX2Handlers * pSAX2Handler = new XFileSAX2Handlers;
  pSAX2Parser->setContentHandler(pSAX2Handler);
  pSAX2Parser->setErrorHandler(pSAX2Handler);

  pSAX2Handler->SetVariables(m_bValidation ? NULL : m_pXMLcore, m_bValidation,
                             ImportedPrefix, m_delimiter, bImportPSWDsOnly,
                             m_bValidation ? NULL : m_pPossible_Aliases,
                             m_bValidation ? NULL : m_pPossible_Shortcuts,
                             m_pmulticmds, m_prpt);
  if (!m_bValidation) {
    b_into_empty = m_pXMLcore->GetNumEntries() == 0;
  }

  try {
    // Let's begin the parsing now
    pSAX2Parser->parse(xmlfilename);
  }
  catch (const OutOfMemoryException&) {
    LoadAString(strResultText, IDCS_XERCESOUTOFMEMORY);
    bErrorOccurred = true;
  }
  catch (const XMLException& e) {
    strResultText = stringT(_X2ST(e.getMessage()));
    bErrorOccurred = true;
  }

  catch (...) {
    LoadAString(strResultText, IDCS_XERCESEXCEPTION);
    bErrorOccurred = true;
  }

  if (pSAX2Handler->getIfErrors() || bErrorOccurred) {
    bErrorOccurred = true;
    strResultText = pSAX2Handler->getValidationResult();
    Format(m_strXMLErrors, IDSC_XERCESPARSEERROR,
           m_bValidation ? cs_validation.c_str() : cs_import.c_str(),
           strResultText.c_str());
  } else {
    if (m_bValidation) {
      m_strXMLErrors = pSAX2Handler->getValidationResult();
      m_numEntriesValidated = pSAX2Handler->getNumEntries();
      m_delimiter = pSAX2Handler->getDelimiter();
    } else {
      pSAX2Handler->AddXMLEntries();

      // Get numbers (may have been modified by AddXMLEntries
      m_numEntriesImported = pSAX2Handler->getNumEntries();
      m_numEntriesSkipped = pSAX2Handler->getNumSkipped();
      m_numEntriesRenamed = pSAX2Handler->getNumRenamed();
      m_numEntriesPWHErrors = pSAX2Handler->getNumPWHErrors();
      m_numNoPolicies = pSAX2Handler->getNumNoPolicies();
      m_numRenamedPolicies = pSAX2Handler->getNumRenamedPolicies();
      m_numShortcutsRemoved = pSAX2Handler->getNumShortcutsRemoved();

      // Get lists
      m_strXMLErrors = pSAX2Handler->getXMLErrors();
      m_strSkippedList = pSAX2Handler->getSkippedList();
      m_strPWHErrorList = pSAX2Handler->getPWHErrorList();
      m_strRenameList = pSAX2Handler->getRenameList();


      if (b_into_empty) {
        pSAX2Handler->AddDBPreferences();
      }
    }
  }

  //  Delete the pSAX2Parser itself.  Must be done prior to calling Terminate, below.
  delete pSAX2Parser;
  delete pSAX2Handler;

  USES_XMLCH_STR_END

  // And call the termination method
  XMLPlatformUtils::Terminate();

  return !bErrorOccurred;
}
bool XFilterXMLProcessor::Process(const bool &bvalidation,
                                  const StringX &strXMLData,
                                  const stringT &strXMLFileName,
                                  const stringT &strXSDFileName)
{
  USES_XMLCH_STR
  
  bool bErrorOccurred = false;
  stringT cs_validation;
  LoadAString(cs_validation, IDSC_XMLVALIDATION);
  stringT cs_import;
  LoadAString(cs_import, IDSC_XMLIMPORT);
  stringT strResultText(_T(""));
  m_bValidation = bvalidation;  // Validate or Import

  XSecMemMgr sec_mm;

  // Initialize the XML4C2 system
  try
  {
    XMLPlatformUtils::Initialize(XMLUni::fgXercescDefaultLocale, 0, 0, &sec_mm);
  }
  catch (const XMLException& toCatch)
  {
#ifdef UNICODE
    m_strXMLErrors = stringT(_X2ST(toCatch.getMessage()));
#else
    char *szData = XMLString::transcode(toCatch.getMessage());
    strResultText = stringT(szData);
    XMLString::release(&szData);
#endif
    return false;
  }

  //  Create a SAX2 parser object.
  SAX2XMLReader* pSAX2Parser = XMLReaderFactory::createXMLReader(&sec_mm);

  // Set non-default features
  pSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true);
  pSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
  pSAX2Parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
  pSAX2Parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false);
  pSAX2Parser->setFeature(XMLUni::fgXercesSkipDTDValidation, true);

  // Set properties
  pSAX2Parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation,
                      (void *)strXSDFileName.c_str());
  pSAX2Parser->setProperty(XMLUni::fgXercesScannerName,
                      (void *)XMLUni::fgSGXMLScanner);
  pSAX2Parser->setInputBufferSize(4096);

  // Create SAX handler object and install it on the pSAX2Parser, as the
  // document and error pSAX2Handler.
  XFilterSAX2Handlers * pSAX2Handler = new XFilterSAX2Handlers;
  pSAX2Parser->setContentHandler(pSAX2Handler);
  pSAX2Parser->setErrorHandler(pSAX2Handler);

  // Workaround/bypass until Xerces supports retrieving version from the
  // <xs:schema ...> statement!
  // Set 'dummy' schema version to arbitrary value > 1
  pSAX2Handler->SetSchemaVersion(99);

  pSAX2Handler->SetVariables(m_pAsker, &m_MapFilters, m_FPool, m_bValidation);

  try
  {
    // Let's begin the parsing now
    if (!strXMLFileName.empty()) {
      pSAX2Parser->parse(_W2X(strXMLFileName.c_str()));
    } else {
      const char *szID = "database_filters";
#ifdef UNICODE
      const char *buffer = XMLString::transcode(_W2X(strXMLData.c_str()));
#else
      const char *buffer = strXMLData.c_str();
#endif
      MemBufInputSource* memBufIS = new MemBufInputSource(
                    (const XMLByte*)buffer,
                    strXMLData.length(),
                    szID, false);
      pSAX2Parser->parse(*memBufIS);
      delete memBufIS;
#ifdef UNICODE
      XMLString::release((char **)&buffer);
#endif
    }
  }
  catch (const OutOfMemoryException&)
  {
    LoadAString(strResultText, IDCS_XERCESOUTOFMEMORY);
    bErrorOccurred = true;
  }
  catch (const XMLException& e)
  {
#ifdef UNICODE
    strResultText = stringT(_X2ST(e.getMessage()));
#else
    char *szData = XMLString::transcode(e.getMessage());
    strResultText = stringT(szData);
    XMLString::release(&szData);
#endif
    bErrorOccurred = true;
  }

  catch (...)
  {
    LoadAString(strResultText, IDCS_XERCESEXCEPTION);
    bErrorOccurred = true;
  }

  if (pSAX2Handler->getIfErrors() || bErrorOccurred) {
    bErrorOccurred = true;
    strResultText = pSAX2Handler->getValidationResult();
    Format(m_strXMLErrors, IDSC_XERCESPARSEERROR, 
           m_bValidation ? cs_validation.c_str() : cs_import.c_str(), 
           strResultText.c_str());
  } else {
    m_strXMLErrors = strResultText;
  }

  //  Delete the pSAX2Parser itself.  Must be done prior to calling Terminate, below.
  delete pSAX2Parser;
  delete pSAX2Handler;

  USES_XMLCH_STR_END

  // And call the termination method
  XMLPlatformUtils::Terminate();

  return !bErrorOccurred;
}
Exemple #14
0
const stringT pws_os::RegReadValue(const TCHAR *, const TCHAR *, const TCHAR *value)
{
  return stringT(value);
}
void PasswordSafeSearch::FindMatches(const StringX& searchText, bool fCaseSensitive, SearchPointer& searchPtr,
                                       const CItemData::FieldBits& bsFields, bool fUseSubgroups, const wxString& subgroupText,
                                       CItemData::FieldType subgroupObject, PWSMatch::MatchRule subgroupFunction,
                                       bool subgroupFunctionCaseSensitive, Iter begin, Iter end, Accessor afn)
{
  if (searchText.empty())
      return;

  searchPtr.Clear();

  typedef StringX (CItemData::*ItemDataFuncT)() const;

  struct {
      CItemData::FieldType type;
      ItemDataFuncT        func;
  } ItemDataFields[] = {  {CItemData::GROUP,     &CItemData::GetGroup},
                          {CItemData::TITLE,     &CItemData::GetTitle},
                          {CItemData::USER,      &CItemData::GetUser},
                          {CItemData::PASSWORD,  &CItemData::GetPassword},
//                        {CItemData::NOTES,     &CItemData::GetNotes},
                          {CItemData::URL,       &CItemData::GetURL},
                          {CItemData::EMAIL,     &CItemData::GetEmail},
                          {CItemData::RUNCMD,    &CItemData::GetRunCommand},
                          {CItemData::AUTOTYPE,  &CItemData::GetAutoType},
                          {CItemData::XTIME_INT, &CItemData::GetXTimeInt},

                      };

  for ( Iter itr = begin; itr != end; ++itr) {

    const int fn = (subgroupFunctionCaseSensitive? -subgroupFunction: subgroupFunction);
    if (fUseSubgroups && !afn(itr).Matches(stringT(subgroupText.c_str()), subgroupObject, fn))
        continue;

    bool found = false;
    for (size_t idx = 0; idx < NumberOf(ItemDataFields) && !found; ++idx) {
      if (bsFields.test(ItemDataFields[idx].type)) {
          const StringX str = (afn(itr).*ItemDataFields[idx].func)();
          found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str);
      }
    }

    if (!found && bsFields.test(CItemData::NOTES)) {
        StringX str = afn(itr).GetNotes();
        found = fCaseSensitive? str.find(searchText) != StringX::npos: FindNoCase(searchText, str);
    }

    if (!found && bsFields.test(CItemData::PWHIST)) {
        size_t pwh_max, err_num;
        PWHistList pwhistlist;
        CreatePWHistoryList(afn(itr).GetPWHistory(), pwh_max, err_num,
                            pwhistlist, PWSUtil::TMC_XML);
        for (PWHistList::iterator iter = pwhistlist.begin(); iter != pwhistlist.end(); iter++) {
          PWHistEntry pwshe = *iter;
          found = fCaseSensitive? pwshe.password.find(searchText) != StringX::npos: FindNoCase(searchText, pwshe.password );
          if (found)
            break;  // break out of for loop
        }
        pwhistlist.clear();
    }

    if (found) {
        uuid_array_t uuid;
        afn(itr).GetUUID(uuid);
        searchPtr.Add(pws_os::CUUID(uuid));
    }
  }
}
StringX PWSRun::getruncmd(const StringX &sxFile, bool &bfound) const
{
  // 1. If first parameter is in quotes - assume fully qualified - don't search.
  // 2. If first parameter starts with '%, assume it is going to be replaced by the
  // corresponding environmental variable - no need to search directories.
  // 3. If the first parameter ends in '.xxx', and '.xxx' is in the PATHEXT variable,
  // search for it as-is.  If not, append each of the known extensions to it and then
  // search.
  // 4. If searched and could not find, just issue 'as-is'.

  std::vector<StringX> vpaths;
  std::vector<StringX> vextns;

  StringX full_pgm(sxFile), sx_cwd;
  StringX sx_temp, sx_dirs, sx_extns;

  stringT path, drive, dir, fname, extn;
  stringT s_temp;
  bool bsearch_dirs(true), bsearch_extns(true);

  const StringX::size_type len = full_pgm.length();

  bfound = false;

  if (len == 0)
    return full_pgm;

  // Search order:

  // Current working directory
  s_temp = pws_os::getcwd();
  stringT::size_type Tlen = s_temp.length();
  if (Tlen == 0 || s_temp[Tlen - 1] != _T('\\')) {
    s_temp += _T("\\");
  }
  sx_cwd = StringX(s_temp.c_str());
  vpaths.push_back(sx_cwd);

  // Windows directory
  s_temp = pws_os::getenv("windir", true);
  if (s_temp.length() > 0)
    vpaths.push_back(StringX(s_temp.c_str()));

  // Windows/System32 directory
  if (!s_temp.empty()) {
    s_temp += stringT(_T("System32"));
    vpaths.push_back(StringX(s_temp.c_str()));
  }

  // Directories in PATH
  s_temp = pws_os::getenv("PATH", true);
  sx_temp = s_temp.c_str();
  // tokenize into separate elements using ; as the field separator
  for (StringX::size_type st_startpos = 0;
       st_startpos < sx_temp.size();
       /* st_startpos advanced in body */) {
    StringX::size_type st_next = sx_temp.find(_T(';'), st_startpos);
    if (st_next == StringX::npos)
      st_next = sx_temp.size();
    if (st_next > 0) {
      sx_dirs = sx_temp.substr(st_startpos, st_next - st_startpos);
      vpaths.push_back(sx_dirs);
    }
    st_startpos = st_next + 1; // too complex for for statement
  } // tokenization for loop

  // Apps Paths registry key - see below

  // Get support program extensions
  s_temp = pws_os::getenv("PATHEXT", false);
  sx_temp = s_temp.c_str();
  // tokenize into separate elements using ; as the field separator
  for (StringX::size_type st_startpos = 0;
       st_startpos < sx_temp.size();
       /* st_startpos advanced in body */) {
    StringX::size_type st_next = sx_temp.find(_T(';'), st_startpos);
    if (st_next == StringX::npos)
      st_next = sx_temp.size();
    if (st_next > 0) {
      sx_extns = sx_temp.substr(st_startpos, st_next - st_startpos);
      for(StringX::size_type i = 1; i < sx_extns.size(); i++) {
        sx_extns[i] = _totlower(sx_extns[i]);
      }
      vextns.push_back(sx_extns);
    }
    st_startpos = st_next + 1; // too complex for for statement
  } // tokenization for loop

  // Just need drive, directory and file extension
  path = full_pgm.c_str();
  pws_os::splitpath(path, drive, dir, fname, extn);

  if (!extn.empty()) {
    // ends with '.x-x'
    StringX sx_temp = StringX(extn.c_str());
    for (StringX::size_type i = 1; i < extn.size(); i++) {
      sx_temp[i] = _totlower(sx_temp[i]);
    }
    // Check if a known command extn
    if (std::find(vextns.begin(), vextns.end(), sx_temp) != vextns.end()) {
      bsearch_extns = false;
    }
  }

  if (!drive.empty() || !dir.empty()) {
    // Don't search directories but do search extensions
    bsearch_dirs = false;
    if (drive.empty()) {
      // Drive not specified - so could be relative to current directory
      sx_temp = sx_cwd + full_pgm;
      if (pws_os::FileExists(sx_temp.c_str())) {
        full_pgm = sx_temp;
        bfound = true;
        goto exit;
      }
      // Doesn't exist - add on know program extensions
      for (StringX::size_type ie = 0; ie < vextns.size(); ie++) {
        sx_extns = vextns[ie];
        if (pws_os::FileExists((sx_temp + sx_extns).c_str())) {
          full_pgm = full_pgm + sx_extns;
          bfound = true;
          goto exit;
        }
      }
    } else {
      // Drive specified - so should be full path.
      // Check if file exists as-is
      if (pws_os::FileExists(full_pgm.c_str())) {
        bfound = true;
        goto exit;
      }
      // Doesn't exist - add on know program extensions
      for (StringX::size_type ie = 0; ie < vextns.size(); ie++) {
        sx_extns = vextns[ie];
        if (pws_os::FileExists((full_pgm + sx_extns).c_str())) {
          full_pgm = full_pgm + sx_extns;
          bfound = true;
          goto exit;
        }
      }
    }
  }

  // Now search directories!
  if (bsearch_dirs) {
    // Ensure directory ends in a '/'
    for (StringX::size_type id = 0; id < vpaths.size(); id++) {
      sx_dirs = vpaths[id];
      if (sx_dirs[sx_dirs.length() - 1] != _T('\\'))
        sx_dirs += _T("\\");
      if (bsearch_extns) {
        for (StringX::size_type ie = 0; ie < vextns.size(); ie++) {
          sx_extns = vextns[ie];
          if (pws_os::FileExists((sx_dirs + full_pgm + sx_extns).c_str())) {
            full_pgm = sx_dirs + full_pgm + sx_extns;
            bfound = true;
            goto exit;
          }
        }
      } else {
        if (pws_os::FileExists(stringT((sx_dirs + full_pgm).c_str()))) {
          full_pgm = sx_dirs + full_pgm;
          bfound = true;
          goto exit;
        }
      }
    }
  }

  // If not found directly or within current directory structure, 
  // we so need to search registry.
  // Either: we had to search extensions - 
  //    so full_pgm does not end with known program extn;
  // Or: we didn't have to search -
  //    so full_pgm may end with '.exe' and we must not add
  if (!bfound &&
      (bsearch_extns || (!bsearch_extns && extn == _T(".exe")))) {
    // Check via registry
    if (bsearch_extns)
      full_pgm += _T(".exe");

    // Look for registry key
    bool bexists;
    HKEY hSubkey;
    StringX csSubkey = StringX(_T("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\")) +
      full_pgm;
    bexists = (::RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                              csSubkey.c_str(),
                              0L,
                              KEY_READ,
                              &hSubkey) == ERROR_SUCCESS);
    if (bexists) {
      LONG rv;
      DWORD dwType, dwDataLen(0);
      rv = ::RegQueryValueEx(hSubkey,
                             _T("Path"),
                             NULL,
                             &dwType,
                             NULL,
                             &dwDataLen);
      if (rv == ERROR_SUCCESS && dwType == REG_SZ) {
        dwDataLen++;
        TCHAR *pData = new TCHAR[dwDataLen];
        ::memset(pData, 0, dwDataLen);
        rv = ::RegQueryValueEx(hSubkey,
                               _T("Path"),
                               NULL,
                               &dwType,
                               LPBYTE(pData),
                               &dwDataLen);

        if (rv == ERROR_SUCCESS) {
          sx_temp = pData;
          StringX::size_type len = sx_temp.length();
          if (sx_temp[len - 1] == _T(';'))
            sx_temp = sx_temp.substr(0, len - 1) + _T('\\');
          else
            if (sx_temp[len - 1] != _T('\\') && sx_temp[len - 1] != _T('/'))
              sx_temp = sx_temp + _T('\\');
          full_pgm =  sx_temp + full_pgm;
          bfound = true;
        }

        delete[] pData;
      } // Get the value
      ::RegCloseKey(hSubkey);
    }
  }

 exit:
  return full_pgm;
}
bool XFilterXMLProcessor::Process(const bool &bvalidation,
                                  const StringX &strXMLData,
                                  const stringT &strXMLFileName,
                                  const stringT &strXSDFileName)
{
  USES_XMLCH_STR

  bool bErrorOccurred = false;
  stringT cs_validation;
  LoadAString(cs_validation, IDSC_XMLVALIDATION);
  stringT cs_import;
  LoadAString(cs_import, IDSC_XMLIMPORT);
  stringT strResultText(_T(""));
  m_bValidation = bvalidation;  // Validate or Import

  XSecMemMgr sec_mm;

  // Initialize the XML4C2 system
  try
  {
    XMLPlatformUtils::Initialize(XMLUni::fgXercescDefaultLocale, 0, 0, &sec_mm);
  }
  catch (const XMLException& toCatch)
  {
    m_strXMLErrors = stringT(_X2ST(toCatch.getMessage()));
    return false;
  }

  //  Create a SAX2 parser object.
  SAX2XMLReader* pSAX2Parser = XMLReaderFactory::createXMLReader(&sec_mm);

  // Set non-default features
  pSAX2Parser->setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true);
  pSAX2Parser->setFeature(XMLUni::fgSAX2CoreValidation, true);
  pSAX2Parser->setFeature(XMLUni::fgXercesSchemaFullChecking, true);
  pSAX2Parser->setFeature(XMLUni::fgXercesLoadExternalDTD, false);
  pSAX2Parser->setFeature(XMLUni::fgXercesSkipDTDValidation, true);

  // Set properties
  // we need const_cast here, because _W2X return const wchar_t* when
  // WCHAR_INCOMPATIBLE_XMLCH isn't set
  pSAX2Parser->setProperty(XMLUni::fgXercesSchemaExternalNoNameSpaceSchemaLocation,
                      const_cast<XMLCh*>(_W2X(strXSDFileName.c_str())));
  pSAX2Parser->setProperty(XMLUni::fgXercesScannerName,
                      const_cast<XMLCh*>(XMLUni::fgSGXMLScanner));
  pSAX2Parser->setInputBufferSize(4096);

  // Create SAX handler object and install it on the pSAX2Parser, as the
  // document and error pSAX2Handler.
  XFilterSAX2Handlers * pSAX2Handler = new XFilterSAX2Handlers;
  pSAX2Parser->setContentHandler(pSAX2Handler);
  pSAX2Parser->setErrorHandler(pSAX2Handler);

  // Workaround/bypass until Xerces supports retrieving version from the
  // <xs:schema ...> statement!
  // Set 'dummy' schema version to arbitrary value > 1
  pSAX2Handler->SetSchemaVersion(99);

  pSAX2Handler->SetVariables(m_pAsker, &m_MapFilters, m_FPool, m_bValidation);

  // instantiate converter out of if/else to be sure that string will be valid
  // till the end of pSAX2Parser, that may capture pointer to string from MemBufInputSource
  CUTF8Conv conv;
  try
  {
    // Let's begin the parsing now
    if (!strXMLFileName.empty()) {
      pSAX2Parser->parse(_W2X(strXMLFileName.c_str()));
    } else {
      const char *szID = "database_filters";
      // Xerces use encoding from XML (we have set it to utf-8), but transcode() on Windows convert to one-byte cpXXXX,
      // so we need to manually convert from wchar to UTF-8
      const unsigned char* buffer=nullptr;
      size_t len;
      if (!conv.ToUTF8(strXMLData, buffer, len)) {
        throw std::runtime_error("Can't convert data to UTF-8");
      }
      //2nd parameter must be number of bytes, so we use a length for char* representation
      MemBufInputSource* memBufIS = new MemBufInputSource(
                    reinterpret_cast<const XMLByte *>(buffer),
                    strlen(reinterpret_cast<const char*>(buffer)),
                    szID, false);
      pSAX2Parser->parse(*memBufIS);
      delete memBufIS;
    }
  }
  catch (const OutOfMemoryException&)
  {
    LoadAString(strResultText, IDCS_XERCESOUTOFMEMORY);
    bErrorOccurred = true;
  }
  catch (const XMLException& e)
  {
    strResultText = stringT(_X2ST(e.getMessage()));
    bErrorOccurred = true;
  }

  catch (...)
  {
    LoadAString(strResultText, IDCS_XERCESEXCEPTION);
    bErrorOccurred = true;
  }

  if (pSAX2Handler->getIfErrors() || bErrorOccurred) {
    bErrorOccurred = true;
    if (pSAX2Handler->getIfErrors())
      strResultText = pSAX2Handler->getValidationResult();
    Format(m_strXMLErrors, IDSC_XERCESPARSEERROR,
           m_bValidation ? cs_validation.c_str() : cs_import.c_str(),
           strResultText.c_str());
  } else {
    m_strXMLErrors = strResultText;
  }

  //  Delete the pSAX2Parser itself.  Must be done prior to calling Terminate, below.
  delete pSAX2Parser;
  delete pSAX2Handler;

  USES_XMLCH_STR_END

  // And call the termination method
  XMLPlatformUtils::Terminate();

  return !bErrorOccurred;
}