159 lines
4.1 KiB
Python
Executable File
159 lines
4.1 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
from io import BytesIO, open
|
|
import struct
|
|
import hashlib
|
|
from dbparse import DBParser
|
|
import sys
|
|
from math import log
|
|
|
|
MAGIC = 0x52474442
|
|
VERSION = 20
|
|
|
|
if len(sys.argv) < 3:
|
|
print('Usage: %s output-file input-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, c.dfs_region)] = 1
|
|
return list(result)
|
|
|
|
def create_wmms(countries):
|
|
result = {}
|
|
for c in countries.values():
|
|
for rule in c.permissions:
|
|
if rule.wmmrule is not None:
|
|
result[rule.wmmrule] = 1
|
|
return list(result)
|
|
|
|
def be32(output, val):
|
|
output.write(struct.pack('>I', val))
|
|
def be16(output, val):
|
|
output.write(struct.pack('>H', val))
|
|
|
|
class PTR(object):
|
|
def __init__(self, output):
|
|
self._output = output
|
|
self._pos = output.tell()
|
|
be16(output, 0)
|
|
self._written = False
|
|
|
|
def set(self, val=None):
|
|
if val is None:
|
|
val = self._output.tell()
|
|
assert val & 3 == 0
|
|
self._offset = val
|
|
pos = self._output.tell()
|
|
self._output.seek(self._pos)
|
|
be16(self._output, val >> 2)
|
|
self._output.seek(pos)
|
|
self._written = True
|
|
|
|
def get(self):
|
|
return self._offset
|
|
|
|
@property
|
|
def written(self):
|
|
return self._written
|
|
|
|
p = DBParser()
|
|
countries = p.parse(open(sys.argv[2], 'r', encoding='utf-8'))
|
|
rules = create_rules(countries)
|
|
rules.sort()
|
|
collections = create_collections(countries)
|
|
collections.sort()
|
|
wmms = create_wmms(countries)
|
|
wmms.sort()
|
|
|
|
output = BytesIO()
|
|
|
|
# struct regdb_file_header
|
|
be32(output, MAGIC)
|
|
be32(output, VERSION)
|
|
|
|
country_ptrs = {}
|
|
countrynames = list(countries)
|
|
countrynames.sort()
|
|
for alpha2 in countrynames:
|
|
coll = countries[alpha2]
|
|
output.write(struct.pack('>BB', alpha2[0], alpha2[1]))
|
|
country_ptrs[alpha2] = PTR(output)
|
|
output.write(b'\x00' * 4)
|
|
|
|
wmmdb = {}
|
|
for w in wmms:
|
|
assert output.tell() & 3 == 0
|
|
wmmdb[w] = output.tell() >> 2
|
|
for r in w._as_tuple():
|
|
ecw = int(log(r[0] + 1, 2)) << 4 | int(log(r[1] + 1, 2))
|
|
ac = (ecw, r[2],r[3])
|
|
output.write(struct.pack('>BBH', *ac))
|
|
|
|
reg_rules = {}
|
|
flags = 0
|
|
for reg_rule in rules:
|
|
freq_range, power_rule, wmm_rule = reg_rule.freqband, reg_rule.power, reg_rule.wmmrule
|
|
reg_rules[reg_rule] = output.tell()
|
|
assert power_rule.max_ant_gain == 0
|
|
flags = 0
|
|
# convert to new rule flags
|
|
assert reg_rule.flags & ~0x899 == 0
|
|
if reg_rule.flags & 1<<0:
|
|
flags |= 1<<0
|
|
if reg_rule.flags & 1<<3:
|
|
flags |= 1<<1
|
|
if reg_rule.flags & 1<<4:
|
|
flags |= 1<<2
|
|
if reg_rule.flags & 1<<7:
|
|
flags |= 1<<3
|
|
if reg_rule.flags & 1<<11:
|
|
flags |= 1<<4
|
|
rule_len = 16
|
|
cac_timeout = 0 # TODO
|
|
if not (flags & 1<<2):
|
|
cac_timeout = 0
|
|
if cac_timeout or wmm_rule:
|
|
rule_len += 2
|
|
if wmm_rule is not None:
|
|
rule_len += 2
|
|
output.write(struct.pack('>BBHIII', rule_len, flags, int(power_rule.max_eirp * 100),
|
|
int(freq_range.start * 1000), int(freq_range.end * 1000), int(freq_range.maxbw * 1000),
|
|
))
|
|
if rule_len > 16:
|
|
output.write(struct.pack('>H', cac_timeout))
|
|
|
|
if rule_len > 18:
|
|
be16(output, wmmdb[wmm_rule])
|
|
|
|
while rule_len % 4:
|
|
output.write('\0')
|
|
rule_len += 1
|
|
|
|
for coll in collections:
|
|
for alpha2 in countrynames:
|
|
if (countries[alpha2].permissions, countries[alpha2].dfs_region) == coll:
|
|
assert not country_ptrs[alpha2].written
|
|
country_ptrs[alpha2].set()
|
|
slen = 3
|
|
output.write(struct.pack('>BBBx', slen, len(list(coll[0])), coll[1]))
|
|
coll = list(coll[0])
|
|
for regrule in coll:
|
|
be16(output, reg_rules[regrule] >> 2)
|
|
if len(coll) % 2:
|
|
be16(output, 0)
|
|
|
|
for alpha2 in countrynames:
|
|
assert country_ptrs[alpha2].written
|
|
|
|
outfile = open(sys.argv[1], 'wb')
|
|
outfile.write(output.getvalue())
|