148 lines
3.6 KiB
Python
Executable File
148 lines
3.6 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
from io import BytesIO, open
|
|
import struct
|
|
import hashlib
|
|
from dbparse import DBParser
|
|
import sys
|
|
|
|
MAGIC = 0x52474442
|
|
VERSION = 19
|
|
|
|
if len(sys.argv) < 3:
|
|
print('Usage: %s output-file input-file [key-file]' % sys.argv[0])
|
|
sys.exit(2)
|
|
|
|
def create_rules(countries):
|
|
result = {}
|
|
for c in countries.values():
|
|
for rule in c.permissions:
|
|
result[rule] = 1
|
|
return list(result)
|
|
|
|
def create_collections(countries):
|
|
result = {}
|
|
for c in countries.values():
|
|
result[c.permissions] = 1
|
|
return list(result)
|
|
|
|
|
|
def be32(output, val):
|
|
output.write(struct.pack('>I', val))
|
|
|
|
class PTR(object):
|
|
def __init__(self, output):
|
|
self._output = output
|
|
self._pos = output.tell()
|
|
be32(output, 0xFFFFFFFF)
|
|
|
|
def set(self, val=None):
|
|
if val is None:
|
|
val = self._output.tell()
|
|
self._offset = val
|
|
pos = self._output.tell()
|
|
self._output.seek(self._pos)
|
|
be32(self._output, val)
|
|
self._output.seek(pos)
|
|
|
|
def get(self):
|
|
return self._offset
|
|
|
|
p = DBParser()
|
|
countries = p.parse(open(sys.argv[2], 'r', encoding='utf-8'))
|
|
|
|
countrynames = list(countries)
|
|
countrynames.sort()
|
|
|
|
power = []
|
|
bands = []
|
|
for alpha2 in countrynames:
|
|
for perm in countries[alpha2].permissions:
|
|
if not perm.freqband in bands:
|
|
bands.append(perm.freqband)
|
|
if not perm.power in power:
|
|
power.append(perm.power)
|
|
rules = create_rules(countries)
|
|
rules.sort()
|
|
collections = create_collections(countries)
|
|
collections.sort()
|
|
|
|
output = BytesIO()
|
|
|
|
# struct regdb_file_header
|
|
be32(output, MAGIC)
|
|
be32(output, VERSION)
|
|
reg_country_ptr = PTR(output)
|
|
# add number of countries
|
|
be32(output, len(countries))
|
|
siglen = PTR(output)
|
|
|
|
power_rules = {}
|
|
for pr in power:
|
|
power_rules[pr] = output.tell()
|
|
pr = [int(v * 100.0) for v in (pr.max_ant_gain, pr.max_eirp)]
|
|
# struct regdb_file_power_rule
|
|
output.write(struct.pack('>II', *pr))
|
|
|
|
freq_ranges = {}
|
|
for fr in bands:
|
|
freq_ranges[fr] = output.tell()
|
|
fr = [int(f * 1000.0) for f in (fr.start, fr.end, fr.maxbw)]
|
|
# struct regdb_file_freq_range
|
|
output.write(struct.pack('>III', *fr))
|
|
|
|
|
|
reg_rules = {}
|
|
for reg_rule in rules:
|
|
freq_range, power_rule = reg_rule.freqband, reg_rule.power
|
|
reg_rules[reg_rule] = output.tell()
|
|
# struct regdb_file_reg_rule
|
|
output.write(struct.pack('>III', freq_ranges[freq_range], power_rules[power_rule],
|
|
reg_rule.flags))
|
|
|
|
|
|
reg_rules_collections = {}
|
|
|
|
for coll in collections:
|
|
reg_rules_collections[coll] = output.tell()
|
|
# struct regdb_file_reg_rules_collection
|
|
coll = list(coll)
|
|
be32(output, len(coll))
|
|
coll.sort()
|
|
for regrule in coll:
|
|
be32(output, reg_rules[regrule])
|
|
|
|
# update country pointer now!
|
|
reg_country_ptr.set()
|
|
|
|
for alpha2 in countrynames:
|
|
coll = countries[alpha2]
|
|
# struct regdb_file_reg_country
|
|
output.write(struct.pack('>BBxBI', alpha2[0], alpha2[1], coll.dfs_region, reg_rules_collections[coll.permissions]))
|
|
|
|
|
|
if len(sys.argv) > 3:
|
|
# Load RSA only now so people can use this script
|
|
# without having those libraries installed to verify
|
|
# their SQL changes
|
|
from M2Crypto import RSA
|
|
|
|
# determine signature length
|
|
key = RSA.load_key(sys.argv[3])
|
|
hash = hashlib.sha1()
|
|
hash.update(output.getvalue())
|
|
sig = key.sign(hash.digest())
|
|
# write it to file
|
|
siglen.set(len(sig))
|
|
# sign again
|
|
hash = hashlib.sha1()
|
|
hash.update(output.getvalue())
|
|
sig = key.sign(hash.digest())
|
|
|
|
output.write(sig)
|
|
else:
|
|
siglen.set(0)
|
|
|
|
outfile = open(sys.argv[1], 'wb')
|
|
outfile.write(output.getvalue())
|