pico_phone 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +21 -0
- data/THIRD_PARTY_LICENSES.txt +353 -0
- data/ext/pico_phone/carrier_data.cc +68763 -0
- data/ext/pico_phone/carrier_mapper.cc +127 -0
- data/ext/pico_phone/carrier_mapper.h +88 -0
- data/ext/pico_phone/extconf.rb +8 -0
- data/ext/pico_phone/pico_phone.cpp +51 -1
- data/ext/pico_phone/timezone_data.cc +6648 -0
- data/ext/pico_phone/timezone_data.h +25 -0
- data/ext/pico_phone/timezone_mapper.cc +54 -0
- data/ext/pico_phone/timezone_mapper.h +49 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/area_code_map.h +92 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/carrier_data.h +52 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/geocoding_data.h +93 -0
- data/ext/pico_phone/vendor_headers/phonenumbers/geocoding/mapping_file_provider.h +89 -0
- data/lib/pico_phone/phone_number.rb +19 -0
- data/lib/pico_phone/version.rb +1 -1
- metadata +15 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// First-party pico_phone file. See carrier_mapper.h.
|
|
2
|
+
|
|
3
|
+
#include "carrier_mapper.h"
|
|
4
|
+
|
|
5
|
+
#include <algorithm>
|
|
6
|
+
#include <cstring>
|
|
7
|
+
#include <string>
|
|
8
|
+
|
|
9
|
+
#include "phonenumbers/geocoding/area_code_map.h"
|
|
10
|
+
#include "phonenumbers/geocoding/carrier_data.h"
|
|
11
|
+
#include "phonenumbers/geocoding/mapping_file_provider.h"
|
|
12
|
+
#include "phonenumbers/phonenumber.pb.h"
|
|
13
|
+
|
|
14
|
+
#include "absl/synchronization/mutex.h"
|
|
15
|
+
|
|
16
|
+
namespace i18n {
|
|
17
|
+
namespace phonenumbers {
|
|
18
|
+
|
|
19
|
+
using std::string;
|
|
20
|
+
|
|
21
|
+
namespace {
|
|
22
|
+
|
|
23
|
+
// Returns true if s1 comes strictly before s2 in lexicographic order.
|
|
24
|
+
bool IsLowerThan(const char* s1, const char* s2) {
|
|
25
|
+
return strcmp(s1, s2) < 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
} // namespace
|
|
29
|
+
|
|
30
|
+
PhoneNumberCarrierMapper::PhoneNumberCarrierMapper() {
|
|
31
|
+
provider_.reset(new MappingFileProvider(get_carrier_country_calling_codes(),
|
|
32
|
+
get_carrier_country_calling_codes_size(),
|
|
33
|
+
get_carrier_country_languages));
|
|
34
|
+
prefix_language_code_pairs_ = get_carrier_prefix_language_code_pairs();
|
|
35
|
+
prefix_language_code_pairs_size_ = get_carrier_prefix_language_code_pairs_size();
|
|
36
|
+
get_prefix_descriptions_ = get_carrier_prefix_descriptions;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
PhoneNumberCarrierMapper::~PhoneNumberCarrierMapper() {
|
|
40
|
+
// Pointer-taking constructor, not the reference-taking one: this file
|
|
41
|
+
// compiles against two different Abseil versions depending on build path
|
|
42
|
+
// (vendored 20260526.0 for the static/native build, whatever Debian/Ubuntu
|
|
43
|
+
// packages for the dynamic/apt-linked build), and only the older
|
|
44
|
+
// pointer-taking overload exists in both. The vendored geocoder itself hit
|
|
45
|
+
// the same tension in the other direction (see build_deps.sh's
|
|
46
|
+
// absl::MutexLock patch) -- there it's a -Werror'd deprecation inside
|
|
47
|
+
// libphonenumber's own CMake build; here it's just a harmless warning
|
|
48
|
+
// since pico_phone's own extension build doesn't set -Werror.
|
|
49
|
+
absl::MutexLock l(&mu_);
|
|
50
|
+
for (AreaCodeMaps::const_iterator it = available_maps_.begin();
|
|
51
|
+
it != available_maps_.end(); ++it) {
|
|
52
|
+
delete it->second;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const AreaCodeMap* PhoneNumberCarrierMapper::GetPhonePrefixDescriptions(
|
|
57
|
+
int prefix, const string& language, const string& script,
|
|
58
|
+
const string& region) const {
|
|
59
|
+
string filename;
|
|
60
|
+
provider_->GetFileName(prefix, language, script, region, &filename);
|
|
61
|
+
if (filename.empty()) {
|
|
62
|
+
return NULL;
|
|
63
|
+
}
|
|
64
|
+
AreaCodeMaps::const_iterator it = available_maps_.find(filename);
|
|
65
|
+
if (it == available_maps_.end()) {
|
|
66
|
+
return LoadAreaCodeMapFromFile(filename);
|
|
67
|
+
}
|
|
68
|
+
return it->second;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const AreaCodeMap* PhoneNumberCarrierMapper::LoadAreaCodeMapFromFile(
|
|
72
|
+
const string& filename) const {
|
|
73
|
+
const char** const prefix_language_code_pairs_end =
|
|
74
|
+
prefix_language_code_pairs_ + prefix_language_code_pairs_size_;
|
|
75
|
+
const char** const prefix_language_code_pair =
|
|
76
|
+
std::lower_bound(prefix_language_code_pairs_,
|
|
77
|
+
prefix_language_code_pairs_end,
|
|
78
|
+
filename.c_str(), IsLowerThan);
|
|
79
|
+
if (prefix_language_code_pair != prefix_language_code_pairs_end &&
|
|
80
|
+
filename.compare(*prefix_language_code_pair) == 0) {
|
|
81
|
+
AreaCodeMap* const m = new AreaCodeMap();
|
|
82
|
+
m->ReadAreaCodeMap(get_prefix_descriptions_(
|
|
83
|
+
prefix_language_code_pair - prefix_language_code_pairs_));
|
|
84
|
+
return available_maps_.insert(AreaCodeMaps::value_type(filename, m))
|
|
85
|
+
.first->second;
|
|
86
|
+
}
|
|
87
|
+
return NULL;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const char* PhoneNumberCarrierMapper::GetAreaDescription(
|
|
91
|
+
const PhoneNumber& number, const string& lang, const string& script,
|
|
92
|
+
const string& region) const {
|
|
93
|
+
const int country_calling_code = number.country_code();
|
|
94
|
+
// NANPA area is not split in C++ code (matches PhoneNumberOfflineGeocoder).
|
|
95
|
+
const int phone_prefix = country_calling_code;
|
|
96
|
+
absl::MutexLock l(&mu_);
|
|
97
|
+
const AreaCodeMap* const descriptions = GetPhonePrefixDescriptions(
|
|
98
|
+
phone_prefix, lang, script, region);
|
|
99
|
+
const char* description = descriptions ? descriptions->Lookup(number) : NULL;
|
|
100
|
+
// When a carrier name is not available in the requested language, fall
|
|
101
|
+
// back to English.
|
|
102
|
+
if ((!description || *description == '\0') && MayFallBackToEnglish(lang)) {
|
|
103
|
+
const AreaCodeMap* default_descriptions = GetPhonePrefixDescriptions(
|
|
104
|
+
phone_prefix, "en", "", "");
|
|
105
|
+
if (!default_descriptions) {
|
|
106
|
+
return "";
|
|
107
|
+
}
|
|
108
|
+
description = default_descriptions->Lookup(number);
|
|
109
|
+
}
|
|
110
|
+
return description ? description : "";
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Don't fall back to English if the requested language is among the following:
|
|
114
|
+
// - Chinese
|
|
115
|
+
// - Japanese
|
|
116
|
+
// - Korean
|
|
117
|
+
bool PhoneNumberCarrierMapper::MayFallBackToEnglish(const string& lang) const {
|
|
118
|
+
return lang.compare("zh") && lang.compare("ja") && lang.compare("ko");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
string PhoneNumberCarrierMapper::GetNameForNumber(
|
|
122
|
+
const PhoneNumber& number, const string& lang) const {
|
|
123
|
+
return GetAreaDescription(number, lang, "", "");
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
} // namespace phonenumbers
|
|
127
|
+
} // namespace i18n
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
// First-party pico_phone file. A trimmed mirror of libphonenumber's
|
|
2
|
+
// PhoneNumberOfflineGeocoder (phonenumbers/geocoding/
|
|
3
|
+
// phonenumber_offline_geocoder.h in the vendored source), reusing the same
|
|
4
|
+
// AreaCodeMap/MappingFileProvider machinery -- lazy per (country calling
|
|
5
|
+
// code, language) file loading, cached for the life of the process -- but
|
|
6
|
+
// backed by carrier_data.cc instead of geocoding_data.cc, and with the
|
|
7
|
+
// ICU-based country-name fallback removed: carrier data has no natural
|
|
8
|
+
// "fall back to the country name" concept (unlike geocoding), so an
|
|
9
|
+
// unmapped prefix returns an empty string, matching phonelib's carrier
|
|
10
|
+
// semantics. This also means, unlike the geocoder, this class has no ICU
|
|
11
|
+
// dependency at all.
|
|
12
|
+
|
|
13
|
+
#ifndef PICO_PHONE_CARRIER_MAPPER_H_
|
|
14
|
+
#define PICO_PHONE_CARRIER_MAPPER_H_
|
|
15
|
+
|
|
16
|
+
#include <map>
|
|
17
|
+
#include <string>
|
|
18
|
+
|
|
19
|
+
#include "absl/synchronization/mutex.h"
|
|
20
|
+
#include "phonenumbers/base/memory/scoped_ptr.h"
|
|
21
|
+
|
|
22
|
+
namespace i18n {
|
|
23
|
+
namespace phonenumbers {
|
|
24
|
+
|
|
25
|
+
class AreaCodeMap;
|
|
26
|
+
class MappingFileProvider;
|
|
27
|
+
class PhoneNumber;
|
|
28
|
+
struct CountryLanguages;
|
|
29
|
+
struct PrefixDescriptions;
|
|
30
|
+
|
|
31
|
+
class PhoneNumberCarrierMapper {
|
|
32
|
+
private:
|
|
33
|
+
typedef std::map<std::string, const AreaCodeMap*> AreaCodeMaps;
|
|
34
|
+
|
|
35
|
+
public:
|
|
36
|
+
PhoneNumberCarrierMapper();
|
|
37
|
+
|
|
38
|
+
PhoneNumberCarrierMapper(const PhoneNumberCarrierMapper&) = delete;
|
|
39
|
+
PhoneNumberCarrierMapper& operator=(const PhoneNumberCarrierMapper&) = delete;
|
|
40
|
+
|
|
41
|
+
~PhoneNumberCarrierMapper();
|
|
42
|
+
|
|
43
|
+
// Returns the carrier name for the given phone number in the given
|
|
44
|
+
// language, or an empty string if no carrier mapping is available for
|
|
45
|
+
// this prefix. lang is a two or three-letter lowercase ISO 639 language
|
|
46
|
+
// code, as with PhoneNumberOfflineGeocoder.
|
|
47
|
+
//
|
|
48
|
+
// The carrier name is the one the number was originally allocated to,
|
|
49
|
+
// however if the country supports mobile number portability the number
|
|
50
|
+
// might not belong to the returned carrier anymore (same caveat as
|
|
51
|
+
// upstream's Java-only PhoneNumberToCarrierMapper.getNameForNumber,
|
|
52
|
+
// verbatim -- see java/carrier/src/.../PhoneNumberToCarrierMapper.java
|
|
53
|
+
// in the vendored source tree).
|
|
54
|
+
std::string GetNameForNumber(const PhoneNumber& number,
|
|
55
|
+
const std::string& lang) const;
|
|
56
|
+
|
|
57
|
+
private:
|
|
58
|
+
typedef const PrefixDescriptions* (*prefix_descriptions_getter)(int index);
|
|
59
|
+
|
|
60
|
+
const AreaCodeMap* LoadAreaCodeMapFromFile(
|
|
61
|
+
const std::string& filename) const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
|
|
62
|
+
|
|
63
|
+
const AreaCodeMap* GetPhonePrefixDescriptions(
|
|
64
|
+
int prefix, const std::string& language, const std::string& script,
|
|
65
|
+
const std::string& region) const ABSL_EXCLUSIVE_LOCKS_REQUIRED(mu_);
|
|
66
|
+
|
|
67
|
+
const char* GetAreaDescription(const PhoneNumber& number,
|
|
68
|
+
const std::string& lang,
|
|
69
|
+
const std::string& script,
|
|
70
|
+
const std::string& region) const
|
|
71
|
+
ABSL_LOCKS_EXCLUDED(mu_);
|
|
72
|
+
|
|
73
|
+
bool MayFallBackToEnglish(const std::string& lang) const;
|
|
74
|
+
|
|
75
|
+
scoped_ptr<const MappingFileProvider> provider_;
|
|
76
|
+
|
|
77
|
+
const char** prefix_language_code_pairs_;
|
|
78
|
+
int prefix_language_code_pairs_size_;
|
|
79
|
+
prefix_descriptions_getter get_prefix_descriptions_;
|
|
80
|
+
|
|
81
|
+
mutable absl::Mutex mu_;
|
|
82
|
+
mutable AreaCodeMaps available_maps_ ABSL_GUARDED_BY(mu_);
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
} // namespace phonenumbers
|
|
86
|
+
} // namespace i18n
|
|
87
|
+
|
|
88
|
+
#endif // PICO_PHONE_CARRIER_MAPPER_H_
|
data/ext/pico_phone/extconf.rb
CHANGED
|
@@ -2,6 +2,14 @@ require "mkmf-rice"
|
|
|
2
2
|
|
|
3
3
|
$CXXFLAGS << ' -std=c++17'
|
|
4
4
|
|
|
5
|
+
# carrier_mapper.cc needs AreaCodeMap/MappingFileProvider/the
|
|
6
|
+
# CountryLanguages+PrefixDescriptions structs, none of which libphonenumber
|
|
7
|
+
# installs publicly (only phonenumber_offline_geocoder.h is installed) in
|
|
8
|
+
# either build path below. Headers vendored verbatim under
|
|
9
|
+
# vendor_headers/phonenumbers/geocoding/ -- see that directory's own
|
|
10
|
+
# comments. Needed unconditionally, regardless of NATIVE_BUILD.
|
|
11
|
+
$INCFLAGS << " -I#{File.expand_path("vendor_headers", __dir__)}"
|
|
12
|
+
|
|
5
13
|
VENDOR_INSTALL = File.expand_path("vendor/install", __dir__)
|
|
6
14
|
NATIVE_BUILD = ENV["PICO_PHONE_NATIVE_BUILD"] == "1"
|
|
7
15
|
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#include <string.h>
|
|
4
4
|
#include <list>
|
|
5
5
|
#include <set>
|
|
6
|
+
#include <vector>
|
|
6
7
|
#include <phonenumbers/phonenumber.pb.h>
|
|
7
8
|
#include <phonenumbers/phonenumberutil.h>
|
|
8
9
|
#include <phonenumbers/shortnumberinfo.h>
|
|
@@ -13,6 +14,8 @@
|
|
|
13
14
|
// any ICU header is reachable.
|
|
14
15
|
#undef UChar
|
|
15
16
|
#include <phonenumbers/geocoding/phonenumber_offline_geocoder.h>
|
|
17
|
+
#include "carrier_mapper.h"
|
|
18
|
+
#include "timezone_mapper.h"
|
|
16
19
|
|
|
17
20
|
using namespace Rice;
|
|
18
21
|
using namespace i18n::phonenumbers;
|
|
@@ -223,6 +226,51 @@ VALUE parsed_number_geo_name(int argc, VALUE *argv, VALUE self) {
|
|
|
223
226
|
return rb_str_new(description.c_str(), description.size());
|
|
224
227
|
}
|
|
225
228
|
|
|
229
|
+
// PhoneNumberCarrierMapper mirrors PhoneNumberOfflineGeocoder's lazy
|
|
230
|
+
// per-(prefix, language) file loading and caching -- see carrier_mapper.h.
|
|
231
|
+
static const PhoneNumberCarrierMapper& GetCarrierMapper() {
|
|
232
|
+
static PhoneNumberCarrierMapper instance;
|
|
233
|
+
return instance;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
VALUE parsed_number_carrier_name(int argc, VALUE *argv, VALUE self) {
|
|
237
|
+
VALUE language;
|
|
238
|
+
rb_scan_args(argc, argv, "01", &language);
|
|
239
|
+
|
|
240
|
+
std::string language_code = RB_NIL_P(language)
|
|
241
|
+
? "en"
|
|
242
|
+
: std::string(StringValuePtr(language), RSTRING_LEN(language));
|
|
243
|
+
|
|
244
|
+
PhoneNumber *phone_number;
|
|
245
|
+
TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
|
|
246
|
+
|
|
247
|
+
std::string name = GetCarrierMapper().GetNameForNumber(*phone_number, language_code);
|
|
248
|
+
|
|
249
|
+
return rb_str_new(name.c_str(), name.size());
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// PhoneNumberTimeZonesMapper eagerly loads its single flat prefix table
|
|
253
|
+
// once at construction (unlike the geocoder/carrier mappers, there's no
|
|
254
|
+
// per-language dimension or lazy per-file loading to do here) -- see
|
|
255
|
+
// timezone_mapper.h.
|
|
256
|
+
static const PhoneNumberTimeZonesMapper& GetTimeZonesMapper() {
|
|
257
|
+
static PhoneNumberTimeZonesMapper instance;
|
|
258
|
+
return instance;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
Array parsed_number_timezones(Object self) {
|
|
262
|
+
PhoneNumber *phone_number;
|
|
263
|
+
TypedData_Get_Struct(self, PhoneNumber, &phone_number_type, phone_number);
|
|
264
|
+
|
|
265
|
+
std::vector<std::string> zones = GetTimeZonesMapper().GetTimeZonesForNumber(*phone_number);
|
|
266
|
+
|
|
267
|
+
Array result;
|
|
268
|
+
for (const auto& zone : zones) {
|
|
269
|
+
result.push(Object(rb_str_new(zone.c_str(), zone.size())));
|
|
270
|
+
}
|
|
271
|
+
return result;
|
|
272
|
+
}
|
|
273
|
+
|
|
226
274
|
Object pico_phone_is_emergency_number(Object self, String number, String region) {
|
|
227
275
|
return GetShortNumberInfo().IsEmergencyNumber(number.c_str(), region.c_str()) ? Qtrue : Qfalse;
|
|
228
276
|
}
|
|
@@ -860,9 +908,11 @@ void Init_pico_phone() {
|
|
|
860
908
|
.define_method("possible_with_reason", &parsed_number_possible_with_reason)
|
|
861
909
|
.define_method("geographical?", &parsed_number_geographical)
|
|
862
910
|
.define_method("can_be_internationally_dialled?", &parsed_number_can_be_internationally_dialled)
|
|
863
|
-
.define_method("possible_for_type?", &parsed_number_possible_for_type)
|
|
911
|
+
.define_method("possible_for_type?", &parsed_number_possible_for_type)
|
|
912
|
+
.define_method("timezones", &parsed_number_timezones);
|
|
864
913
|
|
|
865
914
|
rb_define_alloc_func(rb_cPhoneNumber, rb_phone_number_alloc);
|
|
866
915
|
rb_define_method(rb_cPhoneNumber, "initialize", reinterpret_cast<VALUE (*)(...)>(phone_number_initialize), -1);
|
|
867
916
|
rb_define_method(rb_cPhoneNumber, "geo_name", reinterpret_cast<VALUE (*)(...)>(parsed_number_geo_name), -1);
|
|
917
|
+
rb_define_method(rb_cPhoneNumber, "carrier_name", reinterpret_cast<VALUE (*)(...)>(parsed_number_carrier_name), -1);
|
|
868
918
|
}
|