db2fw.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. #!/usr/bin/env python
  2. from io import BytesIO, open
  3. import struct
  4. import hashlib
  5. from dbparse import DBParser
  6. import sys
  7. from math import log
  8. MAGIC = 0x52474442
  9. VERSION = 20
  10. if len(sys.argv) < 3:
  11. print('Usage: %s output-file input-file' % sys.argv[0])
  12. sys.exit(2)
  13. def create_rules(countries):
  14. result = {}
  15. for c in countries.values():
  16. for rule in c.permissions:
  17. result[rule] = 1
  18. return list(result)
  19. def create_collections(countries):
  20. result = {}
  21. for c in countries.values():
  22. result[(c.permissions, c.dfs_region)] = 1
  23. return list(result)
  24. def create_wmms(countries):
  25. result = {}
  26. for c in countries.values():
  27. for rule in c.permissions:
  28. if rule.wmmrule is not None:
  29. result[rule.wmmrule] = 1
  30. return list(result)
  31. def be32(output, val):
  32. output.write(struct.pack('>I', val))
  33. def be16(output, val):
  34. output.write(struct.pack('>H', val))
  35. class PTR(object):
  36. def __init__(self, output):
  37. self._output = output
  38. self._pos = output.tell()
  39. be16(output, 0)
  40. self._written = False
  41. def set(self, val=None):
  42. if val is None:
  43. val = self._output.tell()
  44. assert val & 3 == 0
  45. self._offset = val
  46. pos = self._output.tell()
  47. self._output.seek(self._pos)
  48. be16(self._output, val >> 2)
  49. self._output.seek(pos)
  50. self._written = True
  51. def get(self):
  52. return self._offset
  53. @property
  54. def written(self):
  55. return self._written
  56. p = DBParser()
  57. countries = p.parse(open(sys.argv[2], 'r', encoding='utf-8'))
  58. rules = create_rules(countries)
  59. rules.sort()
  60. collections = create_collections(countries)
  61. collections.sort()
  62. wmms = create_wmms(countries)
  63. wmms.sort()
  64. output = BytesIO()
  65. # struct regdb_file_header
  66. be32(output, MAGIC)
  67. be32(output, VERSION)
  68. country_ptrs = {}
  69. countrynames = list(countries)
  70. countrynames.sort()
  71. for alpha2 in countrynames:
  72. coll = countries[alpha2]
  73. output.write(struct.pack('>BB', alpha2[0], alpha2[1]))
  74. country_ptrs[alpha2] = PTR(output)
  75. output.write(b'\x00' * 4)
  76. wmmdb = {}
  77. for w in wmms:
  78. assert output.tell() & 3 == 0
  79. wmmdb[w] = output.tell() >> 2
  80. for r in w._as_tuple():
  81. ecw = int(log(r[0] + 1, 2)) << 4 | int(log(r[1] + 1, 2))
  82. ac = (ecw, r[2],r[3])
  83. output.write(struct.pack('>BBH', *ac))
  84. reg_rules = {}
  85. flags = 0
  86. for reg_rule in rules:
  87. freq_range, power_rule, wmm_rule = reg_rule.freqband, reg_rule.power, reg_rule.wmmrule
  88. reg_rules[reg_rule] = output.tell()
  89. assert power_rule.max_ant_gain == 0
  90. flags = 0
  91. # convert to new rule flags
  92. assert reg_rule.flags & ~0x899 == 0
  93. if reg_rule.flags & 1<<0:
  94. flags |= 1<<0
  95. if reg_rule.flags & 1<<3:
  96. flags |= 1<<1
  97. if reg_rule.flags & 1<<4:
  98. flags |= 1<<2
  99. if reg_rule.flags & 1<<7:
  100. flags |= 1<<3
  101. if reg_rule.flags & 1<<11:
  102. flags |= 1<<4
  103. rule_len = 16
  104. cac_timeout = 0 # TODO
  105. if not (flags & 1<<2):
  106. cac_timeout = 0
  107. if cac_timeout or wmm_rule:
  108. rule_len += 2
  109. if wmm_rule is not None:
  110. rule_len += 2
  111. output.write(struct.pack('>BBHIII', rule_len, flags, int(power_rule.max_eirp * 100),
  112. int(freq_range.start * 1000), int(freq_range.end * 1000), int(freq_range.maxbw * 1000),
  113. ))
  114. if rule_len > 16:
  115. output.write(struct.pack('>H', cac_timeout))
  116. if rule_len > 18:
  117. be16(output, wmmdb[wmm_rule])
  118. while rule_len % 4:
  119. output.write('\0')
  120. rule_len += 1
  121. for coll in collections:
  122. for alpha2 in countrynames:
  123. if (countries[alpha2].permissions, countries[alpha2].dfs_region) == coll:
  124. assert not country_ptrs[alpha2].written
  125. country_ptrs[alpha2].set()
  126. slen = 3
  127. output.write(struct.pack('>BBBx', slen, len(list(coll[0])), coll[1]))
  128. coll = list(coll[0])
  129. for regrule in coll:
  130. be16(output, reg_rules[regrule] >> 2)
  131. if len(coll) % 2:
  132. be16(output, 0)
  133. for alpha2 in countrynames:
  134. assert country_ptrs[alpha2].written
  135. outfile = open(sys.argv[1], 'wb')
  136. outfile.write(output.getvalue())