aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/restricted/boost/locale/src/win32/lcid.cpp
blob: e1b998d66b3819b370d93d112616229b05e53112 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
//
// Copyright (c) 2009-2011 Artyom Beilis (Tonkikh)
//
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#ifndef NOMINMAX
#    define NOMINMAX
#endif

#include "lcid.hpp"
#include <boost/locale/util/locale_data.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/mutex.hpp>
#include <map>
#include <sstream>
#include <string.h>
#include <string>
#include <windows.h>

namespace boost { namespace locale { namespace impl_win {

    typedef std::map<std::string, unsigned> table_type;

    static table_type* volatile table = 0;

    boost::mutex& lcid_table_mutex()
    {
        static boost::mutex m;
        return m;
    }

    table_type& real_lcid_table()
    {
        static table_type real_table;
        return real_table;
    }

    BOOL CALLBACK proc(char* s)
    {
        table_type& tbl = real_lcid_table();
        try {
            std::istringstream ss;
            ss.str(s);
            ss >> std::hex;

            unsigned lcid;
            ss >> lcid;
            if(ss.fail() || !ss.eof())
                return FALSE;

            char iso_639_lang[16];
            char iso_3166_country[16];
            if(GetLocaleInfoA(lcid, LOCALE_SISO639LANGNAME, iso_639_lang, sizeof(iso_639_lang)) == 0)
                return FALSE;
            std::string lc_name = iso_639_lang;
            if(GetLocaleInfoA(lcid, LOCALE_SISO3166CTRYNAME, iso_3166_country, sizeof(iso_3166_country)) != 0) {
                lc_name += "_";
                lc_name += iso_3166_country;
            }
            const auto p = tbl.find(lc_name);
            if(p != tbl.end()) {
                if(p->second > lcid)
                    p->second = lcid;
            } else
                tbl[lc_name] = lcid;
        } catch(...) {
            tbl.clear();
            return FALSE;
        }
        return TRUE;
    }

    const table_type& get_ready_lcid_table()
    {
        if(table)
            return *table;
        else {
            boost::unique_lock<boost::mutex> lock(lcid_table_mutex());
            if(table)
                return *table;
            EnumSystemLocalesA(proc, LCID_INSTALLED);
            table = &real_lcid_table();
            return *table;
        }
    }

    unsigned locale_to_lcid(const std::string& locale_name)
    {
        if(locale_name.empty())
            return LOCALE_USER_DEFAULT;
        boost::locale::util::locale_data d;
        d.parse(locale_name);
        std::string id = d.language();

        if(!d.country().empty())
            id += "_" + d.country();
        if(!d.variant().empty())
            id += "@" + d.variant();

        const table_type& tbl = get_ready_lcid_table();
        const auto p = tbl.find(id);
        return (p != tbl.end()) ? p->second : 0;
    }

}}} // namespace boost::locale::impl_win