diff --git a/ZRColaCompile/dbsource.cpp b/ZRColaCompile/dbsource.cpp index 5b9832b..f209d6b 100644 --- a/ZRColaCompile/dbsource.cpp +++ b/ZRColaCompile/dbsource.cpp @@ -304,7 +304,7 @@ bool ZRCola::DBSource::Open(LPCTSTR filename) wxVERIFY(SUCCEEDED(::CoCreateInstance(CLSID_CADOCommand, NULL, CLSCTX_ALL, IID_IADOCommand, (LPVOID*)&m_comTranslation))); wxVERIFY(SUCCEEDED(m_comTranslation->put_ActiveConnection(variant(m_db)))); wxVERIFY(SUCCEEDED(m_comTranslation->put_CommandType(adCmdText))); - wxVERIFY(SUCCEEDED(m_comTranslation->put_CommandText(bstr(L"SELECT [Komb1] AS [komb], [rang_komb1] AS [rang_komb], [Komb2] AS [znak], [rang_komb2] AS [rang_znak] " + wxVERIFY(SUCCEEDED(m_comTranslation->put_CommandText(bstr(L"SELECT [Komb1] AS [komb], [rang_komb1] AS [rang_komb], '' AS [Kano], 0 AS [Kanoniziraj], [Komb2] AS [znak], [rang_komb2] AS [rang_znak] " L"FROM [VRS_ScriptRepl] " L"WHERE [Script]=? " L"ORDER BY [Komb2], [rang_komb2], [rang_komb1], [Komb1]")))); @@ -391,6 +391,23 @@ bool ZRCola::DBSource::GetValue(const com_obj& f, int& val) const } +bool ZRCola::DBSource::GetValue(const com_obj& f, string& val) const +{ + wxASSERT_MSG(f, wxT("field is empty")); + + variant v; + wxVERIFY(SUCCEEDED(f->get_Value(&v))); + if (V_VT(&v) != VT_NULL) { + wxCHECK(SUCCEEDED(v.change_type(VT_BSTR)), false); + + WideCharToMultiByte(CP_ACP, 0, V_BSTR(&v), ::SysStringLen(V_BSTR(&v)), val, NULL, NULL); + } else + val.clear(); + + return true; +} + + bool ZRCola::DBSource::GetValue(const com_obj& f, wstring& val) const { wxASSERT_MSG(f, wxT("field is empty")); @@ -480,6 +497,42 @@ bool ZRCola::DBSource::GetUnicodeString(const com_obj& f, wstring& str } +bool ZRCola::DBSource::GetNormPerm(const winstd::com_obj& f, normperm& np) const +{ + wxASSERT_MSG(f, wxT("field is empty")); + + variant v; + wxVERIFY(SUCCEEDED(f->get_Value(&v))); + np.clear(); + if (V_VT(&v) != VT_NULL) { + wxCHECK(SUCCEEDED(v.change_type(VT_BSTR)), false); + + // Parse the field. Must be "nnnn,nnnn,nnnn..." sequence. + for (UINT i = 0, n = ::SysStringLen(V_BSTR(&v)); i < n && V_BSTR(&v)[i];) { + // Parse Unicode code. + UINT j = 0; + std::vector p; + for (; i < n && V_BSTR(&v)[i]; i++, j++) { + if (L'0' <= V_BSTR(&v)[i] && V_BSTR(&v)[i] <= L'9') p.push_back(V_BSTR(&v)[i] - L'0'); + else break; + } + if (j <= 0) { + bstr fieldname; wxVERIFY(SUCCEEDED(f->get_Name(&fieldname))); + _ftprintf(stderr, wxT("%s: error ZCC0150: Syntax error in \"%.*ls\" field (\"%.*ls\"). Permutation sequence must be at least one decimal digit long.\n"), m_filename.c_str(), fieldname.length(), (BSTR)fieldname, n, V_BSTR(&v)); + return false; + } + np.insert(std::move(p)); + + // Skip delimiter(s) and whitespace. + for (; i < n && V_BSTR(&v)[i] && (V_BSTR(&v)[i] == L',' || _iswspace_l(V_BSTR(&v)[i], m_locale)); i++); + } + } + + return true; +} + + + bool ZRCola::DBSource::GetLanguage(const com_obj& f, ZRCola::langid_t& lang) const { wxASSERT_MSG(f, wxT("field is empty")); @@ -600,6 +653,59 @@ bool ZRCola::DBSource::GetTagNames(const winstd::com_obj& f, LCID lcid } +bool ZRCola::DBSource::SelectNormPermSets(winstd::com_obj& rs) const +{ + // Create a new recordset. + rs.free(); + wxCHECK(SUCCEEDED(::CoCreateInstance(CLSID_CADORecordset, NULL, CLSCTX_ALL, IID_IADORecordset, (LPVOID*)&rs)), false); + + // Open it. + if (FAILED(rs->Open(variant( + L"SELECT [oblika], [oblike] " + L"FROM [VRS_CharCanoOblike] " + L"ORDER BY [oblika], [oblike]"), variant(m_db), adOpenStatic, adLockReadOnly, adCmdText))) + { + _ftprintf(stderr, wxT("%s: error ZCC0160: Error loading normalization permutation sets from database. Please make sure the file is ZRCola.zrc compatible.\n"), m_filename.c_str()); + LogErrors(); + return false; + } + + return true; +} + + +bool ZRCola::DBSource::GetNormPerm(const winstd::com_obj& rs, std::string& norm, normperm& np) const +{ + wxASSERT_MSG(rs, wxT("recordset is empty")); + + com_obj flds; + wxVERIFY(SUCCEEDED(rs->get_Fields(&flds))); + + { + com_obj f; + wxVERIFY(SUCCEEDED(flds->get_Item(variant(L"oblika"), &f))); + wxCHECK(GetValue(f, norm), false); + } + + { + com_obj f; + wxVERIFY(SUCCEEDED(flds->get_Item(variant(L"oblike"), &f))); + wxCHECK(GetNormPerm(f, np), false); + } + + // Verify all lengths match. + size_t n = norm.length(); + for (auto p = np.cbegin(), p_end = np.cend(); p != p_end; ++p) { + if (p->size() != n) { + _ftprintf(stderr, wxT("%s: error ZCC0170: Inconsistent normalization sequence \"%.*s\" permutation length. Please make sure all permutation lengths match normalization sequence length (%u).\n"), m_filename.c_str(), n, norm.c_str(), n); + return false; + } + } + + return true; +} + + bool ZRCola::DBSource::SelectTranslations(com_obj &rs) const { // Create a new recordset. @@ -608,7 +714,7 @@ bool ZRCola::DBSource::SelectTranslations(com_obj &rs) const // Open it. if (FAILED(rs->Open(variant( - L"SELECT [komb], [rang_komb], [znak], [rang_znak] " + L"SELECT [komb], [rang_komb], [Kano], [Kanoniziraj], [znak], [rang_znak] " L"FROM [VRS_ReplChar] " L"WHERE [rang_komb]=1 " L"ORDER BY [znak], [rang_znak], [rang_komb], [komb]"), variant(m_db), adOpenStatic, adLockReadOnly, adCmdText))) @@ -662,6 +768,19 @@ bool ZRCola::DBSource::GetTranslation(const com_obj& rs, ZRCola::D wxCHECK(GetValue(f, t.src.rank), false); } + { + bool norm; + com_obj f; + wxVERIFY(SUCCEEDED(flds->get_Item(variant(L"Kanoniziraj"), &f))); + wxCHECK(GetValue(f, norm), false); + if (norm) { + com_obj f; + wxVERIFY(SUCCEEDED(flds->get_Item(variant(L"Kano"), &f))); + wxCHECK(GetValue(f, t.norm), false); + } else + t.norm.clear(); + } + { com_obj f; wxVERIFY(SUCCEEDED(flds->get_Item(variant(L"rang_znak"), &f))); diff --git a/ZRColaCompile/dbsource.h b/ZRColaCompile/dbsource.h index 9d8afc9..15efcd1 100644 --- a/ZRColaCompile/dbsource.h +++ b/ZRColaCompile/dbsource.h @@ -119,9 +119,10 @@ namespace ZRCola { /// class translation { public: - int set; ///< Translation set ID - charseq src; ///< Source sequence - charseq dst; ///< Destination sequence + int set; ///< Translation set ID + charseq src; ///< Source sequence + std::string norm; ///< Normalization footprint + charseq dst; ///< Destination sequence }; @@ -136,6 +137,12 @@ namespace ZRCola { }; + /// + /// Normalization permutation set + /// + typedef std::set > normperm; + + /// /// Key sequence /// @@ -454,6 +461,18 @@ namespace ZRCola { /// bool GetValue(const winstd::com_obj& f, int& val) const; + /// + /// Gets string from ZRCola.zrc database + /// + /// \param[in] f Data field + /// \param[out] val Output string value + /// + /// \returns + /// - true when successful + /// - false otherwise + /// + bool GetValue(const winstd::com_obj& f, std::string& val) const; + /// /// Gets string from ZRCola.zrc database /// @@ -490,6 +509,18 @@ namespace ZRCola { /// bool GetUnicodeString(const winstd::com_obj& f, std::wstring& str) const; + /// + /// Gets encoded normalization permutations from ZRCola.zrc database + /// + /// \param[in] f Data field + /// \param[out] str Output normalization permutation set + /// + /// \returns + /// - true when successful + /// - false otherwise + /// + bool GetNormPerm(const winstd::com_obj& f, normperm& np) const; + /// /// Gets language ID from ZRCola.zrc database /// @@ -526,6 +557,29 @@ namespace ZRCola { /// bool GetTagNames(const winstd::com_obj& f, LCID lcid, std::list& names) const; + /// + /// Returns normalization permutation sets + /// + /// \param[out] rs Recordset with results + /// + /// \returns + /// - true when query succeeds + /// - false otherwise + /// + bool SelectNormPermSets(winstd::com_obj& rs) const; + + /// + /// Returns normalization permutation set + /// + /// \param[in] rs Recordset with results + /// \param[out] np Normalization permutation set + /// + /// \returns + /// - true when succeeded + /// - false otherwise + /// + bool GetNormPerm(const winstd::com_obj& rs, std::string& norm, normperm& np) const; + /// /// Returns character translations ///