#!/usr/bin/env python3
"""
Generates MTS_IO_MccMncTable.cpp file by pulling latest MCC/MNC values
from http://mcc-mnc.com or the csv file.
Original Source Idea: https://github.com/musalbas/mcc-mnc-table
"""
########################################################################################################################
import re
import urllib.request
import urllib.parse
import datetime
from typing import Iterable, Generator
from collections import namedtuple
########################################################################################################################
PREAMBLE_TEMPLATE = """\
/*
* Copyright (C) 2015 by Multi-Tech Systems
*
* This file is part of libmts-io.
*
* libmts-io is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* libmts-io is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with libmts-io. If not, see .
*
*/
/*!
\\file MTS_IO_MccMncTable.cpp
\\brief Auto-Generated MCC-MNC Lookup Table
\\date {today}
\\author sgodinez
An Auto-Generated MCC-MNC Lookup Table
*/
"""
GENERAL_CODE = """\
#include
#include
#include
using namespace MTS::IO;
MTS::AutoPtr MccMncTable::m_apLock(new MTS::Lock());
MccMncTable* MccMncTable::m_pInstance = NULL;
MccMncTable* MccMncTable::getInstance() {
if(m_pInstance == NULL) {
m_apLock->lock();
if (m_pInstance == NULL) {
m_pInstance = new MccMncTable();
}
m_apLock->unlock();
}
return m_pInstance;
}
MccMncTable::MccMncTable() {
createTable();
}
Json::Value MccMncTable::lookup(const std::string& sMcc, const std::string& sMnc) {
uint32_t iMcc, iMnc;
std::string sNormalizedMnc = sMnc;
printTrace("[MCCMNC] MCCx[%s] MNCx[%s]", sMcc.c_str(), sMnc.c_str());
if (sMnc.length() == 2) {
sNormalizedMnc += 'f';
}
if (!MTS::Text::parseHex(iMcc, sMcc)) { return Json::Value::null; }
if (!MTS::Text::parseHex(iMnc, sNormalizedMnc)) { return Json::Value::null; }
printTrace("[MCCMNC] MCC0X[%d] MNC0X[%d]", iMcc, iMnc);
if (m_mTable.count(iMcc)) {
if(m_mTable[iMcc].count(iMnc)) {
std::vector vJson = MTS::Text::split(m_mTable[iMcc][iMnc], ',');
Json::Value j;
j["iso"] = vJson[0];
j["country"] = vJson[1];
j["code"] = vJson[2];
j["carrier"] = vJson[3];
return j;
}
}
return Json::Value::null;
}
"""
########################################################################################################################
MccMncElement = namedtuple(
'MccMncData',
field_names=('mcc', 'mcc_int', 'mnc', 'mnc_int', 'iso', 'country', 'country_code', 'network')
)
########################################################################################################################
def print_cpp_preamble() -> None:
print(PREAMBLE_TEMPLATE.format(today=datetime.date.today()))
def print_cpp_general_code() -> None:
print(GENERAL_CODE)
def format_mcc_mnc_line(el: MccMncElement) -> str:
if el.mnc.upper() != "N/A":
return ' m_mTable[{mcc_int}][{mnc_int}] = "{iso},{country},{country_code},{network}";'.format(
mcc_int=el.mcc_int,
mnc_int=el.mnc_int,
iso=el.iso,
country=el.country,
country_code=el.country_code,
network=el.network
)
else:
# TODO: The Country and Country Code values were swapped in the original implementation due to a bug.
# Left as is for compatibility reasons.
return ' //MCC({mcc}) MNC(N/A) ISO({iso}) Country Code({country}) Country({country_code}) Carrier({network})'.format(
mcc=el.mcc,
iso=el.iso,
country=el.country,
country_code=el.country_code,
network=el.network
)
def print_cpp_mcc_mnc_table(data: Iterable[MccMncElement]) -> None:
print("void MccMncTable::createTable() {")
print(" std::string sData;")
for el in data:
print(format_mcc_mnc_line(el))
print("}")
print("")
def mcc_to_mcc_int(src: str) -> str:
if src.upper() == "N/A":
return src
hash_ = int(src, 16)
return "{:d}".format(hash_)
def mnc_to_mnc_int(src: str) -> str:
if src.upper() == "N/A":
return src
src_norm = src
if len(src) == 2:
src_norm += 'f'
hash_ = int(src_norm, 16)
return "{:d}".format(hash_)
def mcc_mnc_from_website(url: str) -> Generator[MccMncElement, None, None]:
td_re = re.compile('([^<]*) | ' * 6)
html_bytes = urllib.request.urlopen(url).read() # type: bytes
html = html_bytes.decode(encoding='utf-8')
tbody_start = False
for line in html.split('\n'):
if '' in line:
tbody_start = True
elif '' in line:
break
elif tbody_start:
td_search = td_re.search(line)
mcc = td_search.group(1).strip().replace(',', '')
mnc = td_search.group(2).strip().replace(',', '')
iso = td_search.group(3).strip().replace(',', '')
country = td_search.group(4).strip().replace(',', '')
country_code = td_search.group(5).strip().replace(',', '')
carrier = td_search.group(6).strip().replace(',', '')
mcc_int = mcc_to_mcc_int(mcc)
mnc_int = mnc_to_mnc_int(mnc)
yield MccMncElement(
mcc=mcc,
mcc_int=mcc_int,
mnc=mnc,
mnc_int=mnc_int,
iso=iso,
country=country,
country_code=country_code,
network=carrier
)
########################################################################################################################
def main():
print_cpp_preamble()
print_cpp_general_code()
print_cpp_mcc_mnc_table(
mcc_mnc_from_website('http://mcc-mnc.com/')
)
########################################################################################################################
if __name__ == "__main__":
main()