blob: 02806886c0ccb54751c071d70091c49d9589567a [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Please refer to ISO 3166-1 for information about the two-character country
// codes; http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 is useful. In the
// following (C++) code, we pack the two letters of the country code into an int
// value we call the CountryId.
#ifndef COMPONENTS_COUNTRY_CODES_COUNTRY_CODES_H_
#define COMPONENTS_COUNTRY_CODES_COUNTRY_CODES_H_
#include <array>
#include <string>
#include "base/component_export.h"
namespace country_codes {
// Class representing a Country Identifier based on ISO 3166-1 two-letter
// country codes.
class CountryId {
public:
// Constructs the default instance of CountryId pointing to an unspecified
// country.
constexpr CountryId() : CountryId(kUnknownCountryCode) {}
// Constructs a CountryId from a two-character country code (ISO 3166-1).
// If the provided code does not have exactly two uppercase letter characters,
// the constructed CountryId will report invalid.
explicit constexpr CountryId(std::string_view code) {
if (code.size() != 2 // Country code is exactly 2 letters long
|| code[0] < 'A' || code[0] > 'Z' // Country code requires exactly
|| code[1] < 'A' || code[1] > 'Z' // two uppercase letters.
) {
code = kUnknownCountryCode;
}
country_code_[0] = code[0];
country_code_[1] = code[1];
}
// Deserializes a CountryId from an integer code.
// This call complements the `Serialize()` method, and can be used to
// de-serialize CountryId from persisted information.
// If the supplied integer fails validation, the constructed CountryId will
// report invalid.
static constexpr CountryId Deserialize(int code) {
// We only use the lowest 16 bits to build two ASCII characters. If there is
// more than that, the ID is invalid.
if (code <= 0 || code > 0xffff) {
return CountryId();
}
char country_code[2]{static_cast<char>(code >> 8),
static_cast<char>(code & 0xff)};
return CountryId(std::string_view(country_code, std::size(country_code)));
}
// Returns the integer representation of the CountryId. This is exposed for
// serialization and testing but should not be used for any other purpose.
constexpr int Serialize() const {
return country_code_[0] << 8 | country_code_[1];
}
constexpr auto operator<=>(const CountryId& other) const = default;
// Determines whether this instance of CountryId represents a valid country.
constexpr bool IsValid() const {
return CountryCode() != kUnknownCountryCode;
}
// Returns associated country code.
// This call alone may not sufficiently help you determine the country, and
// will return a country code associated with unknown or invalid territory,
// when `IsValid()` returns `false`.
constexpr std::string_view CountryCode() const {
return std::string_view(country_code_.data(), country_code_.size());
}
private:
// ISRC uses ZZ as a pseudo country code, if
// - the origin is unknown, or
// - the territory was not issued a country code through the ISRC agency, or
// otherwise 'ZZ' is used for testing and to denote an unknown, or invalid
// territory, and does not reference a real country.
// See https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#ZZ
static constexpr std::string_view kUnknownCountryCode = "ZZ";
// Note: this must be a std::array, and not a char[] array to enforce proper
// creation of `std::string_view`. This is because arrays implicitly decay to
// pointers, which may confuse std::string_view and result in security issues.
std::array<char, 2> country_code_{};
};
// Returns the identifier for the user current country.
COMPONENT_EXPORT(COMPONENTS_COUNTRY_CODES)
CountryId GetCurrentCountryID();
} // namespace country_codes
#endif // COMPONENTS_COUNTRY_CODES_COUNTRY_CODES_H_