/* * MmsValue.c * * Copyright 2013 Michael Zillgith * * This file is part of libIEC61850. * * libIEC61850 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * libIEC61850 is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with libIEC61850. If not, see . * * See COPYING file for the complete license text. */ #include "libiec61850_platform_includes.h" #include "mms_common.h" #include "mms_value.h" #include "mms_type_spec.h" #include "string_utilities.h" #include "platform_endian.h" #include "mms_common_internal.h" #include "mms_value_internal.h" #include "conversions.h" #include /* for ctime_r */ static inline int bitStringByteSize(MmsValue* value) { int bitSize = value->value.bitString.size; return (bitSize / 8) + ((bitSize % 8) > 0); } int MmsValue_getBitStringByteSize(MmsValue* self) { return bitStringByteSize(self); } static void updateStructuredComponent(MmsValue* self, MmsValue* update) { int componentCount; MmsValue** selfValues; MmsValue** updateValues; componentCount = self->value.structure.size; selfValues = self->value.structure.components; updateValues = update->value.structure.components; int i; for (i = 0; i < componentCount; i++) { MmsValue_update(selfValues[i], updateValues[i]); } } MmsValue* MmsValue_newIntegerFromBerInteger(Asn1PrimitiveValue* berInteger) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); self->type = MMS_INTEGER; self->value.integer = berInteger; return self; } MmsValue* MmsValue_newUnsignedFromBerInteger(Asn1PrimitiveValue* berInteger) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); self->type = MMS_UNSIGNED; self->value.integer = berInteger; return self; } bool MmsValue_equals(MmsValue* self, MmsValue* otherValue) { if (self->type == otherValue->type) { switch (self->type) { case MMS_ARRAY: case MMS_STRUCTURE: if (self->value.structure.size == otherValue->value.structure.size) { int componentCount = self->value.structure.size; int i; for (i = 0; i < componentCount; i++) { if (!MmsValue_equals(self->value.structure.components[i], otherValue->value.structure.components[i])) return false; } return true; } break; case MMS_BOOLEAN: if (self->value.boolean == otherValue->value.boolean) return true; break; case MMS_FLOAT: if (memcmp(self->value.floatingPoint.buf, otherValue->value.floatingPoint.buf, self->value.floatingPoint.formatWidth / 8) == 0) return true; break; case MMS_INTEGER: case MMS_UNSIGNED: return Asn1PrimitivaValue_compare(self->value.integer, otherValue->value.integer); break; case MMS_UTC_TIME: if (memcmp(self->value.utcTime, otherValue->value.utcTime, 8) == 0) return true; break; case MMS_BIT_STRING: if (self->value.bitString.size == otherValue->value.bitString.size) { if (memcmp(self->value.bitString.buf, otherValue->value.bitString.buf, bitStringByteSize(self)) == 0) return true; } break; case MMS_BINARY_TIME: if (self->value.binaryTime.size == otherValue->value.binaryTime.size) { if (memcmp(self->value.binaryTime.buf, otherValue->value.binaryTime.buf, self->value.binaryTime.size) == 0) return true; } break; case MMS_OCTET_STRING: if (self->value.octetString.size == otherValue->value.octetString.size) { if (memcmp(self->value.octetString.buf, otherValue->value.octetString.buf, self->value.octetString.size) == 0) return true; } break; case MMS_VISIBLE_STRING: case MMS_STRING: if (self->value.visibleString.buf != NULL) { if (otherValue->value.visibleString.buf != NULL) { if (strcmp(self->value.visibleString.buf, otherValue->value.visibleString.buf) == 0) return true; } } else { if (otherValue->value.visibleString.buf == NULL) return true; } break; case MMS_DATA_ACCESS_ERROR: if (self->value.dataAccessError == otherValue->value.dataAccessError) return true; break; default: break; } return false; } else return false; } bool MmsValue_equalTypes(MmsValue* self, MmsValue* otherValue) { if (self->type == otherValue->type) { switch (self->type) { case MMS_ARRAY: case MMS_STRUCTURE: if (self->value.structure.size == otherValue->value.structure.size) { int componentCount = self->value.structure.size; int i; for (i = 0; i < componentCount; i++) { if (!MmsValue_equalTypes(self->value.structure.components[i], otherValue->value.structure.components[i])) return false; } return true; } else return false; break; default: return true; } } else return false; } bool MmsValue_update(MmsValue* self, MmsValue* update) { if (self->type == update->type) { switch (self->type) { case MMS_STRUCTURE: case MMS_ARRAY: updateStructuredComponent(self, update); break; case MMS_BOOLEAN: self->value.boolean = update->value.boolean; break; case MMS_FLOAT: if (self->value.floatingPoint.formatWidth == update->value.floatingPoint.formatWidth) { self->value.floatingPoint.exponentWidth = update->value.floatingPoint.exponentWidth; memcpy(self->value.floatingPoint.buf, update->value.floatingPoint.buf, self->value.floatingPoint.formatWidth / 8); } else return false; break; case MMS_INTEGER: case MMS_UNSIGNED: if (BerInteger_setFromBerInteger(self->value.integer, update->value.integer)) return true; else return false; break; case MMS_UTC_TIME: memcpy(self->value.utcTime, update->value.utcTime, 8); break; case MMS_BIT_STRING: if (self->value.bitString.size == update->value.bitString.size) memcpy(self->value.bitString.buf, update->value.bitString.buf, bitStringByteSize(self)); else return false; break; case MMS_OCTET_STRING: if (self->value.octetString.maxSize == update->value.octetString.maxSize) { memcpy(self->value.octetString.buf, update->value.octetString.buf, update->value.octetString.size); self->value.octetString.size = update->value.octetString.size; } else return false; break; case MMS_VISIBLE_STRING: MmsValue_setVisibleString(self, update->value.visibleString.buf); break; case MMS_STRING: MmsValue_setMmsString(self, update->value.visibleString.buf); break; case MMS_BINARY_TIME: self->value.binaryTime.size = update->value.binaryTime.size; memcpy(self->value.binaryTime.buf, update->value.binaryTime.buf, update->value.binaryTime.size); break; default: return false; break; } return true; } else return false; } MmsValue* MmsValue_newDataAccessError(MmsDataAccessError accessError) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); self->type = MMS_DATA_ACCESS_ERROR; self->value.dataAccessError = accessError; return self; } MmsValue* MmsValue_newBitString(int bitSize) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue));; self->type = MMS_BIT_STRING; self->value.bitString.size = bitSize; self->value.bitString.buf = (uint8_t*) calloc(bitStringByteSize(self), 1); return self; } static int getBitStringByteSize(MmsValue* self) { int byteSize; if (self->value.bitString.size % 8) byteSize = (self->value.bitString.size / 8) + 1; else byteSize = self->value.bitString.size / 8; return byteSize; } void MmsValue_deleteAllBitStringBits(MmsValue* self) { int byteSize = getBitStringByteSize(self); int i; for (i = 0; i < byteSize; i++) { self->value.bitString.buf[i] = 0; } } void MmsValue_setAllBitStringBits(MmsValue* self) { int byteSize = getBitStringByteSize(self); int i; for (i = 0; i < byteSize; i++) { self->value.bitString.buf[i] = 0xff; } int padding = (byteSize * 8) - self->value.bitString.size; uint8_t paddingMask = 0; for (i = 0; i < padding; i++) { paddingMask += (1 << i); } paddingMask = ~paddingMask; self->value.bitString.buf[byteSize - 1] = self->value.bitString.buf[byteSize - 1] & paddingMask; } int MmsValue_getBitStringSize(MmsValue* self) { return self->value.bitString.size; } int MmsValue_getNumberOfSetBits(MmsValue* self) { int setBitsCount = 0; int byteSize = getBitStringByteSize(self); int i; for (i = 0; i < byteSize; i++) { uint8_t currentByte = self->value.bitString.buf[i]; while (currentByte != 0) { if ((currentByte & 1) == 1) setBitsCount++; currentByte >>= 1; } } return setBitsCount; } void MmsValue_setBitStringBit(MmsValue* self, int bitPos, bool value) { if (bitPos < self->value.bitString.size) { int bytePos = bitPos / 8; int bitPosInByte = 7 - (bitPos % 8); int bitMask = (1 << bitPosInByte); if (value) self->value.bitString.buf[bytePos] |= bitMask; else self->value.bitString.buf[bytePos] &= (~bitMask); } } bool MmsValue_getBitStringBit(MmsValue* self, int bitPos) { if (bitPos < self->value.bitString.size) { int bytePos = bitPos / 8; int bitPosInByte = 7 - (bitPos % 8); int bitMask = (1 << bitPosInByte); if ((self->value.bitString.buf[bytePos] & bitMask) > 0) return true; else return false; } else return false; /* out of range bits are always zero */ } uint32_t MmsValue_getBitStringAsInteger(MmsValue* self) { uint32_t value = 0; int bitPos; for (bitPos = 0; bitPos < self->value.bitString.size; bitPos++) { if (MmsValue_getBitStringBit(self, bitPos)) { value += (1 << bitPos); } } return value; } void MmsValue_setBitStringFromInteger(MmsValue* self, uint32_t intValue) { int bitPos; for (bitPos = 0; bitPos < self->value.bitString.size; bitPos++) { if ((intValue & 1) == 1) MmsValue_setBitStringBit(self, bitPos, true); else MmsValue_setBitStringBit(self, bitPos, false); intValue = intValue >> 1; } } MmsValue* MmsValue_newFloat(float variable) { MmsValue* value = (MmsValue*) malloc(sizeof(MmsValue));; value->type = MMS_FLOAT; value->value.floatingPoint.formatWidth = 32; value->value.floatingPoint.exponentWidth = 8; value->value.floatingPoint.buf = (uint8_t*) malloc(4); *((float*) value->value.floatingPoint.buf) = variable; return value; } void MmsValue_setFloat(MmsValue* value, float newFloatValue) { if (value->type == MMS_FLOAT) { if (value->value.floatingPoint.formatWidth == 32) { *((float*) value->value.floatingPoint.buf) = newFloatValue; } else if (value->value.floatingPoint.formatWidth == 64) { *((double*) value->value.floatingPoint.buf) = (double) newFloatValue; } } } void MmsValue_setDouble(MmsValue* value, double newFloatValue) { if (value->type == MMS_FLOAT) { if (value->value.floatingPoint.formatWidth == 32) { *((float*) value->value.floatingPoint.buf) = (float) newFloatValue; } else if (value->value.floatingPoint.formatWidth == 64) { *((double*) value->value.floatingPoint.buf) = newFloatValue; } } } MmsValue* MmsValue_newDouble(double variable) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_FLOAT; value->value.floatingPoint.formatWidth = 64; value->value.floatingPoint.exponentWidth = 11; value->value.floatingPoint.buf = (uint8_t*) malloc(8); *((double*) value->value.floatingPoint.buf) = variable; return value; } MmsValue* MmsValue_newIntegerFromInt8(int8_t integer) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt32((int32_t) integer); return value; } MmsValue* MmsValue_newIntegerFromInt16(int16_t integer) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt32((int32_t) integer); return value; } void MmsValue_setInt8(MmsValue* value, int8_t integer) { if (value->type == MMS_INTEGER) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 1) { BerInteger_setInt32(value->value.integer, (int32_t) integer); } } } void MmsValue_setInt16(MmsValue* value, int16_t integer) { if (value->type == MMS_INTEGER) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 1) { BerInteger_setInt32(value->value.integer, (int32_t) integer); } } } void MmsValue_setInt32(MmsValue* value, int32_t integer) { if (value->type == MMS_INTEGER) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 4) { BerInteger_setInt32(value->value.integer, integer); } } } void MmsValue_setInt64(MmsValue* value, int64_t integer) { if (value->type == MMS_INTEGER) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 8) { BerInteger_setInt64(value->value.integer, integer); } } } void MmsValue_setUint32(MmsValue* value, uint32_t integer) { if (value->type == MMS_UNSIGNED) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 4) { BerInteger_setUint32(value->value.integer, integer); } } } void MmsValue_setUint16(MmsValue* value, uint16_t integer) { if (value->type == MMS_UNSIGNED) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 2) { BerInteger_setUint16(value->value.integer, integer); } } } void MmsValue_setUint8(MmsValue* value, uint8_t integer) { if (value->type == MMS_UNSIGNED) { if (Asn1PrimitiveValue_getMaxSize(value->value.integer) >= 1) { BerInteger_setUint8(value->value.integer, integer); } } } void MmsValue_setBoolean(MmsValue* value, bool boolValue) { value->value.boolean = boolValue; } bool MmsValue_getBoolean(MmsValue* value) { return value->value.boolean; } MmsValue* MmsValue_setUtcTime(MmsValue* value, uint32_t timeval) { uint8_t* timeArray = (uint8_t*) &timeval; uint8_t* valueArray = value->value.utcTime; #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(valueArray, timeArray, 4); #else memcpy(valueArray, timeArray, 4); #endif return value; } MmsValue* MmsValue_setUtcTimeMs(MmsValue* self, uint64_t timeval) { uint32_t timeval32 = (timeval / 1000LL); uint8_t* timeArray = (uint8_t*) &timeval32; uint8_t* valueArray = self->value.utcTime; #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder(valueArray, timeArray, 4); #else memcpy(valueArray, timeArray, 4); #endif uint32_t remainder = (timeval % 1000LL); uint32_t fractionOfSecond = (remainder) * 16777 + ((remainder * 216) / 1000); /* encode fraction of second */ valueArray[4] = ((fractionOfSecond >> 16) & 0xff); valueArray[5] = ((fractionOfSecond >> 8) & 0xff); valueArray[6] = (fractionOfSecond & 0xff); /* encode time quality */ valueArray[7] = 0x0a; /* 10 bit sub-second time accuracy */ return self; } void MmsValue_setUtcTimeQuality(MmsValue* self, uint8_t timeQuality) { self->value.utcTime[7] = timeQuality; } uint8_t MmsValue_getUtcTimeQuality(MmsValue* self) { return self->value.utcTime[7]; } void MmsValue_setUtcTimeByBuffer(MmsValue* self, uint8_t* buffer) { uint8_t* valueArray = self->value.utcTime; int i; for (i = 0; i < 8; i++) { valueArray[i] = buffer[i]; } } uint64_t MmsValue_getUtcTimeInMs(MmsValue* self) { uint32_t timeval32; uint8_t* valueArray = self->value.utcTime; #if (ORDER_LITTLE_ENDIAN == 1) memcpyReverseByteOrder((uint8_t*) &timeval32, valueArray, 4); #else memcpy((uint8_t*) &timeval32, valueArray, 4); #endif uint32_t fractionOfSecond = 0; fractionOfSecond = (valueArray[4] << 16); fractionOfSecond += (valueArray[5] << 8); fractionOfSecond += (valueArray[6]); uint32_t remainder = fractionOfSecond / 16777; uint64_t msVal = (timeval32 * 1000LL) + remainder; return msVal; } MmsValue* MmsValue_newIntegerFromInt32(int32_t integer) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt32(integer); return value; } MmsValue* MmsValue_newUnsignedFromUint32(uint32_t integer) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; value->type = MMS_UNSIGNED; value->value.integer = BerInteger_createFromUint32(integer); return value; } MmsValue* MmsValue_newIntegerFromInt64(int64_t integer) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue));; value->type = MMS_INTEGER; value->value.integer = BerInteger_createFromInt64(integer); return value; } /** * Convert signed integer to int32_t */ int32_t MmsValue_toInt32(MmsValue* value) { int32_t integerValue = 0; if ((value->type == MMS_INTEGER) || (value->type == MMS_UNSIGNED)) BerInteger_toInt32(value->value.integer, &integerValue); return integerValue; } uint32_t MmsValue_toUint32(MmsValue* value) { uint32_t integerValue = 0; if ((value->type == MMS_INTEGER) || (value->type == MMS_UNSIGNED)) BerInteger_toUint32(value->value.integer, &integerValue); return integerValue; } /** * Convert signed integer to int64_t and do sign extension if required */ int64_t MmsValue_toInt64(MmsValue* value) { int64_t integerValue = 0; if ((value->type == MMS_INTEGER) || (value->type == MMS_UNSIGNED)) BerInteger_toInt64(value->value.integer, &integerValue); return integerValue; } float MmsValue_toFloat(MmsValue* value) { if (value->type == MMS_FLOAT) { if (value->value.floatingPoint.formatWidth == 32) { float val; val = *((float*) (value->value.floatingPoint.buf)); return val; } else if (value->value.floatingPoint.formatWidth == 64) { float val; val = *((double*) (value->value.floatingPoint.buf)); return val; } } else printf("MmsValue_toFloat: conversion error. Wrong type!\n"); return 0.f; } double MmsValue_toDouble(MmsValue* value) { if (value->type == MMS_FLOAT) { double val; if (value->value.floatingPoint.formatWidth == 32) { val = (double) *((float*) (value->value.floatingPoint.buf)); return val; } if (value->value.floatingPoint.formatWidth == 64) { val = *((double*) (value->value.floatingPoint.buf)); return val; } } return 0.f; } uint32_t MmsValue_toUnixTimestamp(MmsValue* value) { uint32_t timestamp; uint8_t* timeArray = (uint8_t*) ×tamp; #if (ORDER_LITTLE_ENDIAN == 1) timeArray[0] = value->value.utcTime[3]; timeArray[1] = value->value.utcTime[2]; timeArray[2] = value->value.utcTime[1]; timeArray[3] = value->value.utcTime[0]; #else timeArray[0] = value->value.utcTime[0]; timeArray[1] = value->value.utcTime[1]; timeArray[2] = value->value.utcTime[2]; timeArray[3] = value->value.utcTime[3]; #endif return timestamp; } int MmsValue_getSizeInMemory(MmsValue* self) { int memorySize = sizeof(MmsValue); switch(self->type) { case MMS_ARRAY: case MMS_STRUCTURE: { memorySize += (sizeof(MmsValue*) * self->value.structure.size); int i; for (i = 0; i < self->value.structure.size; i++) memorySize += MmsValue_getSizeInMemory(self->value.structure.components[i]); } break; case MMS_BIT_STRING: memorySize += bitStringByteSize(self); break; case MMS_INTEGER: case MMS_UNSIGNED: memorySize += sizeof(Asn1PrimitiveValue); memorySize += self->value.integer->maxSize; break; case MMS_FLOAT: memorySize += (self->value.floatingPoint.formatWidth / 8); break; case MMS_OCTET_STRING: memorySize += self->value.octetString.maxSize; break; case MMS_STRING: case MMS_VISIBLE_STRING: memorySize += strlen(self->value.visibleString.buf); memorySize += 1; /* add space for 0 character */ break; default: break; } return memorySize; } uint8_t* MmsValue_cloneToBuffer(MmsValue* self, uint8_t* destinationAddress) { MmsValue* newValue = (MmsValue*) destinationAddress; memcpy(destinationAddress, self, sizeof(MmsValue)); destinationAddress += sizeof(MmsValue); switch (self->type) { case MMS_ARRAY: case MMS_STRUCTURE: { newValue->value.structure.components = (MmsValue**) destinationAddress; destinationAddress += (sizeof(MmsValue*) * self->value.structure.size); int i; for (i = 0; i < self->value.structure.size; i++) { newValue->value.structure.components[i] = (MmsValue*) destinationAddress; destinationAddress = MmsValue_cloneToBuffer(self->value.structure.components[i], destinationAddress); } } break; case MMS_BIT_STRING: memcpy(destinationAddress, self->value.bitString.buf, bitStringByteSize(self)); newValue->value.bitString.buf = destinationAddress; destinationAddress += bitStringByteSize(self); break; case MMS_INTEGER: case MMS_UNSIGNED: { Asn1PrimitiveValue* newAsn1Value = (Asn1PrimitiveValue*) destinationAddress; memcpy(destinationAddress, self->value.integer, sizeof(Asn1PrimitiveValue)); destinationAddress += sizeof(Asn1PrimitiveValue); newAsn1Value->octets = destinationAddress; memcpy(destinationAddress, self->value.integer->octets, self->value.integer->maxSize); destinationAddress += self->value.integer->maxSize; } break; case MMS_FLOAT: { int floatSizeInBytes = (self->value.floatingPoint.formatWidth / 8); newValue->value.floatingPoint.buf = destinationAddress; memcpy(destinationAddress, self->value.floatingPoint.buf, floatSizeInBytes); destinationAddress += floatSizeInBytes; } break; case MMS_OCTET_STRING: newValue->value.octetString.buf = destinationAddress; memcpy(destinationAddress, self->value.octetString.buf, self->value.octetString.maxSize); destinationAddress += self->value.octetString.maxSize; break; case MMS_STRING: case MMS_VISIBLE_STRING: newValue->value.visibleString.buf = (char*) destinationAddress; newValue->value.visibleString.size = self->value.visibleString.size; strcpy((char*) destinationAddress, self->value.visibleString.buf); destinationAddress += (strlen(self->value.visibleString.buf) + 1); break; default: break; } return destinationAddress; } // create a deep clone MmsValue* MmsValue_clone(MmsValue* value) { MmsValue* newValue = (MmsValue*) calloc(1, sizeof(MmsValue)); newValue->deleteValue = value->deleteValue; newValue->type = value->type; int size; switch(value->type) { case MMS_ARRAY: case MMS_STRUCTURE: { int componentCount = value->value.structure.size; newValue->value.structure.size = componentCount; newValue->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); int i; for (i = 0; i < componentCount; i++) { newValue->value.structure.components[i] = MmsValue_clone(value->value.structure.components[i]); } } break; case MMS_INTEGER: case MMS_UNSIGNED: newValue->value.integer = Asn1PrimitiveValue_clone(value->value.integer); break; case MMS_FLOAT: newValue->value.floatingPoint.formatWidth = value->value.floatingPoint.formatWidth; newValue->value.floatingPoint.exponentWidth = value->value.floatingPoint.exponentWidth; size = value->value.floatingPoint.formatWidth / 8; newValue->value.floatingPoint.buf = (uint8_t*) malloc(size); memcpy(newValue->value.floatingPoint.buf, value->value.floatingPoint.buf, size); break; case MMS_BIT_STRING: newValue->value.bitString.size = value->value.bitString.size; size = bitStringByteSize(value); newValue->value.bitString.buf = (uint8_t*) malloc(size); memcpy(newValue->value.bitString.buf, value->value.bitString.buf, size); break; case MMS_BOOLEAN: newValue->value.boolean = value->value.boolean; break; case MMS_OCTET_STRING: size = value->value.octetString.size; newValue->value.octetString.size = size; newValue->value.octetString.maxSize = value->value.octetString.maxSize; newValue->value.octetString.buf = (uint8_t*) malloc(value->value.octetString.maxSize); memcpy(newValue->value.octetString.buf, value->value.octetString.buf, size); break; case MMS_UTC_TIME: memcpy(newValue->value.utcTime, value->value.utcTime, 8); break; case MMS_BINARY_TIME: newValue->value.binaryTime.size = value->value.binaryTime.size; memcpy(newValue->value.binaryTime.buf, value->value.binaryTime.buf, 6); break; case MMS_VISIBLE_STRING: case MMS_STRING: size = value->value.visibleString.size; newValue->value.visibleString.buf = (char*) malloc(size + 1); newValue->value.visibleString.size = size; strcpy(newValue->value.visibleString.buf, value->value.visibleString.buf); break; case MMS_DATA_ACCESS_ERROR: newValue->value.dataAccessError = value->value.dataAccessError; break; default: break; } return newValue; } uint32_t MmsValue_getArraySize(MmsValue* value) { return value->value.structure.size; } void MmsValue_deleteIfNotNull(MmsValue* value) { if (value != NULL) MmsValue_delete(value); } void MmsValue_delete(MmsValue* value) { switch (value->type) { case MMS_INTEGER: case MMS_UNSIGNED: Asn1PrimitiveValue_destroy(value->value.integer); break; case MMS_FLOAT: free(value->value.floatingPoint.buf); break; case MMS_BIT_STRING: free(value->value.bitString.buf); break; case MMS_OCTET_STRING: free(value->value.octetString.buf); break; case MMS_VISIBLE_STRING: case MMS_STRING: if (value->value.visibleString.buf != NULL) free(value->value.visibleString.buf); break; case MMS_ARRAY: case MMS_STRUCTURE: { int componentCount = value->value.structure.size; int i; for (i = 0; i < componentCount; i++) { if (value->value.structure.components[i] != NULL) MmsValue_delete(value->value.structure.components[i]); } } free(value->value.structure.components); break; default: break; } free(value); } /* delete only when deleteValue field set */ void MmsValue_deleteConditional(MmsValue* value) { if (value->deleteValue == 1) { switch (value->type) { case MMS_INTEGER: case MMS_UNSIGNED: Asn1PrimitiveValue_destroy(value->value.integer); break; case MMS_FLOAT: free(value->value.floatingPoint.buf); break; case MMS_BIT_STRING: free(value->value.bitString.buf); break; case MMS_OCTET_STRING: free(value->value.octetString.buf); break; case MMS_VISIBLE_STRING: case MMS_STRING: if (value->value.visibleString.buf != NULL) free(value->value.visibleString.buf); break; case MMS_ARRAY: case MMS_STRUCTURE: { int componentCount = value->value.structure.size; int i; for (i = 0; i < componentCount; i++) { if (value->value.structure.components[i] != NULL) MmsValue_deleteConditional(value->value.structure.components[i]); } } free(value->value.structure.components); break; default: break; } free(value); } } MmsValue* MmsValue_newInteger(int size /*integer size in bits*/) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_INTEGER; if (size <= 32) value->value.integer = BerInteger_createInt32(); else value->value.integer = BerInteger_createInt64(); return value; } MmsValue* MmsValue_newUnsigned(int size /*integer size in bits*/) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_UNSIGNED; if (size <= 32) value->value.integer = BerInteger_createInt32(); else value->value.integer = BerInteger_createInt64(); return value; } MmsValue* MmsValue_newBoolean(bool boolean) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); self->type = MMS_BOOLEAN; if (boolean == true) self->value.boolean = 1; else self->value.boolean = 0; return self; } MmsValue* MmsValue_newOctetString(int size, int maxSize) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); self->type = MMS_OCTET_STRING; self->value.octetString.size = size; self->value.octetString.maxSize = maxSize; self->value.octetString.buf = (uint8_t*) calloc(1, maxSize); return self; } void MmsValue_setOctetString(MmsValue* self, uint8_t* buf, int size) { if (size <= self->value.octetString.maxSize) { memcpy(self->value.octetString.buf, buf, size); self->value.octetString.size = size; } } uint16_t MmsValue_getOctetStringSize(MmsValue* self) { return self->value.octetString.size; } uint16_t MmsValue_getOctetStringMaxSize(MmsValue* self) { return self->value.octetString.maxSize; } uint8_t* MmsValue_getOctetStringBuffer(MmsValue* self) { return self->value.octetString.buf; } MmsValue* MmsValue_newStructure(MmsVariableSpecification* typeSpec) { MmsValue* self = (MmsValue*) calloc(1, sizeof(MmsValue)); self->type = MMS_STRUCTURE; int componentCount = typeSpec->typeSpec.structure.elementCount; self->value.structure.size = componentCount; self->value.structure.components = (MmsValue**) calloc(componentCount, sizeof(MmsValue*)); int i; for (i = 0; i < componentCount; i++) { self->value.structure.components[i] = MmsValue_newDefaultValue(typeSpec->typeSpec.structure.elements[i]); } return self; } MmsValue* MmsValue_newDefaultValue(MmsVariableSpecification* typeSpec) { MmsValue* value = NULL; switch (typeSpec->type) { case MMS_INTEGER: value = MmsValue_newInteger(typeSpec->typeSpec.integer); break; case MMS_UNSIGNED: value = MmsValue_newUnsigned(typeSpec->typeSpec.unsignedInteger); break; case MMS_FLOAT: value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_FLOAT; value->value.floatingPoint.exponentWidth = typeSpec->typeSpec.floatingpoint.exponentWidth; value->value.floatingPoint.formatWidth = typeSpec->typeSpec.floatingpoint.formatWidth; value->value.floatingPoint.buf = (uint8_t*) calloc(1, typeSpec->typeSpec.floatingpoint.formatWidth / 8); break; case MMS_BIT_STRING: value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_BIT_STRING; { int bitSize = abs(typeSpec->typeSpec.bitString); value->value.bitString.size = bitSize; int size = (bitSize / 8) + ((bitSize % 8) > 0); value->value.bitString.buf = (uint8_t*) calloc(1, size); } break; case MMS_OCTET_STRING: value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_OCTET_STRING; if (typeSpec->typeSpec.octetString < 0) value->value.octetString.size = 0; else value->value.octetString.size = typeSpec->typeSpec.octetString; value->value.octetString.maxSize = abs(typeSpec->typeSpec.octetString); value->value.octetString.buf = (uint8_t*) calloc(1, abs(typeSpec->typeSpec.octetString)); break; case MMS_VISIBLE_STRING: value = MmsValue_newVisibleStringWithSize(abs(typeSpec->typeSpec.visibleString)); break; case MMS_BOOLEAN: value = MmsValue_newBoolean(false); break; case MMS_UTC_TIME: value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; break; case MMS_ARRAY: value = MmsValue_createArray(typeSpec->typeSpec.array.elementTypeSpec, typeSpec->typeSpec.array.elementCount); break; case MMS_STRUCTURE: value = MmsValue_newStructure(typeSpec); break; case MMS_STRING: value = MmsValue_newMmsStringWithSize(abs(typeSpec->typeSpec.visibleString)); break; case MMS_BINARY_TIME: if (typeSpec->typeSpec.binaryTime == 4) value = MmsValue_newBinaryTime(true); else value = MmsValue_newBinaryTime(false); break; default: break; } if (value != NULL) value->deleteValue = 0; return value; } static inline void setVisibleStringValue(MmsValue* value, char* string) { if (value->value.visibleString.buf != NULL) { if (string != NULL) { int newStringSize = strlen(string); if (newStringSize > value->value.visibleString.size) { free(value->value.visibleString.buf); value->value.visibleString.buf = (char*) malloc(newStringSize + 1); value->value.visibleString.size = newStringSize; } strncpy(value->value.visibleString.buf, string, value->value.visibleString.size + 1); value->value.visibleString.buf[value->value.visibleString.size] = 0; } else value->value.visibleString.buf[0] = 0; } } static MmsValue* MmsValue_newString(char* string, MmsType type) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = type; if (string == NULL) { value->value.visibleString.size = 0; value->value.visibleString.buf = NULL; } else { int stringSize = strlen(string); value->value.visibleString.size = stringSize; value->value.visibleString.buf = (char*) malloc(stringSize + 1); setVisibleStringValue(value, string); } return value; } MmsValue* MmsValue_newVisibleString(char* string) { return MmsValue_newString(string, MMS_VISIBLE_STRING); } static MmsValue* MmsValue_newStringWithSize(int size, MmsType type) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = type; value->value.visibleString.size = size; value->value.visibleString.buf = (char*) malloc(size + 1); value->value.visibleString.buf[0] = 0; return value; } MmsValue* MmsValue_newVisibleStringWithSize(int size) { return MmsValue_newStringWithSize(size, MMS_VISIBLE_STRING); } MmsValue* MmsValue_newMmsString(char* string) { return MmsValue_newString(string, MMS_STRING); } MmsValue* MmsValue_newMmsStringWithSize(int size) { return MmsValue_newStringWithSize(size, MMS_STRING); } MmsValue* MmsValue_newBinaryTime(bool timeOfDay) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_BINARY_TIME; if (timeOfDay == true) value->value.binaryTime.size = 4; else value->value.binaryTime.size = 6; return value; } void MmsValue_setBinaryTime(MmsValue* value, uint64_t timestamp) { uint64_t mmsTime = timestamp - (441763200000LL); uint8_t* binaryTimeBuf = value->value.binaryTime.buf; if (value->value.binaryTime.size == 6) { uint16_t daysDiff = mmsTime / (86400000LL); uint8_t* daysDiffBuf = (uint8_t*) &daysDiff; #if (ORDER_LITTLE_ENDIAN == 1) binaryTimeBuf[4] = daysDiffBuf[1]; binaryTimeBuf[5] = daysDiffBuf[0]; #else binaryTimeBuf[4] = daysDiffBuf[0]; binaryTimeBuf[5] = daysDiffBuf[1]; #endif } uint32_t msSinceMidnight = mmsTime % (86400000LL); uint8_t* msSinceMidnightBuf = (uint8_t*) &msSinceMidnight; #if (ORDER_LITTLE_ENDIAN == 1) binaryTimeBuf[0] = msSinceMidnightBuf[3]; binaryTimeBuf[1] = msSinceMidnightBuf[2]; binaryTimeBuf[2] = msSinceMidnightBuf[1]; binaryTimeBuf[3] = msSinceMidnightBuf[0]; #else binaryTimeBuf[0] = msSinceMidnightBuf[0]; binaryTimeBuf[1] = msSinceMidnightBuf[1]; binaryTimeBuf[2] = msSinceMidnightBuf[2]; binaryTimeBuf[3] = msSinceMidnightBuf[3]; #endif } uint64_t MmsValue_getBinaryTimeAsUtcMs(MmsValue* value) { uint64_t timestamp = 0; uint8_t* binaryTimeBuf = value->value.binaryTime.buf; if (value->value.binaryTime.size == 6) { uint16_t daysDiff; daysDiff = binaryTimeBuf[4] * 256; daysDiff += binaryTimeBuf[5]; uint64_t mmsTime; mmsTime = daysDiff * (86400000LL); timestamp = mmsTime + (441763200000LL); } uint32_t msSinceMidnight = 0; msSinceMidnight = binaryTimeBuf[0] << 24; msSinceMidnight += binaryTimeBuf[1] << 16; msSinceMidnight += binaryTimeBuf[2] << 8; msSinceMidnight += binaryTimeBuf[3]; timestamp += msSinceMidnight; return timestamp; } MmsDataAccessError MmsValue_getDataAccessError(MmsValue* self) { return self->value.dataAccessError; } void MmsValue_setMmsString(MmsValue* value, char* string) { if (value->type == MMS_STRING) { assert(value->value.visibleString.buf != NULL); setVisibleStringValue(value, string); } } static MmsValue* MmsValue_newStringFromByteArray(uint8_t* byteArray, int size, MmsType type) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = type; value->value.visibleString.buf = createStringFromBuffer(byteArray, size); value->value.visibleString.size = size; return value; } MmsValue* MmsValue_newVisibleStringFromByteArray(uint8_t* byteArray, int size) { return MmsValue_newStringFromByteArray(byteArray, size, MMS_VISIBLE_STRING); } MmsValue* MmsValue_newMmsStringFromByteArray(uint8_t* byteArray, int size) { return MmsValue_newStringFromByteArray(byteArray, size, MMS_STRING); } void MmsValue_setVisibleString(MmsValue* value, char* string) { if (value->type == MMS_VISIBLE_STRING) { assert(value->value.visibleString.buf != NULL); setVisibleStringValue(value, string); } } char* MmsValue_toString(MmsValue* value) { if ((value->type == MMS_VISIBLE_STRING) || (value->type == MMS_STRING)) return value->value.visibleString.buf; return NULL; } MmsValue* MmsValue_newUtcTime(uint32_t timeval) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; uint8_t* timeArray = (uint8_t*) &timeval; uint8_t* valueArray = value->value.utcTime; #if (ORDER_LITTLE_ENDIAN == 1) valueArray[0] = timeArray[3]; valueArray[1] = timeArray[2]; valueArray[2] = timeArray[1]; valueArray[3] = timeArray[0]; #else valueArray[0] = timeArray[0]; valueArray[1] = timeArray[1]; valueArray[2] = timeArray[2]; valueArray[3] = timeArray[3]; #endif return value; } MmsValue* MmsValue_newUtcTimeByMsTime(uint64_t timeval) { MmsValue* value = (MmsValue*) calloc(1, sizeof(MmsValue)); value->type = MMS_UTC_TIME; MmsValue_setUtcTimeMs(value, timeval); return value; } MmsValue* MmsValue_createArray(MmsVariableSpecification* elementType, int size) { MmsValue* array = (MmsValue*) calloc(1, sizeof(MmsValue)); array->type = MMS_ARRAY; array->value.structure.size = size; array->value.structure.components = (MmsValue**) calloc(size, sizeof(MmsValue*)); int i; for (i = 0; i < size; i++) { array->value.structure.components[i] = MmsValue_newDefaultValue(elementType); } return array; } MmsValue* MmsValue_createEmtpyArray(int size) { MmsValue* array = (MmsValue*) calloc(1, sizeof(MmsValue)); array->type = MMS_ARRAY; array->value.structure.size = size; array->value.structure.components = (MmsValue**) calloc(size, sizeof(MmsValue*)); int i; for (i = 0; i < size; i++) { array->value.structure.components[i] = NULL; } return array; } MmsValue* MmsValue_createEmptyStructure(int size) { MmsValue* structure = MmsValue_createEmtpyArray(size); structure->type = MMS_STRUCTURE; return structure; } void MmsValue_setElement(MmsValue* complexValue, int index, MmsValue* elementValue) { if ((complexValue->type != MMS_ARRAY) && (complexValue->type != MMS_STRUCTURE)) return; if ((index < 0) || (index >= complexValue->value.structure.size)) return; complexValue->value.structure.components[index] = elementValue; } MmsValue* MmsValue_getElement(MmsValue* complexValue, int index) { if ((complexValue->type != MMS_ARRAY) && (complexValue->type != MMS_STRUCTURE)) return NULL; if ((index < 0) || (index >= complexValue->value.structure.size)) return NULL; return complexValue->value.structure.components[index]; } void MmsValue_setDeletable(MmsValue* value) { value->deleteValue = 1; } void MmsValue_setDeletableRecursive(MmsValue* value) { if ((MmsValue_getType(value) == MMS_ARRAY) || (MmsValue_getType(value) == MMS_STRUCTURE)) { int i; int elementCount = MmsValue_getArraySize(value); for (i = 0; i < elementCount; i++) MmsValue_setDeletableRecursive(MmsValue_getElement(value, i)); } MmsValue_setDeletable(value); } int MmsValue_isDeletable(MmsValue* value) { return value->deleteValue; } MmsType MmsValue_getType(MmsValue* value) { return value->type; } MmsValue* MmsValue_getSubElement(MmsValue* self, MmsVariableSpecification* varSpec, char* mmsPath) { return MmsVariableSpecification_getChildValue(varSpec, self, mmsPath); } char* MmsValue_getTypeString(MmsValue* self) { switch (MmsValue_getType(self)) { case MMS_ARRAY: return "array"; case MMS_BCD: return "bcd"; case MMS_BINARY_TIME: return "binary-time"; case MMS_BIT_STRING: return "bit-string"; case MMS_BOOLEAN: return "boolean"; case MMS_DATA_ACCESS_ERROR: return "access-error"; case MMS_FLOAT: return "float"; case MMS_GENERALIZED_TIME: return "generalized-time"; case MMS_INTEGER: return "integer"; case MMS_OBJ_ID: return "oid"; case MMS_STRING: return "mms-string"; case MMS_STRUCTURE: return "structure"; case MMS_OCTET_STRING: return "octet-string"; case MMS_UNSIGNED: return "unsigned"; case MMS_UTC_TIME: return "utc-time"; case MMS_VISIBLE_STRING: return "visible-string"; default: return "unknown(error)"; } } char* MmsValue_printToBuffer(MmsValue* self, char* buffer, int bufferSize) { switch (MmsValue_getType(self)) { case MMS_STRUCTURE: case MMS_ARRAY: { buffer[0] = '{'; int bufPos = 1; int arraySize = MmsValue_getArraySize(self); int i; for (i = 0; i < arraySize; i++) { char* currentStr = MmsValue_printToBuffer(MmsValue_getElement(self, i), buffer + bufPos, bufferSize - bufPos); bufPos += strlen(currentStr); if (bufPos >= bufferSize) break; if (i != (arraySize - 1)) { buffer[bufPos++] = ','; } } buffer[bufPos++] = '}'; buffer[bufPos] = 0; } break; case MMS_BINARY_TIME: Conversions_msTimeToGeneralizedTime(MmsValue_getBinaryTimeAsUtcMs(self), (uint8_t*) buffer); break; case MMS_BIT_STRING: { int bufPos = 0; int size = MmsValue_getBitStringSize(self); int i; for (i = 0; i < size; i++) { if (MmsValue_getBitStringBit(self, i)) buffer[bufPos++] = '1'; else buffer[bufPos++] = '0'; } buffer[bufPos] = 0; } break; case MMS_BOOLEAN: if (MmsValue_getBoolean(self)) strncpy(buffer, "true", bufferSize); else strncpy(buffer, "false", bufferSize); break; case MMS_DATA_ACCESS_ERROR: snprintf(buffer, bufferSize, "error %i", self->value.dataAccessError); break; case MMS_FLOAT: snprintf(buffer, bufferSize, "%f", MmsValue_toFloat(self)); break; case MMS_GENERALIZED_TIME: strncpy(buffer, "generalized time", bufferSize); break; case MMS_INTEGER: snprintf(buffer, bufferSize, "%i", MmsValue_toInt32(self)); break; case MMS_OCTET_STRING: { int size = MmsValue_getOctetStringSize(self); int bufPos = 0; int i; for (i = 0; i < size; i++) { snprintf(buffer + bufPos, bufferSize - bufPos, "%02x", self->value.octetString.buf[i]); bufPos += 2; if (bufPos >= bufferSize) break; } } break; case MMS_UNSIGNED: snprintf(buffer, bufferSize, "%u", MmsValue_toUint32(self)); break; case MMS_UTC_TIME: Conversions_msTimeToGeneralizedTime(MmsValue_getUtcTimeInMs(self), (uint8_t*) buffer); break; case MMS_STRING: case MMS_VISIBLE_STRING: strncpy(buffer, MmsValue_toString(self), bufferSize); break; default: strncpy(buffer, "unknown type", bufferSize); break; } return buffer; }