def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is None: substrate = value.asOctets() elif not isOctetsType(value): substrate = asn1Spec.clone(value).asOctets() else: substrate = value maxChunkSize = options.get('maxChunkSize', 0) if not maxChunkSize or len(substrate) <= maxChunkSize: return substrate, False, True if LOG: LOG('encoding into up to %s-octet chunks' % maxChunkSize) # strip off explicit tags for inner chunks if asn1Spec is None: baseTag = value.tagSet.baseTag # strip off explicit tags if baseTag: tagSet = tag.TagSet(baseTag, baseTag) else: tagSet = tag.TagSet() asn1Spec = value.clone(tagSet=tagSet) elif not isOctetsType(value): baseTag = asn1Spec.tagSet.baseTag # strip off explicit tags if baseTag: tagSet = tag.TagSet(baseTag, baseTag) else: tagSet = tag.TagSet() asn1Spec = asn1Spec.clone(tagSet=tagSet) pos = 0 substrate = null while True: chunk = value[pos:pos + maxChunkSize] if not chunk: break substrate += encodeFun(chunk, asn1Spec, **options) pos += maxChunkSize return substrate, True, True
def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is None: substrate = value.asOctets() elif not isOctetsType(value): substrate = asn1Spec.clone(value).asOctets() else: substrate = value maxChunkSize = options.get('maxChunkSize', 0) if not maxChunkSize or len(substrate) <= maxChunkSize: return substrate, False, True if LOG: LOG('encoding into up to %s-octet chunks' % maxChunkSize) # strip off explicit tags for inner chunks if asn1Spec is None: baseTag = value.tagSet.baseTag # strip off explicit tags if baseTag: tagSet = tag.TagSet(baseTag, baseTag) else: tagSet = tag.TagSet() asn1Spec = value.clone(tagSet=tagSet) elif not isOctetsType(value): baseTag = asn1Spec.tagSet.baseTag # strip off explicit tags if baseTag: tagSet = tag.TagSet(baseTag, baseTag) else: tagSet = tag.TagSet() asn1Spec = asn1Spec.clone(tagSet=tagSet) pos = 0 substrate = null while True: chunk = value[pos:pos + maxChunkSize] if not chunk: break substrate += encodeFun(chunk, asn1Spec, **options) pos += maxChunkSize return substrate, True, True
def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is None: value = value.asOctets() elif not isOctetsType(value): value = asn1Spec.clone(value).asOctets() return value, not options.get('defMode', True), True
def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is None: # will strip off explicit tags tagSet = value.tagSet asn1Spec = value.clone( tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag)) value = value.asOctets() elif not isOctetsType(value): # will strip off explicit tags tagSet = asn1Spec.tagSet asn1Spec = asn1Spec.clone( tagSet=tag.TagSet(tagSet.baseTag, tagSet.baseTag)) value = asn1Spec.clone(value).asOctets() maxChunkSize = options.get('maxChunkSize', 0) if not maxChunkSize or len(value) <= maxChunkSize: return value, False, True else: pos = 0 substrate = null while True: chunk = value[pos:pos + maxChunkSize] if not chunk: break substrate += encodeFun(chunk, asn1Spec, **options) pos += maxChunkSize return substrate, True, True
def encodeValue(self, value, asn1Spec, encodeFun, **options): if asn1Spec is None: value = value.asOctets() elif not isOctetsType(value): value = asn1Spec.clone(value).asOctets() return value, not options.get('defMode', True), True
def evaluateValue(self, oid, tag, value, **context): tag, encodingId = self.unpackTag(tag) try: if encodingId == 'e': value = self.evaluateRawString(value) return oid, tag, self.grammar.TAG_MAP[tag](value) elif encodingId == 'x': if octets.isOctetsType(value): value = octets.octs2str(value) return oid, tag, self.grammar.TAG_MAP[tag](hexValue=value) else: return oid, tag, self.grammar.TAG_MAP[tag](value) except Exception: raise error.SnmpsimError( 'value evaluation error for tag %r, value ' '%r: %s' % (tag, value, sys.exc_info()[1]))
def evaluate_value(self, oid, tag, value, **context): tag, encoding_id = self.unpack_tag(tag) try: if encoding_id == 'e': value = self.evaluate_raw_string(value) return oid, tag, self.grammar.TAG_MAP[tag](value) elif encoding_id == 'x': if octets.isOctetsType(value): value = octets.octs2str(value) return oid, tag, self.grammar.TAG_MAP[tag](hexValue=value) else: return oid, tag, self.grammar.TAG_MAP[tag](value) except Exception as exc: raise error.SnmpsimError( 'value evaluation error for tag %r, value ' '%r: %s' % (tag, value, exc))
def evaluateValue(self, oid, tag, value, **context): tag, encodingId = self.unpackTag(tag) try: if encodingId == 'e': value = self.evaluateRawString(value) return oid, tag, self.grammar.TAG_MAP[tag](value) elif encodingId == 'x': if octets.isOctetsType(value): value = octets.octs2str(value) return oid, tag, self.grammar.TAG_MAP[tag](hexValue=value) else: return oid, tag, self.grammar.TAG_MAP[tag](value) except Exception: raise error.SnmpsimError( 'value evaluation error for tag %r, value ' '%r: %s' % (tag, value, sys.exc_info()[1]))
def prettyIn(self, value): # override asn1 type method """Implements DISPLAY-HINT parsing into base SNMP value Proper parsing seems impossible due to ambiguities. Here we are trying to do our best, but be prepared for failures on complicated DISPLAY-HINTs. Keep in mind that this parser only works with "text" input meaning `unicode` (Py2) or `str` (Py3). """ for base in inspect.getmro(self.__class__): if not issubclass(base, TextualConvention) and issubclass( base, Asn1Item): break else: raise SmiError( 'TEXTUAL-CONVENTION has no underlying SNMP base type') if self.displayHint and ( self.__integer.isSuperTypeOf(self, matchConstraints=False) and self.getNamedValues() or self.__unsigned32.isSuperTypeOf( self, matchConstraints=False) or self.__timeticks.isSuperTypeOf(self, matchConstraints=False)): value = str(value) _ = lambda t, f=0: (t, f) displayHintType, decimalPrecision = _(*self.displayHint.split('-')) if displayHintType == 'x' and (value.startswith('0x') or value.startswith('-0x')): try: if value.startswith('-'): return base.prettyIn(self, -int(value[3:], 16)) else: return base.prettyIn(self, int(value[2:], 16)) except Exception: raise SmiError('integer evaluation error: %s' % sys.exc_info()[1]) elif displayHintType == 'd': try: return base.prettyIn( self, int(float(value) * 10**int(decimalPrecision))) except Exception: raise SmiError('float evaluation error: %s' % sys.exc_info()[1]) elif displayHintType == 'o' and (value.startswith('0') or value.startswith('-0')): try: return base.prettyIn(self, int(value, 8)) except Exception: raise SmiError('octal evaluation error: %s' % sys.exc_info()[1]) elif displayHintType == 'b' and (value.startswith('B') or value.startswith('-B')): negative = value.startswith('-') if negative: value = value[2:] else: value = value[1:] value = [x != '0' and 1 or 0 for x in value] binValue = 0 while value: binValue <<= value[0] del value[0] return base.prettyIn(self, binValue) else: raise SmiError('Unsupported numeric type spec "%s" at %s' % (displayHintType, self.__class__.__name__)) elif self.displayHint and self.__octetString.isSuperTypeOf( self, matchConstraints=False): numBase = {'x': 16, 'd': 10, 'o': 8} numDigits = { 'x': octets.str2octs(string.hexdigits), 'o': octets.str2octs(string.octdigits), 'd': octets.str2octs(string.digits) } # how do we know if object is initialized with display-hint # formatted text? based on "text" input maybe? # That boils down to `str` object on Py3 or `unicode` on Py2. if octets.isStringType(value) and not octets.isOctetsType(value): value = base.prettyIn(self, value) else: return base.prettyIn(self, value) outputValue = octets.str2octs('') runningValue = value displayHint = self.displayHint while runningValue and displayHint: # 1 this information is totally lost, just fail explicitly if displayHint[0] == '*': raise SmiError('Can\'t parse "*" in DISPLAY-HINT (%s)' % self.__class__.__name__) # 2 this becomes ambiguous when it comes to rendered value octetLength = '' while displayHint and displayHint[0] in string.digits: octetLength += displayHint[0] displayHint = displayHint[1:] # length is mandatory but people ignore that if not octetLength: octetLength = len(runningValue) try: octetLength = int(octetLength) except Exception: raise SmiError('Bad octet length: %s' % octetLength) if not displayHint: raise SmiError('Short octet length: %s' % self.displayHint) # 3 displayFormat = displayHint[0] displayHint = displayHint[1:] # 4 this is the lifesaver -- we could use it as an anchor if displayHint and displayHint[ 0] not in string.digits and displayHint[0] != '*': displaySep = displayHint[0] displayHint = displayHint[1:] else: displaySep = '' # 5 is probably impossible to support if displayFormat in ('a', 't'): outputValue += runningValue[:octetLength] elif displayFormat in numBase: if displaySep: guessedOctetLength = runningValue.find( octets.str2octs(displaySep)) if guessedOctetLength == -1: guessedOctetLength = len(runningValue) else: for idx in range(len(runningValue)): if runningValue[idx] not in numDigits[ displayFormat]: guessedOctetLength = idx break else: guessedOctetLength = len(runningValue) try: num = int( octets.octs2str(runningValue[:guessedOctetLength]), numBase[displayFormat]) except Exception: raise SmiError('Display format eval failure: %s: %s' % (runningValue[:guessedOctetLength], sys.exc_info()[1])) num_as_bytes = [] if num: while num: num_as_bytes.append(num & 0xFF) num >>= 8 else: num_as_bytes = [0] while len(num_as_bytes) < octetLength: num_as_bytes.append(0) num_as_bytes.reverse() outputValue += octets.ints2octs(num_as_bytes) if displaySep: guessedOctetLength += 1 octetLength = guessedOctetLength else: raise SmiError('Unsupported display format char: %s' % displayFormat) runningValue = runningValue[octetLength:] if not displayHint: displayHint = self.displayHint return base.prettyIn(self, outputValue) else: return base.prettyIn(self, value)
def __call__(self, substrate, asn1Spec=None, tagSet=None, length=None, state=stDecodeTag, recursiveFlag=1, substrateFun=None, allowEoo=False): if debug.logger & debug.flagDecoder: debug.logger('decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) if asn1Spec is not None and not isinstance(asn1Spec, (base.Asn1Item, tagmap.TagMap)): raise error.PyAsn1Error('asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__) fullSubstrate = substrate while state != stStop: if state == stDecodeTag: if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on tag decoding' ) if not isOctetsType(substrate) and \ not isinstance(substrate, univ.OctetString): raise error.PyAsn1Error('Bad octet stream type') # Decode tag firstOctet = substrate[0] substrate = substrate[1:] if firstOctet in self.__tagCache: lastTag = self.__tagCache[firstOctet] else: t = oct2int(firstOctet) # Look for end-of-octets sentinel if t == 0: if substrate and oct2int(substrate[0]) == 0: if allowEoo and self.supportIndefLength: debug.logger and debug.logger & debug.flagDecoder and debug.logger('end-of-octets sentinel found') value, substrate = eoo.endOfOctets, substrate[1:] state = stStop continue else: raise error.PyAsn1Error('Unexpected end-of-contents sentinel') else: raise error.PyAsn1Error('Zero tag encountered') tagClass = t&0xC0 tagFormat = t&0x20 tagId = t&0x1F if tagId == 0x1F: tagId = 0 while 1: if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on long tag decoding' ) t = oct2int(substrate[0]) tagId = tagId << 7 | (t&0x7F) substrate = substrate[1:] if not t&0x80: break lastTag = tag.Tag( tagClass=tagClass, tagFormat=tagFormat, tagId=tagId ) if tagId < 31: # cache short tags self.__tagCache[firstOctet] = lastTag if tagSet is None: if firstOctet in self.__tagSetCache: tagSet = self.__tagSetCache[firstOctet] else: # base tag not recovered tagSet = tag.TagSet((), lastTag) if firstOctet in self.__tagCache: self.__tagSetCache[firstOctet] = tagSet else: tagSet = lastTag + tagSet state = stDecodeLength debug.logger and debug.logger & debug.flagDecoder and debug.logger('tag decoded into %s, decoding length' % tagSet) if state == stDecodeLength: # Decode length if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on length decoding' ) firstOctet = oct2int(substrate[0]) if firstOctet == 128: size = 1 length = -1 elif firstOctet < 128: length, size = firstOctet, 1 else: size = firstOctet & 0x7F # encoded in size bytes length = 0 lengthString = substrate[1:size+1] # missing check on maximum size, which shouldn't be a # problem, we can handle more than is possible if len(lengthString) != size: raise error.SubstrateUnderrunError( '%s<%s at %s' % (size, len(lengthString), tagSet) ) for char in lengthString: length = (length << 8) | oct2int(char) size += 1 substrate = substrate[size:] if length != -1 and len(substrate) < length: raise error.SubstrateUnderrunError( '%d-octet short' % (length - len(substrate)) ) if length == -1 and not self.supportIndefLength: error.PyAsn1Error('Indefinite length encoding not supported by this codec') state = stGetValueDecoder debug.logger and debug.logger & debug.flagDecoder and debug.logger('value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length]))) if state == stGetValueDecoder: if asn1Spec is None: state = stGetValueDecoderByTag else: state = stGetValueDecoderByAsn1Spec # # There're two ways of creating subtypes in ASN.1 what influences # decoder operation. These methods are: # 1) Either base types used in or no IMPLICIT tagging has been # applied on subtyping. # 2) Subtype syntax drops base type information (by means of # IMPLICIT tagging. # The first case allows for complete tag recovery from substrate # while the second one requires original ASN.1 type spec for # decoding. # # In either case a set of tags (tagSet) is coming from substrate # in an incremental, tag-by-tag fashion (this is the case of # EXPLICIT tag which is most basic). Outermost tag comes first # from the wire. # if state == stGetValueDecoderByTag: if tagSet in self.__tagMap: concreteDecoder = self.__tagMap[tagSet] else: concreteDecoder = None if concreteDecoder: state = stDecodeValue else: _k = tagSet[:1] if _k in self.__tagMap: concreteDecoder = self.__tagMap[_k] else: concreteDecoder = None if concreteDecoder: state = stDecodeValue else: state = stTryAsExplicitTag if debug.logger and debug.logger & debug.flagDecoder: debug.logger('codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag')) debug.scope.push(concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) if state == stGetValueDecoderByAsn1Spec: if isinstance(asn1Spec, (dict, tagmap.TagMap)): if tagSet in asn1Spec: __chosenSpec = asn1Spec[tagSet] else: __chosenSpec = None if debug.logger and debug.logger & debug.flagDecoder: debug.logger('candidate ASN.1 spec is a map of:') for t, v in asn1Spec.getPosMap().items(): debug.logger(' %s -> %s' % (t, v.__class__.__name__)) if asn1Spec.getNegMap(): debug.logger('but neither of: ') for t, v in asn1Spec.getNegMap().items(): debug.logger(' %s -> %s' % (t, v.__class__.__name__)) debug.logger('new candidate ASN.1 spec is %s, chosen by %s' % (__chosenSpec is None and '<none>' or __chosenSpec.prettyPrintType(), tagSet)) else: __chosenSpec = asn1Spec debug.logger and debug.logger & debug.flagDecoder and debug.logger('candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) if __chosenSpec is not None and ( tagSet == __chosenSpec.getTagSet() or \ tagSet in __chosenSpec.getTagMap() ): # use base type for codec lookup to recover untagged types baseTagSet = __chosenSpec.baseTagSet if __chosenSpec.typeId is not None and \ __chosenSpec.typeId in self.__typeMap: # ambiguous type concreteDecoder = self.__typeMap[__chosenSpec.typeId] debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId,)) elif baseTagSet in self.__tagMap: # base type or tagged subtype concreteDecoder = self.__tagMap[baseTagSet] debug.logger and debug.logger & debug.flagDecoder and debug.logger('value decoder chosen by base %s' % (baseTagSet,)) else: concreteDecoder = None if concreteDecoder: asn1Spec = __chosenSpec state = stDecodeValue else: state = stTryAsExplicitTag else: concreteDecoder = None state = stTryAsExplicitTag if debug.logger and debug.logger & debug.flagDecoder: debug.logger('codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag')) debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__) if state == stTryAsExplicitTag: if tagSet and \ tagSet[0][1] == tag.tagFormatConstructed and \ tagSet[0][0] != tag.tagClassUniversal: # Assume explicit tagging concreteDecoder = explicitTagDecoder state = stDecodeValue else: concreteDecoder = None state = self.defaultErrorState debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as failure')) if state == stDumpRawValue: concreteDecoder = self.defaultRawDecoder debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) state = stDecodeValue if state == stDecodeValue: if recursiveFlag == 0 and not substrateFun: # legacy substrateFun = lambda a,b,c: (a,b[:c]) if length == -1: # indef length value, substrate = concreteDecoder.indefLenValueDecoder( fullSubstrate, substrate, asn1Spec, tagSet, length, stGetValueDecoder, self, substrateFun ) else: value, substrate = concreteDecoder.valueDecoder( fullSubstrate, substrate, asn1Spec, tagSet, length, stGetValueDecoder, self, substrateFun ) state = stStop debug.logger and debug.logger & debug.flagDecoder and debug.logger('codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>')) if state == stErrorCondition: raise error.PyAsn1Error( '%s not in asn1Spec: %s' % (tagSet, asn1Spec) ) if debug.logger and debug.logger & debug.flagDecoder: debug.scope.pop() debug.logger('decoder left scope %s, call completed' % debug.scope) return value, substrate
def test_isOctetsType(self): assert octets.isOctetsType('abc') == True assert octets.isOctetsType(123) == False assert octets.isOctetsType(unicode('abc')) == False
def test_isOctetsType(self): assert octets.isOctetsType('abc') == False assert octets.isOctetsType(123) == False assert octets.isOctetsType(bytes()) == True
def __call__(self, substrate, asn1Spec=None, tagSet=None, length=None, state=stDecodeTag, recursiveFlag=1, substrateFun=None, allowEoo=False): if debug.logger & debug.flagDecoder: debug.logger( 'decoder called at scope %s with state %d, working with up to %d octets of substrate: %s' % (debug.scope, state, len(substrate), debug.hexdump(substrate))) if asn1Spec is not None and not isinstance( asn1Spec, (base.Asn1Item, tagmap.TagMap)): raise error.PyAsn1Error( 'asn1Spec is not valid (should be an instance of an ASN.1 Item, not %s)' % asn1Spec.__class__.__name__) value = base.noValue fullSubstrate = substrate while state != stStop: if state == stDecodeTag: if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on tag decoding') if not isOctetsType(substrate) and \ not isinstance(substrate, univ.OctetString): raise error.PyAsn1Error('Bad octet stream type') # Decode tag firstOctet = substrate[0] substrate = substrate[1:] if firstOctet in self.__tagCache: lastTag = self.__tagCache[firstOctet] else: t = oct2int(firstOctet) # Look for end-of-octets sentinel if t == 0: if substrate and oct2int(substrate[0]) == 0: if allowEoo and self.supportIndefLength: debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'end-of-octets sentinel found') value, substrate = eoo.endOfOctets, substrate[ 1:] state = stStop continue else: raise error.PyAsn1Error( 'Unexpected end-of-contents sentinel') else: raise error.PyAsn1Error('Zero tag encountered') tagClass = t & 0xC0 tagFormat = t & 0x20 tagId = t & 0x1F short = True if tagId == 0x1F: short = False tagId = 0 while True: if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on long tag decoding') t = oct2int(substrate[0]) tagId = tagId << 7 | (t & 0x7F) substrate = substrate[1:] if not t & 0x80: break lastTag = tag.Tag(tagClass=tagClass, tagFormat=tagFormat, tagId=tagId) if short: # cache short tags self.__tagCache[firstOctet] = lastTag if tagSet is None: if firstOctet in self.__tagSetCache: tagSet = self.__tagSetCache[firstOctet] else: # base tag not recovered tagSet = tag.TagSet((), lastTag) if firstOctet in self.__tagCache: self.__tagSetCache[firstOctet] = tagSet else: tagSet = lastTag + tagSet state = stDecodeLength debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'tag decoded into %s, decoding length' % tagSet) if state == stDecodeLength: # Decode length if not substrate: raise error.SubstrateUnderrunError( 'Short octet stream on length decoding') firstOctet = oct2int(substrate[0]) if firstOctet == 128: size = 1 length = -1 elif firstOctet < 128: length, size = firstOctet, 1 else: size = firstOctet & 0x7F # encoded in size bytes length = 0 lengthString = substrate[1:size + 1] # missing check on maximum size, which shouldn't be a # problem, we can handle more than is possible if len(lengthString) != size: raise error.SubstrateUnderrunError( '%s<%s at %s' % (size, len(lengthString), tagSet)) for char in lengthString: length = (length << 8) | oct2int(char) size += 1 substrate = substrate[size:] if length != -1 and len(substrate) < length: raise error.SubstrateUnderrunError( '%d-octet short' % (length - len(substrate))) if length == -1 and not self.supportIndefLength: error.PyAsn1Error( 'Indefinite length encoding not supported by this codec' ) state = stGetValueDecoder debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'value length decoded into %d, payload substrate is: %s' % (length, debug.hexdump(length == -1 and substrate or substrate[:length]))) if state == stGetValueDecoder: if asn1Spec is None: state = stGetValueDecoderByTag else: state = stGetValueDecoderByAsn1Spec # # There're two ways of creating subtypes in ASN.1 what influences # decoder operation. These methods are: # 1) Either base types used in or no IMPLICIT tagging has been # applied on subtyping. # 2) Subtype syntax drops base type information (by means of # IMPLICIT tagging. # The first case allows for complete tag recovery from substrate # while the second one requires original ASN.1 type spec for # decoding. # # In either case a set of tags (tagSet) is coming from substrate # in an incremental, tag-by-tag fashion (this is the case of # EXPLICIT tag which is most basic). Outermost tag comes first # from the wire. # if state == stGetValueDecoderByTag: if tagSet in self.__tagMap: concreteDecoder = self.__tagMap[tagSet] else: concreteDecoder = None if concreteDecoder: state = stDecodeValue else: _k = tagSet[:1] if _k in self.__tagMap: concreteDecoder = self.__tagMap[_k] else: concreteDecoder = None if concreteDecoder: state = stDecodeValue else: state = stTryAsExplicitTag if debug.logger and debug.logger & debug.flagDecoder: debug.logger( 'codec %s chosen by a built-in type, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag')) debug.scope.push( concreteDecoder is None and '?' or concreteDecoder.protoComponent.__class__.__name__) if state == stGetValueDecoderByAsn1Spec: if isinstance(asn1Spec, (dict, tagmap.TagMap)): if tagSet in asn1Spec: __chosenSpec = asn1Spec[tagSet] else: __chosenSpec = None if debug.logger and debug.logger & debug.flagDecoder: debug.logger('candidate ASN.1 spec is a map of:') for t, v in asn1Spec.getPosMap().items(): debug.logger(' %s -> %s' % (t, v.__class__.__name__)) if asn1Spec.getNegMap(): debug.logger('but neither of: ') for t, v in asn1Spec.getNegMap().items(): debug.logger(' %s -> %s' % (t, v.__class__.__name__)) debug.logger( 'new candidate ASN.1 spec is %s, chosen by %s' % (__chosenSpec is None and '<none>' or __chosenSpec.prettyPrintType(), tagSet)) else: __chosenSpec = asn1Spec debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'candidate ASN.1 spec is %s' % asn1Spec.__class__.__name__) if __chosenSpec is not None and ( tagSet == __chosenSpec.getTagSet() or tagSet in __chosenSpec.getTagMap()): # use base type for codec lookup to recover untagged types baseTagSet = __chosenSpec.baseTagSet if __chosenSpec.typeId is not None and \ __chosenSpec.typeId in self.__typeMap: # ambiguous type concreteDecoder = self.__typeMap[__chosenSpec.typeId] debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'value decoder chosen for an ambiguous type by type ID %s' % (__chosenSpec.typeId, )) elif baseTagSet in self.__tagMap: # base type or tagged subtype concreteDecoder = self.__tagMap[baseTagSet] debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'value decoder chosen by base %s' % (baseTagSet, )) else: concreteDecoder = None if concreteDecoder: asn1Spec = __chosenSpec state = stDecodeValue else: state = stTryAsExplicitTag else: concreteDecoder = None state = stTryAsExplicitTag if debug.logger and debug.logger & debug.flagDecoder: debug.logger( 'codec %s chosen by ASN.1 spec, decoding %s' % (state == stDecodeValue and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as explicit tag')) debug.scope.push(__chosenSpec is None and '?' or __chosenSpec.__class__.__name__) if state == stTryAsExplicitTag: if tagSet and tagSet[0][1] == tag.tagFormatConstructed and \ tagSet[0][0] != tag.tagClassUniversal: # Assume explicit tagging concreteDecoder = explicitTagDecoder state = stDecodeValue else: concreteDecoder = None state = self.defaultErrorState debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'codec %s chosen, decoding %s' % (concreteDecoder and concreteDecoder.__class__.__name__ or "<none>", state == stDecodeValue and 'value' or 'as failure')) if state == stDumpRawValue: concreteDecoder = self.defaultRawDecoder debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'codec %s chosen, decoding value' % concreteDecoder.__class__.__name__) state = stDecodeValue if state == stDecodeValue: if recursiveFlag == 0 and not substrateFun: # legacy def substrateFun(a, b, c): return a, b[:c] if length == -1: # indef length value, substrate = concreteDecoder.indefLenValueDecoder( fullSubstrate, substrate, asn1Spec, tagSet, length, stGetValueDecoder, self, substrateFun) else: value, substrate = concreteDecoder.valueDecoder( fullSubstrate, substrate, asn1Spec, tagSet, length, stGetValueDecoder, self, substrateFun) state = stStop debug.logger and debug.logger & debug.flagDecoder and debug.logger( 'codec %s yields type %s, value:\n%s\n...remaining substrate is: %s' % (concreteDecoder.__class__.__name__, value.__class__.__name__, value.prettyPrint(), substrate and debug.hexdump(substrate) or '<none>')) if state == stErrorCondition: raise error.PyAsn1Error('%s not in asn1Spec: %s' % (tagSet, asn1Spec)) if debug.logger and debug.logger & debug.flagDecoder: debug.scope.pop() debug.logger('decoder left scope %s, call completed' % debug.scope) return value, substrate
def test_isOctetsType(self): assert octets.isOctetsType('abc') == True assert octets.isOctetsType(123) == False assert octets.isOctetsType(unicode('abc')) == False
def test_isOctetsType(self): assert octets.isOctetsType('abc') == False assert octets.isOctetsType(123) == False assert octets.isOctetsType(bytes()) == True
def prettyIn(self, value): # override asn1 type method """Implements DISPLAY-HINT parsing into base SNMP value Proper parsing seems impossible due to ambiguities. Here we are trying to do our best, but be prepared for failures on complicated DISPLAY-HINTs. Keep in mind that this parser only works with "text" input meaning `unicode` (Py2) or `str` (Py3). """ for base in inspect.getmro(self.__class__): if not issubclass(base, TextualConvention) and issubclass(base, Asn1Item): break else: raise SmiError('TEXTUAL-CONVENTION has no underlying SNMP base type') if self.displayHint and (self.__integer.isSuperTypeOf(self, matchConstraints=False) and self.getNamedValues() or self.__unsigned32.isSuperTypeOf(self, matchConstraints=False) or self.__timeticks.isSuperTypeOf(self, matchConstraints=False)): value = str(value) _ = lambda t, f=0: (t, f) displayHintType, decimalPrecision = _(*self.displayHint.split('-')) if displayHintType == 'x' and (value.startswith('0x') or value.startswith('-0x')): try: if value.startswith('-'): return base.prettyIn(self, -int(value[3:], 16)) else: return base.prettyIn(self, int(value[2:], 16)) except Exception as exc: raise SmiError( 'integer evaluation error: %s' % exc ) elif displayHintType == 'd': try: return base.prettyIn(self, int(float(value) * 10**int(decimalPrecision))) except Exception as exc: raise SmiError( 'float evaluation error: %s' % exc ) elif displayHintType == 'o' and (value.startswith('0') or value.startswith('-0')): try: return base.prettyIn(self, int(value, 8)) except Exception as exc: raise SmiError( 'octal evaluation error: %s' % exc ) elif displayHintType == 'b' and (value.startswith('B') or value.startswith('-B')): negative = value.startswith('-') if negative: value = value[2:] else: value = value[1:] value = [x != '0' and 1 or 0 for x in value] binValue = 0 while value: binValue <<= value[0] del value[0] return base.prettyIn(self, binValue) else: raise SmiError( 'Unsupported numeric type spec "%s" at %s' % (displayHintType, self.__class__.__name__) ) elif self.displayHint and self.__octetString.isSuperTypeOf(self, matchConstraints=False): numBase = { 'x': 16, 'd': 10, 'o': 8 } numDigits = { 'x': octets.str2octs(string.hexdigits), 'o': octets.str2octs(string.octdigits), 'd': octets.str2octs(string.digits) } # how do we know if object is initialized with display-hint # formatted text? based on "text" input maybe? # That boils down to `str` object on Py3 or `unicode` on Py2. if octets.isStringType(value) and not octets.isOctetsType(value): value = base.prettyIn(self, value) else: return base.prettyIn(self, value) outputValue = octets.str2octs('') runningValue = value displayHint = self.displayHint while runningValue and displayHint: # 1 this information is totally lost, just fail explicitly if displayHint[0] == '*': raise SmiError( 'Can\'t parse "*" in DISPLAY-HINT (%s)' % self.__class__.__name__ ) # 2 this becomes ambiguous when it comes to rendered value octetLength = '' while displayHint and displayHint[0] in string.digits: octetLength += displayHint[0] displayHint = displayHint[1:] # length is mandatory but people ignore that if not octetLength: octetLength = len(runningValue) try: octetLength = int(octetLength) except Exception: raise SmiError( 'Bad octet length: %s' % octetLength ) if not displayHint: raise SmiError( 'Short octet length: %s' % self.displayHint ) # 3 displayFormat = displayHint[0] displayHint = displayHint[1:] # 4 this is the lifesaver -- we could use it as an anchor if displayHint and displayHint[0] not in string.digits and displayHint[0] != '*': displaySep = displayHint[0] displayHint = displayHint[1:] else: displaySep = '' # 5 is probably impossible to support if displayFormat in ('a', 't'): outputValue += runningValue[:octetLength] elif displayFormat in numBase: if displaySep: guessedOctetLength = runningValue.find(octets.str2octs(displaySep)) if guessedOctetLength == -1: guessedOctetLength = len(runningValue) else: for idx in range(len(runningValue)): if runningValue[idx] not in numDigits[displayFormat]: guessedOctetLength = idx break else: guessedOctetLength = len(runningValue) try: num = int(octets.octs2str(runningValue[:guessedOctetLength]), numBase[displayFormat]) except Exception as exc: raise SmiError( 'Display format eval failure: %s: %s' % (runningValue[:guessedOctetLength], exc) ) num_as_bytes = [] if num: while num: num_as_bytes.append(num & 0xFF) num >>= 8 else: num_as_bytes = [0] while len(num_as_bytes) < octetLength: num_as_bytes.append(0) num_as_bytes.reverse() outputValue += octets.ints2octs(num_as_bytes) if displaySep: guessedOctetLength += 1 octetLength = guessedOctetLength else: raise SmiError( 'Unsupported display format char: %s' % displayFormat ) runningValue = runningValue[octetLength:] if not displayHint: displayHint = self.displayHint return base.prettyIn(self, outputValue) else: return base.prettyIn(self, value)