2 # create the enterprises.c file from
3 # https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
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
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)) {
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]);
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
59 for line
in file_content
.splitlines():
60 decimal_match
= re
.match(DECIMAL_PATTERN
, line
)
62 decimal
= decimal_match
.group(0)
63 elif re
.match(ORGANIZATION_PATTERN
, line
):
64 organization
= line
.strip()
65 if organization
.lower() == "unassigned":
67 organization
= re
.sub(FORMERLY_PATTERN
, r
"\t# \1", organization
)
68 org_lines
+= [decimal
+ "\t" + organization
]
69 elif "last updated" in line
.lower():
71 elif "end of document" in line
.lower():
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
)
82 def __init__(self
, filename
, last_updated_line
):
83 self
.filename
= filename
84 self
.f
= open(filename
, 'w')
89 self
.f
.write('/* ' + os
.path
.basename(self
.filename
) + '\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')
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')
109 self
.f
.write('static const char * const table[] =\n')
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
118 line
= ' "' + self
.mappings
[n
] + '"'
120 if n
< self
.highest_num
:
122 # Add number as aligned comment.
123 line
+= ' '*(90-len(line
)) + '// ' + str(n
)
125 self
.f
.write(line
+'\n')
129 print('Re-generated', self
.filename
)
132 self
.f
.write(LOOKUP_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('"', '""')
144 self
.mappings
[num
] = name
145 self
.highest_num
= num
if num
>self
.highest_num
else self
.highest_num
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
:
160 with urllib
.request
.urlopen(ENTERPRISE_NUMBERS_URL
) as f
:
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
)
175 num
, name
= match
.group(1), match
.group(2)
176 # Strip any comments and/or trailing whitespace
182 c_file
.addMapping(int(num
), name
)
186 if __name__
== "__main__":