/* * This file is a part of Winix * and is distributed under the 2-Clause BSD licence. * Author: Tomasz Sowa */ /* * Copyright (c) 2010-2021, Tomasz Sowa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ #include #include "locale.h" #include "core/log.h" #include "core/misc.h" #include "utf8/utf8.h" namespace Winix { Locale::Locale() { default_lang = 0; current_lang = 0; } void Locale::SetLocaleFiles(const std::vector & files) { locale_files = files; } void Locale::SetLocaleMaxId(size_t max_id) { if( max_id > 1000 ) { max_id = 1000; log << log1 << "Locale: locale_max_id is too big (changed to 1000)" << logend; } size_t old_size = locale_indices.size(); locale_indices.resize(max_id + 1); for(size_t i=old_size ; i= locale_indices.size() ) { log << log1 << "Locale: locale identifier is greater than locale_max_id (skipping)" << logend; return; } locale_tab.push_back(temp_space); locale_indices[id] = locale_tab.size() - 1; } void Locale::ReadSubstTable(const char * dir, const char * dir_def) { bool read = false; temp_space.clear(); subst_url.clear(); subst_smalllet.clear(); subst_capitallet.clear(); subst_sort.clear(); if( dir_def && ReadSubstTable(dir_def) ) read = true; if( dir && ReadSubstTable(dir) ) read = true; if( !read ) log << log1 << "Locale: can't open file for characters substitution" << logend; } bool Locale::ReadSubstTable(const char * dir) { bool read = false; file_name = dir; file_name += '/'; file_name += "substitute"; loc_parser.SetSpace(temp_space); if( loc_parser.ParseSpaceFile(file_name) == pt::SpaceParser::ok ) { read = true; CreateSubstVector(subst_url, temp_space.to_wstr(L"url_original"), temp_space.to_wstr(L"url_changeto")); CreateSubstVector(subst_smalllet, temp_space.to_wstr(L"smallleters"), temp_space.to_wstr(L"capitalics")); CreateSubstVector(subst_capitallet, temp_space.to_wstr(L"capitalics"), temp_space.to_wstr(L"smallleters")); std::vector sort_vec; if( temp_space.to_list(L"sort", sort_vec) ) CreateSubstSortVector(subst_sort, sort_vec); log << log3 << "Locale: read characters substitution tables from: " << file_name << logend; } return read; } void Locale::CreateSubstVector(std::vector & vect, const std::wstring & tab1, const std::wstring & tab2) { size_t i, min_size = (tab1.size() < tab2.size()) ? tab1.size() : tab2.size(); SubstItem s; vect.clear(); if( min_size == 0 ) return; vect.reserve(min_size); for(i=0 ; i & vect, std::vector & tab) { SubstItem s; vect.clear(); if( tab.empty() ) return; vect.reserve(tab.size()); for(size_t i=0 ; i= 3 ) { s.from = tab[i][0]; s.to = tab[i][1]; s.index = Toi(&tab[i][2]); vect.push_back(s); } } std::sort(vect.begin(), vect.end()); } void Locale::Read(const char * dir, const char * dir_def) { locale_tab.clear(); for(size_t i=0 ; i & list, bool try_default_too) { key_str = key; return GetList(key_str, list, try_default_too); } bool Locale::GetList(const std::wstring & key, std::vector & list, bool try_default_too) const { return GetList(key, current_lang, list, try_default_too); } bool Locale::GetList(const wchar_t * key, size_t lang_id, std::vector & list, bool try_default_too) { key_str = key; return GetList(key_str, lang_id, list, try_default_too); } bool Locale::GetListInLanguage(const std::wstring & key, size_t lang_id, std::vector & list) const { if( lang_id < locale_indices.size() ) { size_t index = locale_indices[lang_id]; if( index < locale_tab.size() ) { return locale_tab[index].to_list(key, list); } } return false; } bool Locale::GetList(const std::wstring & key, size_t lang_id, std::vector & list, bool try_default_too) const { if( GetListInLanguage(key, lang_id, list) ) return true; if( !try_default_too || lang_id == default_lang ) return false; if( GetListInLanguage(key, default_lang, list) ) return true; return false; } size_t Locale::IdToIndex(size_t lang_id) { if( lang_id < locale_indices.size() ) return locale_indices[lang_id]; // here can be size(-1) as well return size_t(-1); } size_t Locale::Size() const { return locale_tab.size(); } bool Locale::IsKeyByIndex(const wchar_t * key, size_t index, bool try_default_too) { key_str = key; return IsKeyByIndex(key_str, index, try_default_too); } bool Locale::IsKeyByIndex(const std::wstring & key, size_t index, bool try_default_too) const { if( index < locale_tab.size() ) { if( locale_tab[index].get_object_field(key) != 0 ) return true; } if( try_default_too ) { if( GetKeyInLanguage(key, default_lang) != 0 ) return true; } return false; } const std::wstring & Locale::GetByIndex(const wchar_t * key, size_t index, bool try_default_too) { key_str = key; return GetByIndex(key_str, index, try_default_too); } const std::wstring & Locale::GetByIndex(const std::wstring & key, size_t index, bool try_default_too) const { if( index < locale_tab.size() ) { const std::wstring * value = locale_tab[index].get_wstr(key.c_str()); if( value ) return *value; } if( try_default_too ) { const std::wstring * value = GetKeyInLanguage(key, default_lang); if( value ) return *value; } return empty; } bool Locale::IsListByIndex(const wchar_t * key, size_t index, bool try_default_too) { key_str = key; return IsListByIndex(key_str, index, try_default_too); } bool Locale::IsListByIndex(const std::wstring & key, size_t index, bool try_default_too) const { if( index < locale_tab.size() ) { if( locale_tab[index].has_key(key) ) return true; } if( try_default_too ) return IsListInLanguage(key, default_lang); return false; } bool Locale::IsListInLanguage(const std::wstring & key, size_t lang_id) const { if( lang_id < locale_indices.size() ) { size_t index = locale_indices[lang_id]; if( index < locale_tab.size() ) { if( locale_tab[index].has_key(key) ) return true; } } return false; } bool Locale::GetListByIndex(const wchar_t * key, size_t index, std::vector & list, bool try_default_too) { key_str = key; return GetListByIndex(key_str, index, list, try_default_too); } bool Locale::GetListByIndex(const std::wstring & key, size_t index, std::vector & list, bool try_default_too) const { if( index < locale_tab.size() ) { return locale_tab[index].to_list(key, list); } if( try_default_too ) { return GetListInLanguage(key, default_lang, list); } return false; } /* binary search in vect vect should be sorted by 'from' if the 'val' is found in vect[].from then its index is returned (index to vect table) else vect.size() is returned */ size_t Locale::SubstFindIndex(const std::vector & vect, wchar_t val) { if( vect.empty() ) return vect.size(); size_t o1 = 0; size_t o2 = vect.size() - 1; if( val < vect[o1].from ) return vect.size(); if( val == vect[o1].from ) return o1; if( val > vect[o2].from ) return vect.size(); if( val == vect[o2].from ) return o2; while( o1 + 1 < o2 ) { size_t o = (o1 + o2) / 2; if( val == vect[o].from ) return o; if( val < vect[o].from ) o2 = o; else o1 = o; } return vect.size(); } /* binary search in vect vect should be sorted by 'from' if the 'val' is found in vect[].from then vect[].to is returned else 'val' is returned */ wchar_t Locale::SubstFind(const std::vector & vect, wchar_t val) { size_t i = SubstFindIndex(vect, val); if( i == vect.size() ) { return val; } else { return vect[i].to; } } wchar_t Locale::UrlSubst(wchar_t c) { return SubstFind(subst_url, c); } void Locale::UrlSubst(std::wstring & str) { for(size_t i=0 ; i='A' && c<='Z' ) return c - 'A' + 'a'; return SubstFind(subst_capitallet, c); } void Locale::ToSmall(std::wstring & str) { for(size_t i=0 ; i='a' && c<='z' ) return c - 'a' + 'A'; return SubstFind(subst_smalllet, c); } void Locale::ToCapital(std::wstring & str) { for(size_t i=0 ; i='a' && c1<='z') || (c1>='A' && c1<='Z')) ) { size_t i1 = SubstFindIndex(subst_sort, c1); if( i1 < subst_sort.size() ) { s1.to = subst_sort[i1].to; s1.index = subst_sort[i1].index; } } if( !((c2>='a' && c2<='z') || (c2>='A' && c2<='Z')) ) { size_t i2 = SubstFindIndex(subst_sort, c2); if( i2 < subst_sort.size() ) { s2.to = subst_sort[i2].to; s2.index = subst_sort[i2].index; } } wchar_t small1 = ToSmall(s1.to); wchar_t small2 = ToSmall(s2.to); if( small1 == small2 ) { if( s1.index != s2.index ) return s1.index - s2.index; // this will sort capital letters at the end (after small ones) return s1.to - s2.to; } return small1 - small2; } /* comparing lexicographically two strings return value: less than 0 if str1 is 'less' than str2 zero if they are equal greater than 0 if str1 is 'greater' than str2 */ int Locale::Compare(const std::wstring & str1, const std::wstring & str2) { size_t i1 = 0; size_t i2 = 0; for( ; i1 < str1.size() && i2 < str2.size() ; ++i1, ++i2) { int res = Compare(str1[i1], str2[i2]); if( res != 0 ) return res; } if( str1.size() < str2.size() ) return -1; if( str1.size() > str2.size() ) return 1; return 0; } } // namespace Winix