def _deserializeAlignment(self, regex, mask, unitSize=AbstractType.UNITSIZE_8): """ deserializeAlignment: Transforms the C extension results in a python readable way @param regex the C returned regex @param mask the C returned mask @param unitSize the unitSize @returns the python alignment """ if not (unitSize == AbstractType.UNITSIZE_8 or unitSize == AbstractType.UNITSIZE_4): raise ValueError( "Deserializing with unitSize {0} not yet implemented, only 4 and 8 supported." .format(unitSize)) align = b"" for i, c in enumerate(mask): if c != 2: if c == 1: if unitSize == AbstractType.UNITSIZE_8: align += b"--" elif unitSize == AbstractType.UNITSIZE_4: align += b"-" else: if unitSize == AbstractType.UNITSIZE_8: align += TypeConverter.convert(regex[i:i + 1], Raw, HexaString) elif unitSize == AbstractType.UNITSIZE_4: align += TypeConverter.convert(regex[i:i + 1], Raw, HexaString)[1:] return align
def generate(self, generationStrategy=None): """Generates a random IPv4 which follows the constraints. >>> from netzob.all import * >>> f = Field(IPv4()) >>> len(f.specialize()) 4 >>> f = Field(IPv4("192.168.0.10")) >>> TypeConverter.convert(f.specialize(), Raw, IPv4) IPAddress('192.168.0.10') >>> f = Field(IPv4(network="10.10.10.0/24")) >>> TypeConverter.convert(f.specialize(), Raw, IPv4) in IPNetwork("10.10.10.0/24") True """ from netzob.Model.Types.BitArray import BitArray from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.Raw import Raw if self.value is not None: return self.value elif self.network is not None: ip = random.choice(self.network) return TypeConverter.convert(ip.packed, Raw, BitArray, src_unitSize=self.unitSize, src_endianness=self.endianness, src_sign=self.sign, dst_unitSize=self.unitSize, dst_endianness=self.endianness, dst_sign=self.sign) else: not_valid = [10, 127, 169, 172, 192] first = random.randrange(1, 256) while first in not_valid: first = random.randrange(1, 256) strip = ".".join([ str(first), str(random.randrange(1, 256)), str(random.randrange(1, 256)), str(random.randrange(1, 256)) ]) ip = IPv4.encode(strip) return TypeConverter.convert(ip.packed, Raw, BitArray, src_unitSize=self.unitSize, src_endianness=self.endianness, src_sign=self.sign, dst_unitSize=self.unitSize, dst_endianness=self.endianness, dst_sign=self.sign)
def _computeExpectedValue(self, parsingPath): self._logger.debug("compute expected value for Size field") # first checks the pointed fields all have a value hasValue = True for field in self.fieldDependencies: if field.domain != self and not parsingPath.isDataAvailableForVariable( field.domain): self._logger.debug("Field : {0} has no value".format(field.id)) hasValue = False if not hasValue: raise Exception( "Expected value cannot be computed, some dependencies are missing for domain {0}". format(self)) else: size = 0 for field in self.fieldDependencies: # Retrieve field value if field.domain is self: fieldValue = self.dataType.generate() else: fieldValue = parsingPath.getDataAssignedToVariable( field.domain) if fieldValue is None: break # Retrieve length of field value if fieldValue == TypeConverter.convert("PENDING VALUE", ASCII, BitArray): # Handle case where field value is not currently known. # In such case, we retrieve the max length of the datatype minSize, maxSize = field.domain.dataType.size if maxSize is None: maxSize = AbstractType.MAXIMUM_GENERATED_DATA_SIZE tmpLen = maxSize else: tmpLen = len(fieldValue) size += tmpLen size = int(size * self.factor + self.offset) size_raw = TypeConverter.convert( size, Integer, Raw, src_unitSize=self.dataType.unitSize) b = TypeConverter.convert(size_raw, Raw, BitArray) # add heading '0' while len(b) < self.dataType.size[0]: b.insert(0, False) # in some cases (when unitSize and size are not equal), it may require to delete some '0' in front while len(b) > self.dataType.size[0]: b.remove(0) return b
def __init__(self, value=None, nbBytes=None, unitSize=AbstractType.defaultUnitSize(), endianness=AbstractType.defaultEndianness(), sign=AbstractType.defaultSign()): if value is not None and not isinstance(value, bitarray): from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray if isinstance(value, str): value = TypeConverter.convert(bytes(value, "utf-8"), Raw, BitArray) elif isinstance(value, bytes): value = TypeConverter.convert(value, Raw, BitArray) nbBits = self._convertNbBytesinNbBits(nbBytes) super(Raw, self).__init__(self.__class__.__name__, value, nbBits, unitSize=unitSize, endianness=endianness, sign=sign)
def canParse(self, data, unitSize=AbstractType.defaultUnitSize(), endianness=AbstractType.defaultEndianness(), sign=AbstractType.defaultSign()): """Computes if specified data can be parsed as a Timestamp with the predefined constraints. >>> from netzob.all import * >>> time = Timestamp() >>> time.canParse(TypeConverter.convert(1444494130, Integer, BitArray, src_unitSize=AbstractType.UNITSIZE_32)) True >>> # A timestamp is nothing else than 32bits parsed as an unsigned long >>> time.canParse(TypeConverter.convert("test", ASCII, BitArray)) True >>> time.canParse(TypeConverter.convert("te", ASCII, BitArray)) False However, some constrains over the definition of the Timestamp can be set to restrain the accepted values >>> from netzob.all import * >>> time = Timestamp(epoch=Timestamp.EPOCH_WINDOWS, unity=Timestamp.UNITY_NANOSECOND, unitSize = AbstractType.UNITSIZE_64) >>> # the returned year is < 1900 >>> time.canParse(TypeConverter.convert("test", ASCII, BitArray)) False """ if data is None: raise TypeError("data cannot be None") # Timestamp must be 8 bits modulo length if len(data) % 8 != 0: return False if len(data) < int(self.unitSize): return False try: value = TypeConverter.convert( data[:int(self.unitSize)], BitArray, Integer, dst_unitSize=AbstractType.UNITSIZE_32, dst_sign=AbstractType.SIGN_UNSIGNED) # convert the value in seconds value = value / self.unity # add the utc now with the epoch timestamp_datetime = self.epoch + timedelta(seconds=value) # convert obtained datetime to timestamp in seconds result_sec = int(timestamp_datetime.strftime('%s')) datetime.fromtimestamp(result_sec) except Exception: return False return True
def __init__(self, value=None, epoch=EPOCH_UNIX, unity=UNITY_SECOND, unitSize=AbstractType.UNITSIZE_32, endianness=AbstractType.defaultEndianness(), sign=AbstractType.SIGN_UNSIGNED): """Builds a Timestamp domain with optional constraints. :param value: specifies the value of the timestamp. :type value: an int, a long or a bitarray :param epoch: the initial date expressed in UTC from which timestamp is measured. Default value is the UNIX Epoch. :type datetime.datetime :param unity: specifies the unity of the timestamp (seconds, milliseconds, nanoseconds). Default value is SECOND. :type unity: int """ if value is not None and not isinstance(value, bitarray): # converts the specified value in bitarray value = TypeConverter.convert(value, Integer, BitArray, src_unitSize=unitSize, src_endianness=endianness, src_sign=sign) self.epoch = epoch self.unity = unity super(Timestamp, self).__init__(self.__class__.__name__, value, 32, unitSize=unitSize, endianness=endianness, sign=sign)
def __init__(self, value=None, nbChars=(None, None), unitSize=AbstractType.defaultUnitSize(), endianness=AbstractType.defaultEndianness(), sign=AbstractType.defaultSign()): if value is not None and not isinstance(value, bitarray): from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray value = TypeConverter.convert(value, ASCII, BitArray, src_unitSize=unitSize, src_endianness=endianness, src_sign=sign, dst_unitSize=unitSize, dst_endianness=endianness, dst_sign=sign) else: value = None self.nbChars = nbChars nbBits = self._convertNbCharsInNbBits(self.nbChars) super(ASCII, self).__init__(self.__class__.__name__, value, nbBits, unitSize=unitSize, endianness=endianness, sign=sign)
def generate(self, generationStrategy=None): """Generates a random ASCII that respects the requested size. >>> from netzob.all import * >>> a = ASCII(nbChars=10) >>> gen = a.generate() >>> len(gen)/8 10.0 >>> b = ASCII("netzob") >>> gen = b.generate() >>> print(len(gen)>0) True """ from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray minSize, maxSize = self.nbChars if maxSize is None: maxSize = AbstractType.MAXIMUM_GENERATED_DATA_SIZE if minSize is None: minSize = 0 generatedSize = random.randint(minSize, maxSize) randomContent = ''.join([ random.choice(string.ascii_letters + string.digits) for i in range(generatedSize) ]) return TypeConverter.convert(randomContent, ASCII, BitArray)
def __init__(self, value=None, network=None, unitSize=AbstractType.defaultUnitSize(), endianness=AbstractType.defaultEndianness(), sign=AbstractType.defaultSign()): """Builds an IPv4 domain with optional constraints. :parameter value: specify a constraints over the expected value. :type value: an str, an IPAddress or an int which can be parsed as an IPv4 (ex. "192.168.0.10") :parameter network: if no value is specified (None), a constraints over the network the parsed IP belongs can be specified with this parameter (ex. "192.168.0.0/24") :type network: an str or an IPAddress which can be parsed as a network IPv4 """ if value is not None and not isinstance(value, bitarray): from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray value = TypeConverter.convert(value, IPv4, BitArray, src_unitSize=unitSize, src_endianness=endianness, src_sign=sign, dst_unitSize=unitSize, dst_endianness=endianness, dst_sign=sign) self.network = network super(IPv4, self).__init__(self.__class__.__name__, value, 32, unitSize=unitSize, endianness=endianness, sign=sign)
def encodeChild(self, variable, readingToken): result = [] if not readingToken.isValueForVariableAvailable(variable): return result if variable.varType == "Data" or variable.varType == "Size" or variable.varType == "InternetChecksum": val = readingToken.getValueForVariable(variable) encodedVal = TypeConverter.convert(val, BitArray, variable.dataType.__class__) result.append(str(encodedVal)) elif variable.varType == "Agg" or variable.varType == "Alt": for child in variable.children: result.extend(self.encodeChild(child, readingToken)) elif variable.varType == "Eol": # nothing to encode when child is EOL pass else: raise Exception( "Unknown type of variable: {0}".format(variable.varType)) if len(result) == 0: return '' else: return ''.join(result)
def __repr__(self): """ >>> from netzob.all import * >>> f = Field(Raw("\\x01\\x02\\x03\\x04")) >>> s = Symbol(fields=[f]) >>> messages = [RawMessage(s.specialize()) for x in range(5)] >>> s.messages = messages >>> print(s) Field ------------------ '\\x01\\x02\\x03\\x04' '\\x01\\x02\\x03\\x04' '\\x01\\x02\\x03\\x04' '\\x01\\x02\\x03\\x04' '\\x01\\x02\\x03\\x04' ------------------ """ if self.value is not None: from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray return str( TypeConverter.convert(self.value, BitArray, self.__class__)) else: return str(self.value)
def __init__(self, value=None, size=(None, None)): if value is not None and not isinstance(value, bitarray): from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray value = TypeConverter.convert(value, HexaString, BitArray) super(HexaString, self).__init__(self.__class__.__name__, value, size)
def generate(self, generationStrategy=None): """Generates a random Raw that respects the requested size. >>> from netzob.all import * >>> a = Raw(nbBytes=(10)) >>> gen = a.generate() >>> print(len(gen)) 80 >>> from netzob.all import * >>> a = Raw(nbBytes=(10, 20)) >>> gen = a.generate() >>> print(10<=len(gen) and 20<=len(gen)) True """ from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray minSize, maxSize = self.size if maxSize is None: maxSize = AbstractType.MAXIMUM_GENERATED_DATA_SIZE if minSize is None: minSize = 0 generatedSize = random.randint(minSize, maxSize) return TypeConverter.convert( os.urandom(int(generatedSize / 8)), Raw, BitArray)
def regenerate(self, variableSpecializerPath, moreCallBackAccepted=True): """This method participates in the specialization proces. It creates a VariableSpecializerResult in the provided path that contains a generated value that follows the definition of the Data """ self._logger.debug("Regenerate value {0}".format(self)) if variableSpecializerPath is None: raise Exception("VariableSpecializerPath cannot be None") try: newValue = self._computeExpectedValue(variableSpecializerPath) variableSpecializerPath.addResult(self, newValue) except Exception as e: self._logger.debug( "Cannot specialize since no value is available for the value dependencies, we create a callback function in case it can be computed later: {0}" .format(e)) pendingValue = TypeConverter.convert("PENDING VALUE", ASCII, BitArray) variableSpecializerPath.addResult(self, pendingValue) if moreCallBackAccepted: variableSpecializerPath.registerFieldCallBack( self.fieldDependencies, self, parsingCB=False) else: raise e return [variableSpecializerPath]
def specializeSymbol(self, symbol): """This method generates a message based on the provided symbol definition.""" if symbol is None: raise Exception("Specified symbol is None") self._logger.debug("Specifies symbol '{0}'.".format(symbol.name)) # this variable host all the specialization path specializingPaths = [SpecializingPath(memory=self.memory)] for field in symbol.fields: self._logger.debug("Specializing field {0}".format(field.name)) fieldDomain = field.domain if fieldDomain is None: raise Exception("Cannot specialize field '{0}' since it defines no domain".format(fieldDomain)) fs = FieldSpecializer(field, presets = self.presets) newSpecializingPaths = [] for specializingPath in specializingPaths: newSpecializingPaths.extend(fs.specialize(specializingPath)) specializingPaths = newSpecializingPaths if len(specializingPaths) > 1: self._logger.info("TODO: multiple valid paths found when specializing this message.") if len(specializingPaths) == 0: raise Exception("Cannot specialize this symbol.") retainedPath = specializingPaths[0] generatedContent = None # let's configure the generated content for field in symbol.fields: # TODO: only support one level of children... must be improved if len(field.fields) > 0: d = None for child in field.fields: if d is None: d = retainedPath.getDataAssignedToVariable(child.domain).copy() else: d += retainedPath.getDataAssignedToVariable(child.domain).copy() else: d = retainedPath.getDataAssignedToVariable(field.domain) if generatedContent is None: generatedContent = d.copy() else: generatedContent += d.copy() retainedPath.generatedContent = generatedContent self._logger.debug("Specialized message: {0}".format(TypeConverter.convert(retainedPath.generatedContent, BitArray, ASCII))) self.memory = retainedPath.memory return retainedPath
def encode(self, data): self._logger.debug(data) return TypeConverter.convert(data, BitArray, self.type, dst_unitSize=self.unitSize, dst_endianness=self.endianness, dst_sign=self.sign)
def __repr__(self): if self.value != None: from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray return str( TypeConverter.convert(self.value, BitArray, self.__class__)) else: return str(self.value)
def __str__(self): if self.value is not None: from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray from netzob.Model.Types.HexaString import HexaString return "{0}={1} ({2})".format(self.typeName, repr(TypeConverter.convert(self.value, BitArray, Raw)), self.size) else: return "{0}={1} ({2})".format(self.typeName, self.value, self.size)
def encode(self, data): data_raw = TypeConverter.convert(data, BitArray, Raw) result = None if self.encode_data: result = base64.b64encode(data_raw) else: result = base64.b64decode(data_raw) return result
def _generateDataValues(self, cellsData): result = [] for data in cellsData: if len(data) > 0: result.append(TypeConverter.convert( data[:8], Raw, Integer)) # We take only the first 8 octets else: result.append(0) return result
def __str__(self): from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray if self.value is not None: return "{0}={1} ({2})".format( self.typeName, TypeConverter.convert(self.value, BitArray, self.__class__), self.size) else: return "{0}={1} ({2})".format(self.typeName, self.value, self.size)
def encode(self, data): data_raw = TypeConverter.convert(data, BitArray, Raw) result = None if self.compress_data: result = zlib.compress(data_raw, self.compression_level) else: result = zlib.decompress(data_raw) return result
def convertValue(self, typeClass, dst_unitSize=None, dst_endianness=None, dst_sign=None): """Convert the current data in the netzob type specified in parameter. :parameter typeClass: the netzob class to which the current data must be converted :type typeClass: type :keyword dst_unitSize: the unitsize of the destination value. Values must be one of AbstractType.UNITSIZE_*. if None, the value is the default one. :type dst_unitSize: str :keyword dst_endianness: the endianness of the destination value. Values must be AbstractType.ENDIAN_BIG or AbstractType.ENDIAN_LITTLE. if None, the value is the default one. :type dst_endianness: str :keyword dst_sign: the sign of the destination. Values must be AbstractType.SIGN_SIGNED or AbstractType.SIGN_UNSIGNED. if None, the value is the default one. :type dst_sign: str :return: the converted current value in the specified netzob type :rtype: :class:`netzob.Model.AbstractType.AbstractType` """ if typeClass is None: raise TypeError("TypeClass cannot be None") if typeClass not in AbstractType.supportedTypes(): raise TypeError( "Requested typeClass ({0}) is not supported.".format( typeClass)) if dst_unitSize is None: dst_unitSize = AbstractType.defaultUnitSize() if dst_endianness is None: dst_endianness = AbstractType.defaultEndianness() if dst_sign is None: dst_sign = AbstractType.defaultSign() if dst_unitSize not in AbstractType.supportedUnitSizes(): raise TypeError("Dst_unitsize is not supported.") if dst_endianness not in AbstractType.supportedEndianness(): raise TypeError("Dst_endianness is not supported.") if dst_sign not in AbstractType.supportedSign(): raise TypeError("Sign is not supported.") from netzob.Model.Types.TypeConverter import TypeConverter from netzob.Model.Types.BitArray import BitArray return typeClass(TypeConverter.convert(self.value, BitArray, typeClass, src_unitSize=self.unitSize, src_endianness=self.endianness, src_sign=self.sign, dst_unitSize=dst_unitSize, dst_endianness=dst_endianness, dst_sign=dst_sign), unitSize=dst_unitSize, endianness=dst_endianness, sign=dst_sign)
def _computeExpectedValue(self, parsingPath): self._logger.debug( "compute expected value for Internet checksum field") # first checks the pointed fields all have a value hasValue = True for field in self.fieldDependencies: if field.domain != self and not parsingPath.isDataAvailableForVariable( field.domain): self._logger.debug("Field : {0} has no value".format(field.id)) hasValue = False if not hasValue: raise Exception( "Expected value cannot be computed, some dependencies are missing for domain {0}" .format(self)) else: fieldValues = [] for field in self.fieldDependencies: if field.domain is self: fieldSize = random.randint(field.domain.dataType.size[0], field.domain.dataType.size[1]) fieldValue = b"\x00" * int(fieldSize / 8) else: fieldValue = TypeConverter.convert( parsingPath.getDataAssignedToVariable(field.domain), BitArray, Raw) if fieldValue is None: break else: fieldValues.append(fieldValue) fieldValues = b''.join(fieldValues) # compute the checksum of this value chsum = self.__checksum(fieldValues) b = TypeConverter.convert(chsum, Integer, BitArray, src_unitSize=AbstractType.UNITSIZE_16, src_sign=AbstractType.SIGN_UNSIGNED) return b
def parseRaw(self, dataToParse, fields): """This method parses the specified raw against the specification of the provided symbol.""" if dataToParse is None or len(dataToParse) <= 0: raise Exception("Specified data to parse is empty (or None)") if fields is None: raise Exception("Specified fields is None") if len(fields) == 0: raise Exception("No field specified") bitArrayToParse = TypeConverter.convert(dataToParse, Raw, BitArray) return self.parseBitarray(bitArrayToParse, fields)
def _generateCRC32(self, symbol): header = [] lines = [] header.append(self.ATTR_CRC32) messages = symbol.getMessages() for message in messages: line = [] data = message.getStringData() rawContent = TypeConverter.netzobRawToPythonRaw(data) valCrc32 = zlib.crc32(rawContent) & 0xFFFFFFFF line.append(str(valCrc32)) lines.append(b",".join(line)) return (header, lines)
def _sizeRelation(self, x, x_attribute, y, y_attribute): if x_attribute == self.ATTR_SIZE: if len(x) > 0: x = len(x) else: if len(x) > 0: x = TypeConverter.convert(x[:8], Raw, Integer) else: x = 0 if y_attribute == self.ATTR_SIZE: if len(y) > 0: y = len(y) else: if len(y) > 0: y = TypeConverter.convert(y[:8], Raw, Integer) else: y = 0 if x == y: return True else: return False
def specialize(self, memory=None, generationStrategy=None, presets=None): """Specialize and generate an hexastring which content follows the fields definitions attached to the field of the symbol. >>> from netzob.all import * >>> f1 = Field(domain=ASCII(nbChars=5)) >>> f0 = Field(domain=Size(f1)) >>> s = Symbol(fields=[f0, f1]) >>> result = s.specialize() >>> print(result[0]) 5 >>> print(len(result)) 6 You can also preset the value of some variables included in the symbol definition. >>> from netzob.all import * >>> f1 = Field(domain=ASCII("hello ")) >>> f2 = Field(domain=ASCII(nbChars=(1,10))) >>> s = Symbol(fields = [f1, f2]) >>> presetValues = dict() >>> presetValues[f2] = TypeConverter.convert("antoine", ASCII, BitArray) >>> print(s.specialize(presets = presetValues)) b'hello antoine' A preseted valued bypasses all the constraints checks on your field definition. For example, in the following example it can be use to bypass a size field definition. >>> from netzob.all import * >>> f1 = Field() >>> f2 = Field(domain=Raw(nbBytes=(10,15))) >>> f1.domain = Size(f2) >>> s = Symbol(fields=[f1, f2]) >>> presetValues = {f1: TypeConverter.convert("\xff", Raw, BitArray)} >>> print(s.specialize(presets = presetValues)[0]) 195 :keyword generationStrategy: if set, the strategy will be used to generate the fields definitions :type generaionrStrategy: :class:`` :return: a generated content represented as a Raw :rtype: :class:`str`` :raises: :class:`netzob.Model.Vocabulary.AbstractField.GenerationException` if an error occurs while generating a message """ from netzob.Model.Vocabulary.Domain.Specializer.MessageSpecializer import MessageSpecializer msg = MessageSpecializer(memory=memory, presets=presets) spePath = msg.specializeSymbol(self) if spePath is not None: return TypeConverter.convert(spePath.generatedContent, BitArray, Raw)
def encode(data, unitSize=AbstractType.UNITSIZE_32, endianness=AbstractType.defaultEndianness(), sign=AbstractType.SIGN_UNSIGNED): from netzob.Model.Types.Raw import Raw intValue = TypeConverter.convert(data, Raw, Integer, dst_unitSize=AbstractType.UNITSIZE_32, dst_sign=AbstractType.SIGN_UNSIGNED) parsedTimestamp = datetime.utcfromtimestamp(intValue) return parsedTimestamp.strftime("%c")
def specialize(self): """Specialize the current field to build a raw data that follows the fields definitions attached to current element. This method allows to generate some content following the field definition: >>> from netzob.all import * >>> f = Field("hello") >>> print('\\n'.join([str(f.specialize()) for x in range(3)])) b'hello' b'hello' b'hello' This method also applies on multiple fields using a Symbol >>> fHello = Field("hello ") >>> fName = Field("zoby") >>> s = Symbol([fHello, fName]) >>> print('\\n'.join([str(s.specialize()) for x in range(3)])) b'hello zoby' b'hello zoby' b'hello zoby' :return: a generated content represented with an hexastring :rtype: :class:`str`` :raises: :class:`netzob.Model.Vocabulary.AbstractField.GenerationException` if an error occurs while generating a message """ self._logger.debug("Specializes field {0}".format(self.name)) if self.__domain is None: raise InvalidDomainException("The domain is not defined.") from netzob.Model.Vocabulary.Domain.Specializer.FieldSpecializer import FieldSpecializer fs = FieldSpecializer(self) specializingPaths = fs.specialize() if len(specializingPaths) < 1: raise Exception("Cannot specialize this field") specializingPath = specializingPaths[0] self._logger.debug( "field specializing done: {0}".format(specializingPath)) if specializingPath is None: raise Exception( "The specialization of the field {0} returned no result.". format(self.name)) return TypeConverter.convert( specializingPath.getDataAssignedToVariable(self.domain), BitArray, Raw)