gpt4 book ai didi

python - C/Python 中的 asn.1 解析器

转载 作者:太空狗 更新时间:2023-10-29 17:41:02 26 4
gpt4 key购买 nike

我正在寻找解析 asn.1 规范文件并从中生成解码器的解决方案。

理想情况下,我想使用 Python 模块,但如果没有可用的,我会使用 C/C++ 库并将它们与 Python 接口(interface),并提供大量解决方案。

过去我一直在使用 pyasn1 并手动构建所有内容,但这变得太笨拙了。

我还粗略地查看了 libtasn1 和 asn1c。第一个即使是最简单的文件也无法解析。第二个有一个很好的解析器,但是生成用于解码的 C 代码似乎太复杂了;该解决方案适用于简单的规范,但适用于复杂的规范。

我可能忽略了任何其他好的选择吗?

最佳答案

几年前我写了这样的解析器。它为 pyasn1 库生成 python 类。我在爱立信文档中使用过为他们的 CDR 制作解析器。

我会尝试在这里发布代码。

import sys
from pyparsing import *

OpenBracket = Regex("[({]").suppress()
CloseBracket = Regex("[)}]").suppress()

def Enclose(val):
return OpenBracket + val + CloseBracket

def SetDefType(typekw):
def f(a, b, c):
c["defType"] = typekw
return f

def NoDashes(a, b, c):
return c[0].replace("-", "_")

def DefineTypeDef(typekw, typename, typedef):
return typename.addParseAction(SetDefType(typekw)).setResultsName("definitionType") - \
Optional(Enclose(typedef).setResultsName("definition"))



SizeConstraintBodyOpt = Word(nums).setResultsName("minSize") - \
Optional(Suppress(Literal("..")) - Word(nums + "n").setResultsName("maxSize"))

SizeConstraint = Group(Keyword("SIZE").suppress() - Enclose(SizeConstraintBodyOpt)).setResultsName("sizeConstraint")

Constraints = Group(delimitedList(SizeConstraint)).setResultsName("constraints")

DefinitionBody = Forward()

TagPrefix = Enclose(Word(nums).setResultsName("tagID")) - Keyword("IMPLICIT").setResultsName("tagFormat")

OptionalSuffix = Optional(Keyword("OPTIONAL").setResultsName("isOptional"))
JunkPrefix = Optional("--F--").suppress()
AName = Word(alphanums + "-").setParseAction(NoDashes).setResultsName("name")

SingleElement = Group(JunkPrefix - AName - Optional(TagPrefix) - DefinitionBody.setResultsName("typedef") - OptionalSuffix)

NamedTypes = Dict(delimitedList(SingleElement)).setResultsName("namedTypes")

SetBody = DefineTypeDef("Set", Keyword("SET"), NamedTypes)
SequenceBody = DefineTypeDef("Sequence", Keyword("SEQUENCE"), NamedTypes)
ChoiceBody = DefineTypeDef("Choice", Keyword("CHOICE"), NamedTypes)

SetOfBody = (Keyword("SET") + Optional(SizeConstraint) + Keyword("OF")).setParseAction(SetDefType("SetOf")) + Group(DefinitionBody).setResultsName("typedef")
SequenceOfBody = (Keyword("SEQUENCE") + Optional(SizeConstraint) + Keyword("OF")).setParseAction(SetDefType("SequenceOf")) + Group(DefinitionBody).setResultsName("typedef")

CustomBody = DefineTypeDef("constructed", Word(alphanums + "-").setParseAction(NoDashes), Constraints)
NullBody = DefineTypeDef("Null", Keyword("NULL"), Constraints)

OctetStringBody = DefineTypeDef("OctetString", Regex("OCTET STRING"), Constraints)
IA5StringBody = DefineTypeDef("IA5String", Keyword("IA5STRING"), Constraints)

EnumElement = Group(Word(printables).setResultsName("name") - Enclose(Word(nums).setResultsName("value")))
NamedValues = Dict(delimitedList(EnumElement)).setResultsName("namedValues")
EnumBody = DefineTypeDef("Enum", Keyword("ENUMERATED"), NamedValues)

BitStringBody = DefineTypeDef("BitString", Keyword("BIT") + Keyword("STRING"), NamedValues)

DefinitionBody << (OctetStringBody | SetOfBody | SetBody | ChoiceBody | SequenceOfBody | SequenceBody | EnumBody | BitStringBody | IA5StringBody | NullBody | CustomBody)

Definition = AName - Literal("::=").suppress() - Optional(TagPrefix) - DefinitionBody

Definitions = Dict(ZeroOrMore(Group(Definition)))

pf = Definitions.parseFile(sys.argv[1])

TypeDeps = {}
TypeDefs = {}

def SizeConstraintHelper(size):
s2 = s1 = size.get("minSize")
s2 = size.get("maxSize", s2)
try:
return("constraint.ValueSizeConstraint(%s, %s)" % (int(s1), int(s2)))
except ValueError:
pass

ConstraintMap = {
'sizeConstraint' : SizeConstraintHelper,
}

def ConstraintHelper(c):
result = []
for key, value in c.items():
r = ConstraintMap[key](value)
if r:
result.append(r)
return result

def GenerateConstraints(c, ancestor, element, level=1):
result = ConstraintHelper(c)
if result:
return [ "subtypeSpec = %s" % " + ".join(["%s.subtypeSpec" % ancestor] + result) ]
return []

def GenerateNamedValues(definitions, ancestor, element, level=1):
result = [ "namedValues = namedval.NamedValues(" ]
for kw in definitions:
result.append(" ('%s', %s)," % (kw["name"], kw["value"]))
result.append(")")
return result

OptMap = {
False: "",
True: "Optional",
}

def GenerateNamedTypesList(definitions, element, level=1):
result = []
for val in definitions:
name = val["name"]
typename = None

isOptional = bool(val.get("isOptional"))

subtype = []
constraints = val.get("constraints")
if constraints:
cg = ConstraintHelper(constraints)
subtype.append("subtypeSpec=%s" % " + ".join(cg))
tagId = val.get("tagID")
if tagId:
subtype.append("implicitTag=tag.Tag(tag.tagClassContext, tag.tagFormatConstructed, %s)" % tagId)

if subtype:
subtype = ".subtype(%s)" % ", ".join(subtype)
else:
subtype = ""

cbody = []
if val["defType"] == "constructed":
typename = val["typedef"]
element["_d"].append(typename)
elif val["defType"] == "Null":
typename = "univ.Null"
elif val["defType"] == "SequenceOf":
typename = "univ.SequenceOf"
print val.items()
cbody = [ " componentType=%s()" % val["typedef"]["definitionType"] ]
elif val["defType"] == "Choice":
typename = "univ.Choice"
indef = val.get("definition")
if indef:
cbody = [ " %s" % x for x in GenerateClassDefinition(indef, name, typename, element) ]
construct = [ "namedtype.%sNamedType('%s', %s(" % (OptMap[isOptional], name, typename), ")%s)," % subtype ]
if not cbody:
result.append("%s%s%s" % (" " * level, construct[0], construct[1]))
else:
result.append(" %s" % construct[0])
result.extend(cbody)
result.append(" %s" % construct[1])
return result



def GenerateNamedTypes(definitions, ancestor, element, level=1):
result = [ "componentType = namedtype.NamedTypes(" ]
result.extend(GenerateNamedTypesList(definitions, element))
result.append(")")
return result


defmap = {
'constraints' : GenerateConstraints,
'namedValues' : GenerateNamedValues,
'namedTypes' : GenerateNamedTypes,
}

def GenerateClassDefinition(definition, name, ancestor, element, level=1):
result = []
for defkey, defval in definition.items():
if defval:
fn = defmap.get(defkey)
if fn:
result.extend(fn(defval, ancestor, element, level))
return [" %s" % x for x in result]

def GenerateClass(element, ancestor):
name = element["name"]

top = "class %s(%s):" % (name, ancestor)
definition = element.get("definition")
body = []
if definition:
body = GenerateClassDefinition(definition, name, ancestor, element)
else:
typedef = element.get("typedef")
if typedef:
element["_d"].append(typedef["definitionType"])
body.append(" componentType = %s()" % typedef["definitionType"])
szc = element.get('sizeConstraint')
if szc:
body.extend(GenerateConstraints({ 'sizeConstraint' : szc }, ancestor, element))

if not body:
body.append(" pass")

TypeDeps[name] = list(frozenset(element["_d"]))

return "\n".join([top] + body)

StaticMap = {
"Null" : "univ.Null",
"Enum" : "univ.Enumerated",
"OctetString" : "univ.OctetString",
"IA5String" : "char.IA5String",
"Set" : "univ.Set",
"Sequence" : "univ.Sequence",
"Choice" : "univ.Choice",
"SetOf" : "univ.SetOf",
"BitString" : "univ.BitString",
"SequenceOf" : "univ.SequenceOf",
}

def StaticConstructor(x):
x["_d"] = []
if x["defType"] == "constructed":
dt = x["definitionType"]
x["_d"].append(dt)
else:
dt = StaticMap[x["defType"]]
return GenerateClass(x, dt)


for element in pf:
TypeDefs[element["name"]] = StaticConstructor(element)

while TypeDefs:
ready = [ k for k, v in TypeDeps.items() if len(v) == 0 ]
if not ready:
x = list()
for a in TypeDeps.values():
x.extend(a)
x = frozenset(x) - frozenset(TypeDeps.keys())

print TypeDefs

raise ValueError, sorted(x)

for t in ready:
for v in TypeDeps.values():
try:
v.remove(t)
except ValueError:
pass

del TypeDeps[t]
print TypeDefs[t]
print
print

del TypeDefs[t]

这将获取一个语法类似于这个的文件:

CarrierInfo ::= OCTET STRING (SIZE(2..3))
ChargeAreaCode ::= OCTET STRING (SIZE(3))
ChargeInformation ::= OCTET STRING (SIZE(2..33))
ChargedParty ::= ENUMERATED

(chargingOfCallingSubscriber (0),
chargingOfCalledSubscriber (1),
noCharging (2))
ChargingOrigin ::= OCTET STRING (SIZE(1))
Counter ::= OCTET STRING (SIZE(1..4))
Date ::= OCTET STRING (SIZE(3..4))

您需要在生成的文件顶部添加这一行:

from pyasn1.type import univ, namedtype, namedval, constraint, tag, char

并将结果命名为 defs.py。然后,我将一堆 pretty-print 附加到 defs(如果你没有跳过它)

import defs, parsers

def rplPrettyOut(self, value):
return repr(self.decval(value))

for name in dir(parsers):
if (not name.startswith("_")) and hasattr(defs, name):
target = getattr(defs, name)
target.prettyOut = rplPrettyOut
target.decval = getattr(parsers, name)

然后,归结为:

  def ParseBlock(self, block):
while block and block[0] != '\x00':
result, block = pyasn1.codec.ber.decoder.decode(block, asn1Spec=parserimp.defs.CallDataRecord())
yield result

如果您仍然感兴趣,我会将代码放在某处。事实上,无论如何我都会把它放在某个地方 - 但如果您有兴趣,请告诉我,我会指出您的位置。

关于python - C/Python 中的 asn.1 解析器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1494372/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com