summaryrefslogtreecommitdiff
path: root/scripts/create-mcc-mnc-table.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/create-mcc-mnc-table.py')
-rw-r--r--scripts/create-mcc-mnc-table.py373
1 files changed, 278 insertions, 95 deletions
diff --git a/scripts/create-mcc-mnc-table.py b/scripts/create-mcc-mnc-table.py
index 761454c..c7afb56 100644
--- a/scripts/create-mcc-mnc-table.py
+++ b/scripts/create-mcc-mnc-table.py
@@ -1,106 +1,289 @@
-#Generates MTS_IO_MccMncTable.cpp file by pulling latest MCC/MNC values
-#from http://mcc-mnc.com
+#!/usr/bin/env python3
-#Original Source Idea: https://github.com/musalbas/mcc-mnc-table
+"""
+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 urllib2
+import urllib.request
+import urllib.parse
import datetime
+import csv
+import argparse
+
+from typing import Iterable, Generator, Optional, TextIO
+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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+/*!
+ \\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 <mts/MTS_IO_MccMncTable.h>
+#include <mts/MTS_Logger.h>
+#include <mts/MTS_Text.h>
+
+using namespace MTS::IO;
+
+MTS::AutoPtr<MTS::Lock> 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<std::string> 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];
+ j["carrierCode"] = vJson[4];
+ return j;
+ }
+ }
+
+ return Json::Value::null;
+}
+"""
+
+########################################################################################################################
+
+MccMncElement = namedtuple(
+ 'MccMncData',
+ field_names=('mcc', 'mcc_int', 'mnc', 'mnc_int', 'iso', 'country', 'country_code', 'carrier', 'carrier_code')
+)
+
+
+########################################################################################################################
+
+def init_argparse() -> argparse.ArgumentParser:
+ parser = argparse.ArgumentParser(description='Generate MCC/MNC table file from Website or CSV')
+ parser.add_argument('-w', '--website', action='store_true')
+ parser.add_argument('-c', '--csv', type=str)
+ parser.add_argument('-t', '--target', type=str, default='-')
+ return parser
+
+
+def print_cpp_preamble(*, target: Optional[TextIO] = None) -> None:
+ print(PREAMBLE_TEMPLATE.format(today=datetime.date.today()), file=target)
+
+
+def print_cpp_general_code(*, target: Optional[TextIO] = None) -> None:
+ print(GENERAL_CODE, file=target)
+
+
+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},{carrier},{carrier_code}";'.format(
+ mcc_int=el.mcc_int,
+ mnc_int=el.mnc_int,
+ iso=el.iso,
+ country=el.country,
+ country_code=el.country_code,
+ carrier=el.carrier,
+ carrier_code=el.carrier_code
+ )
+ 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({carrier}) Carrier Code({carrier_code})'.format(
+ mcc=el.mcc,
+ iso=el.iso,
+ country=el.country,
+ country_code=el.country_code,
+ carrier=el.carrier,
+ carrier_code=el.carrier_code
+ )
+
+
+def print_cpp_mcc_mnc_create_table(source: Iterable[MccMncElement], *, target: Optional[TextIO] = None) -> None:
+ print("void MccMncTable::createTable() {", file=target)
+ print(" std::string sData;", file=target)
+
+ for el in source:
+ print(format_mcc_mnc_line(el), file=target)
+
+ print("}", file=target)
+ print("", file=target)
+
+
+def print_cpp(source: Iterable[MccMncElement], *, target: Optional[TextIO] = None) -> None:
+ print_cpp_preamble(target=target)
+ print_cpp_general_code(target=target)
+ print_cpp_mcc_mnc_create_table(source, target=target)
+
+
+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('<td>([^<]*)</td>' * 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 '<tbody>' in line:
+ tbody_start = True
+ elif '</tbody>' 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,
+ carrier=carrier,
+ carrier_code="" # Multitech-specific, not populated from this source
+ )
+
+
+def mcc_mnc_from_csv(path: str) -> Generator[MccMncElement, None, None]:
+ with open(path) as f:
+ csv_reader = csv.DictReader(f)
+ for row in csv_reader:
+ mcc = row['MCC']
+ mnc = row['MNC']
+ iso = row['ISO']
+ country = row['Country']
+ country_code = row['Country Code']
+ carrier = row['Carrier']
+ carrier_code = row['Carrier Code']
+
+ 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,
+ carrier=carrier,
+ carrier_code=carrier_code
+ )
+
+
+########################################################################################################################
+
+def main() -> int:
+ parser = init_argparse()
+ args = parser.parse_args()
+
+ if (args.csv is not None) and args.website:
+ parser.error('Only one source can be used at a time.')
+ return 1
-print "/*!"
-print " \\file MTS_IO_MccMncTable.cpp"
-print " \\brief Auto-Generated MCC-MNC Lookup Table"
-print " \\date " + str(datetime.date.today())
-print " \\author sgodinez"
-print ""
-print " An Auto-Generated MCC-MNC Lookup Table"
-print "*/"
-print ""
-print "#include <mts/MTS_IO_MccMncTable.h>"
-print "#include <mts/MTS_Logger.h>"
-print "#include <mts/MTS_Text.h>"
-print ""
-print "using namespace MTS::IO;"
-print ""
-print "MTS::AutoPtr<MTS::Lock> MccMncTable::m_apLock(new MTS::Lock());"
-print "MccMncTable* MccMncTable::m_pInstance = NULL;"
-print ""
-print "MccMncTable* MccMncTable::getInstance() {"
-print " if(m_pInstance == NULL) {"
-print " m_apLock->lock();"
-print " if (m_pInstance == NULL) {"
-print " m_pInstance = new MccMncTable();"
-print " }"
-print " m_apLock->unlock();"
-print " }"
-print " return m_pInstance;"
-print "}"
-print ""
-print "MccMncTable::MccMncTable() {"
-print " createTable();"
-print "}"
-print ""
-print "Json::Value MccMncTable::lookup(const std::string& sMcc, const std::string& sMnc) {"
-print " uint32_t iMcc, iMnc;"
-print ' printTrace("[MCCMNC] MCCx[%s] MNCx[%s]", sMcc.c_str(), sMnc.c_str());'
-print " if(!MTS::Text::parseHex(iMcc, sMcc)) { return Json::Value::null; }"
-print " if(!MTS::Text::parseHex(iMnc, sMnc)) { return Json::Value::null; }"
-print ' printTrace("[MCCMNC] MCC0X[%d] MNC0X[%d]", iMcc, iMnc);'
-print " if (m_mTable.count(iMcc)) {"
-print " if(m_mTable[iMcc].count(iMnc)) {"
-print " std::vector<std::string> vJson = MTS::Text::split(m_mTable[iMcc][iMnc], ',');"
-print " Json::Value j;"
-print ' j["iso"] = vJson[0];'
-print ' j["country"] = vJson[1];'
-print ' j["code"] = vJson[2];'
-print ' j["carrier"] = vJson[3];'
-print " return j;"
-print " }"
-print " }"
-print ""
-print " return Json::Value::null;"
-print "}"
-print ""
-print "void MccMncTable::createTable() {"
-print " std::string sData;"
-
-td_re = re.compile('<td>([^<]*)</td>'*6)
-
-html = urllib2.urlopen('http://mcc-mnc.com/').read()
-
-tbody_start = False
-for line in html.split('\n'):
- if '<tbody>' in line:
- tbody_start = True
- elif '</tbody>' 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(',','')
- countryCode = td_search.group(4).strip().replace(',','')
- country = td_search.group(5).strip().replace(',','')
- carrier = td_search.group(6).strip().replace(',','')
-
- if mnc != "n/a":
- mcc_int = int(mcc, 16)
- if len(mnc) == 2:
- mnc_int = int(mnc + 'f', 16)
- else:
- mnc_int = int(mnc, 16)
- print ' m_mTable[' + str(mcc_int) + '][' + str(mnc_int) + '] = "' + \
- iso + ',' + countryCode + ',' + country + ',' + carrier + '";'
- else:
- print " //MCC(" + mcc + ') MNC(N/A) ISO(' + iso + ') Country Code(' + countryCode + ') Country(' + country + ') Carrier(' + carrier + ')'
-
-
-
-print "}"
-print ""
+ if args.csv is None:
+ source = mcc_mnc_from_website('http://mcc-mnc.com/')
+ else:
+ source = mcc_mnc_from_csv(args.csv)
+ if args.target == '-':
+ # Print to stdout
+ print_cpp(source, target=None)
+ else:
+ # Print to file
+ with open(args.target, 'w') as f:
+ print_cpp(source, target=f)
+ return 0
+########################################################################################################################
+if __name__ == "__main__":
+ ret = main()
+ exit(ret)