Loading asn2md.py +21 −42 Original line number Diff line number Diff line #!/usr/bin/env python # -*- coding: utf-8 -*- # asn1-doxygen-filter is an extension to the Doxygen utility for creating # documents from ASN.1 files # # Copyright 2017 OnBoard Security, Inc. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUTNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse # parse arguments import os.path # getting extension from file Loading Loading @@ -75,12 +53,12 @@ def parseText(content, indent=None): content = c ret = '' for m in RE_DOXY_C_COMMENTS.finditer(content): lines = m[1].splitlines() lines = m.group(1).splitlines() for l in lines: l = re.sub(r'\s*\*', '', l, 1).rstrip() ret += ''.ljust(indent or 0) + l + '\n' def repl_ref(m): return '[**{0}**]({1}#{0})'.format(m[1], extTypes.get(m[1],'')) return '[**{0}**]({1}#{0})'.format(m.group(1), extTypes.get(m.group(1),'')) c = re.sub(r'@ref\s+([\w-]+)', repl_ref, ret, 0, re.VERBOSE | re.MULTILINE) if c is not None: ret = c Loading @@ -99,14 +77,14 @@ def parseModule(mname, content): m = re.search(r'^\s*IMPORTS\s*(.*?);', content, re.VERBOSE | re.DOTALL | re.MULTILINE) if m is not None: pos = 0 if m[1] is not None: if m.group(1) is not None: ret += '## Imports:\n' s = m[1] s = m.group(1) for fm in re.finditer(r'^([,\s\w-]*?)FROM\s*([\w-]+)\s*({[^}]*}(?:\s+WITH\s+SUCCESSORS)?)?', s, re.VERBOSE | re.MULTILINE): imName = fm[2] for im in re.finditer(r'[^,\s]+', fm[1], 0): imName = fm.group(2) for im in re.finditer(r'[^,\s]+', fm.group(1), 0): extTypes[im[0]] = imName+'.md' ret += ' * **{}** *{}*<br/>\n'.format(imName, re.sub(r'\s+', ' ', fm[3] or '', 0, 0)) ret += ' * **{}** *{}*<br/>\n'.format(imName, re.sub(r'\s+', ' ', fm.group(3) or '', 0, 0)) ret += parseText(s[pos:fm.start()], 3)+'\n' pos = fm.end() ret += parseText(s[pos:]) Loading @@ -119,25 +97,25 @@ def parseModule(mname, content): # parse types def repl_type (m, doc): ret = '## <a name="{0}"></a>{0}\n\n'.format(m[2]) ret = '## <a name="{0}"></a>{0}\n\n'.format(m.group(2)) if doc is not None: ret += parseText(doc) + '\n\n' # parse fields and get out fields descriptions if m[3] is not None: if m.group(3) is not None: ret += 'Fields:\n' pos = 0 for fm in re.finditer('^\s*([\w-]+?)\s+(OCTET\s+STRING|BIT\s+STRING|[A-Z][.\w-]+)?(.*?)(?:,|$)', m[3], re.VERBOSE | re.MULTILINE | re.DOTALL): if fm[2] is not None: f = fm[1].strip() t = fm[2].strip() for fm in re.finditer('^\s*([\w-]+?)\s+(OCTET\s+STRING|BIT\s+STRING|[A-Z][.\w-]+)?(.*?)(?:,|$)', m.group(3), re.VERBOSE | re.MULTILINE | re.DOTALL): if fm.group(2) is not None: f = fm.group(1).strip() t = fm.group(2).strip() if re.match('^OCTET\s+STRING|BIT\s+STRING|BOOLEAN|INTEGER|FLOAT', t, re.VERBOSE|re.MULTILINE) is not None: ret += '* {0} **{1}** {2}<br>\n'.format(f, t, fm[3] or '') ret += '* {0} **{1}** {2}<br>\n'.format(f, t, fm.group(3) or '') else: ret += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), fm[3] or '') ret += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), fm.group(3) or '') ret += parseText(fm.string[pos:fm.start()], 3) pos = fm.end() return ret + '```asn1\n' + re.sub(r'^\s*--.*\n', '', m[1].strip(), 0, re.MULTILINE) +'\n```\n\n' return ret + '```asn1\n' + re.sub(r'^\s*--.*\n', '', m.group(1).strip(), 0, re.MULTILINE) +'\n```\n\n' pos = 0 for m in RE_TYPE.finditer(content[cpos:]): Loading @@ -153,13 +131,14 @@ def parseAsn(outDir, content) : RE_MODULE=re.compile(r'^\s*([A-Z][\w-]*)\s*({.*?})?\s*DEFINITIONS.*?::=\s*?BEGIN(.*)END', re.VERBOSE | re.MULTILINE | re.DOTALL) cnt = 0 for m in RE_MODULE.finditer(content): ret = '# ASN.1 module {}\n OID: _{}_\n'.format(m[1], re.sub(r'\s+', ' ', m[2])) ret = '# ASN.1 module {}\n OID: _{}_\n'.format(m.group(1), re.sub(r'\s+', ' ', m.group(2))) ret += parseText(content[pos:m.start()]) + '\n' if m[3] is not None: ret += parseModule(m[1], m[3]) if m.group(3) is not None: ret += parseModule(m.group(1), m.group(3)) ret += '\n\n' open(outDir + '/' + m[1] + '.md', "w").write(ret) open(outDir + '/' + m.group(1) + '.md', "w").write(ret) pos = m.end() cnt += 1 return cnt def main(): Loading Loading
asn2md.py +21 −42 Original line number Diff line number Diff line #!/usr/bin/env python # -*- coding: utf-8 -*- # asn1-doxygen-filter is an extension to the Doxygen utility for creating # documents from ASN.1 files # # Copyright 2017 OnBoard Security, Inc. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUTNOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE ANDNONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import argparse # parse arguments import os.path # getting extension from file Loading Loading @@ -75,12 +53,12 @@ def parseText(content, indent=None): content = c ret = '' for m in RE_DOXY_C_COMMENTS.finditer(content): lines = m[1].splitlines() lines = m.group(1).splitlines() for l in lines: l = re.sub(r'\s*\*', '', l, 1).rstrip() ret += ''.ljust(indent or 0) + l + '\n' def repl_ref(m): return '[**{0}**]({1}#{0})'.format(m[1], extTypes.get(m[1],'')) return '[**{0}**]({1}#{0})'.format(m.group(1), extTypes.get(m.group(1),'')) c = re.sub(r'@ref\s+([\w-]+)', repl_ref, ret, 0, re.VERBOSE | re.MULTILINE) if c is not None: ret = c Loading @@ -99,14 +77,14 @@ def parseModule(mname, content): m = re.search(r'^\s*IMPORTS\s*(.*?);', content, re.VERBOSE | re.DOTALL | re.MULTILINE) if m is not None: pos = 0 if m[1] is not None: if m.group(1) is not None: ret += '## Imports:\n' s = m[1] s = m.group(1) for fm in re.finditer(r'^([,\s\w-]*?)FROM\s*([\w-]+)\s*({[^}]*}(?:\s+WITH\s+SUCCESSORS)?)?', s, re.VERBOSE | re.MULTILINE): imName = fm[2] for im in re.finditer(r'[^,\s]+', fm[1], 0): imName = fm.group(2) for im in re.finditer(r'[^,\s]+', fm.group(1), 0): extTypes[im[0]] = imName+'.md' ret += ' * **{}** *{}*<br/>\n'.format(imName, re.sub(r'\s+', ' ', fm[3] or '', 0, 0)) ret += ' * **{}** *{}*<br/>\n'.format(imName, re.sub(r'\s+', ' ', fm.group(3) or '', 0, 0)) ret += parseText(s[pos:fm.start()], 3)+'\n' pos = fm.end() ret += parseText(s[pos:]) Loading @@ -119,25 +97,25 @@ def parseModule(mname, content): # parse types def repl_type (m, doc): ret = '## <a name="{0}"></a>{0}\n\n'.format(m[2]) ret = '## <a name="{0}"></a>{0}\n\n'.format(m.group(2)) if doc is not None: ret += parseText(doc) + '\n\n' # parse fields and get out fields descriptions if m[3] is not None: if m.group(3) is not None: ret += 'Fields:\n' pos = 0 for fm in re.finditer('^\s*([\w-]+?)\s+(OCTET\s+STRING|BIT\s+STRING|[A-Z][.\w-]+)?(.*?)(?:,|$)', m[3], re.VERBOSE | re.MULTILINE | re.DOTALL): if fm[2] is not None: f = fm[1].strip() t = fm[2].strip() for fm in re.finditer('^\s*([\w-]+?)\s+(OCTET\s+STRING|BIT\s+STRING|[A-Z][.\w-]+)?(.*?)(?:,|$)', m.group(3), re.VERBOSE | re.MULTILINE | re.DOTALL): if fm.group(2) is not None: f = fm.group(1).strip() t = fm.group(2).strip() if re.match('^OCTET\s+STRING|BIT\s+STRING|BOOLEAN|INTEGER|FLOAT', t, re.VERBOSE|re.MULTILINE) is not None: ret += '* {0} **{1}** {2}<br>\n'.format(f, t, fm[3] or '') ret += '* {0} **{1}** {2}<br>\n'.format(f, t, fm.group(3) or '') else: ret += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), fm[3] or '') ret += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), fm.group(3) or '') ret += parseText(fm.string[pos:fm.start()], 3) pos = fm.end() return ret + '```asn1\n' + re.sub(r'^\s*--.*\n', '', m[1].strip(), 0, re.MULTILINE) +'\n```\n\n' return ret + '```asn1\n' + re.sub(r'^\s*--.*\n', '', m.group(1).strip(), 0, re.MULTILINE) +'\n```\n\n' pos = 0 for m in RE_TYPE.finditer(content[cpos:]): Loading @@ -153,13 +131,14 @@ def parseAsn(outDir, content) : RE_MODULE=re.compile(r'^\s*([A-Z][\w-]*)\s*({.*?})?\s*DEFINITIONS.*?::=\s*?BEGIN(.*)END', re.VERBOSE | re.MULTILINE | re.DOTALL) cnt = 0 for m in RE_MODULE.finditer(content): ret = '# ASN.1 module {}\n OID: _{}_\n'.format(m[1], re.sub(r'\s+', ' ', m[2])) ret = '# ASN.1 module {}\n OID: _{}_\n'.format(m.group(1), re.sub(r'\s+', ' ', m.group(2))) ret += parseText(content[pos:m.start()]) + '\n' if m[3] is not None: ret += parseModule(m[1], m[3]) if m.group(3) is not None: ret += parseModule(m.group(1), m.group(3)) ret += '\n\n' open(outDir + '/' + m[1] + '.md', "w").write(ret) open(outDir + '/' + m.group(1) + '.md', "w").write(ret) pos = m.end() cnt += 1 return cnt def main(): Loading