decryption works, but addid doesn't because of unique pointer layers
[wireshark-sm.git] / tools / make-enterprises.py
blob30abc64228d56f0399abbb9eb06222bc3a322fb0
1 #!/usr/bin/env python3
2 # create the enterprises.c file from
3 # https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
4 # or an offline copy
6 # Copyright 2022 by Moshe Kaplan
7 # Based on make-sminmpec.pl by Gerald Combs
9 # Wireshark - Network traffic analyzer
10 # By Gerald Combs <gerald@wireshark.org>
11 # Copyright 2004 Gerald Combs
13 # SPDX-License-Identifier: GPL-2.0-or-later
15 import os
16 import argparse
17 import re
18 import urllib.request
21 ENTERPRISES_CFILE = os.path.join('epan', 'enterprises.c')
23 ENTERPRISE_NUMBERS_URL = "https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers"
25 DECIMAL_PATTERN = r"^(\d+)"
26 # up to three spaces because of formatting errors in the source
27 ORGANIZATION_PATTERN = r"^ ?(\S.*)"
28 FORMERLY_PATTERN = r" \(((formerly|previously) .*)\)"
31 LOOKUP_FUNCTION = r"""
32 const char* global_enterprises_lookup(uint32_t value)
34 if (value >= array_length(table)) {
35 return NULL;
37 return table[value];
39 """
41 DUMP_FUNCTION = r"""
42 void global_enterprises_dump(FILE *fp)
44 for (size_t idx = 0; idx < array_length(table); idx++) {
45 if (table[idx] != NULL) {
46 fprintf(fp, "%zu\t%s\n", idx, table[idx]);
50 """
52 # This intermediate format is no longer written to a file - returned as string
53 def generate_enterprise_entries(file_content):
54 # We only care about the "Decimal" and "Organization",
55 # not the contact or email
56 org_lines = []
57 last_updated = ""
58 end_seen = False
59 for line in file_content.splitlines():
60 decimal_match = re.match(DECIMAL_PATTERN, line)
61 if decimal_match:
62 decimal = decimal_match.group(0)
63 elif re.match(ORGANIZATION_PATTERN, line):
64 organization = line.strip()
65 if organization.lower() == "unassigned":
66 continue
67 organization = re.sub(FORMERLY_PATTERN, r"\t# \1", organization)
68 org_lines += [decimal + "\t" + organization]
69 elif "last updated" in line.lower():
70 last_updated = line
71 elif "end of document" in line.lower():
72 end_seen = True
74 if not end_seen:
75 raise Exception('"End of Document" not found. Truncated source file?')
77 last_updated_line = "/* " + last_updated + " */\n\n"
78 output = "\n".join(org_lines) + "\n"
79 return (output,last_updated_line)
81 class CFile:
82 def __init__(self, filename, last_updated_line):
83 self.filename = filename
84 self.f = open(filename, 'w')
85 self.mappings = {}
86 self.highest_num = 0
88 # Write file header
89 self.f.write('/* ' + os.path.basename(self.filename) + '\n')
90 self.f.write(' *\n')
91 self.f.write(' * Wireshark - Network traffic analyzer\n')
92 self.f.write(' * By Gerald Combs <gerald@wireshark.org>\n')
93 self.f.write(' * Copyright 1998 Gerald Combs\n')
94 self.f.write(' *\n')
95 self.f.write(' * Do not edit - this file is automatically generated\n')
96 self.f.write(' * SPDX-License-Identifier: GPL-2.0-or-later\n')
97 self.f.write(' */\n\n')
98 self.f.write(last_updated_line)
100 # Include header files
101 self.f.write('#include "config.h"\n\n')
102 self.f.write('#include <stddef.h>\n')
103 self.f.write('#include <wsutil/array.h>\n')
104 self.f.write('#include "enterprises.h"\n')
105 self.f.write('\n\n')
107 def __del__(self):
108 # Write static table
109 self.f.write('static const char * const table[] =\n')
110 self.f.write('{\n')
111 # Largest index
112 # Entries (read from dict)
113 for n in range(0, self.highest_num+1):
114 if n not in self.mappings:
115 # There are some gaps, write a NULL entry so can lookup by index
116 line = ' NULL'
117 else:
118 line = ' "' + self.mappings[n] + '"'
119 # Add comma.
120 if n < self.highest_num:
121 line += ','
122 # Add number as aligned comment.
123 line += ' '*(90-len(line)) + '// ' + str(n)
125 self.f.write(line+'\n')
127 # End of array
128 self.f.write('};\n')
129 print('Re-generated', self.filename)
131 # Lookup function
132 self.f.write(LOOKUP_FUNCTION)
134 # Dump function
135 self.f.write(DUMP_FUNCTION)
137 # Add an individual mapping to the function
138 def addMapping(self, num, name):
139 # Handle some escapings
140 name = name.replace('\\', '\\\\')
141 name = name.replace('"', '""')
143 # Record.
144 self.mappings[num] = name
145 self.highest_num = num if num>self.highest_num else self.highest_num
149 def main():
150 parser = argparse.ArgumentParser(description="Create the {} file.".format(ENTERPRISES_CFILE))
151 parser.add_argument('--infile')
152 parser.add_argument('outfile', nargs='?', default=ENTERPRISES_CFILE)
153 parsed_args = parser.parse_args()
155 # Read data from file or webpage
156 if parsed_args.infile:
157 with open(parsed_args.infile, encoding='utf-8') as fh:
158 data = fh.read()
159 else:
160 with urllib.request.urlopen(ENTERPRISE_NUMBERS_URL) as f:
161 if f.status != 200:
162 raise Exception("request for " + ENTERPRISE_NUMBERS_URL + " failed with result code " + f.status)
163 data = f.read().decode('utf-8').replace(u'\u200e', '')
165 # Find bits we need and generate enterprise entries
166 enterprises_content,last_updated_line = generate_enterprise_entries(data)
168 # Now write to a C file the contents (which is faster than parsing the global file at runtime).
169 c_file = CFile(parsed_args.outfile, last_updated_line)
171 mapping_re = re.compile(r'^(\d+)\s+(.*)$')
172 for line in enterprises_content.splitlines():
173 match = mapping_re.match(line)
174 if match:
175 num, name = match.group(1), match.group(2)
176 # Strip any comments and/or trailing whitespace
177 idx = name.find('#')
178 if idx != -1:
179 name = name[0:idx]
180 name = name.rstrip()
181 # Add
182 c_file.addMapping(int(num), name)
186 if __name__ == "__main__":
187 main()