/* * mms_access_result.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_access_result.h" #include "mms_server_internal.h" #include "mms_value_internal.h" static int encodeArrayAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode) { if (value == NULL) // TODO report internal error return 0; int elementsSize = 0; int i; int size; int arraySize = MmsValue_getArraySize(value); for (i = 0; i < arraySize; i++) { MmsValue* element = MmsValue_getElement(value, i); elementsSize += mmsServer_encodeAccessResult(element, NULL, 0, false); } if (encode) { buffer[bufPos++] = 0xa1; /* tag for array */ bufPos = BerEncoder_encodeLength(elementsSize, buffer, bufPos); for (i = 0; i < arraySize; i++) { MmsValue* element = MmsValue_getElement(value, i); bufPos = mmsServer_encodeAccessResult(element, buffer, bufPos, true); } size = bufPos; } else { size = 1 + elementsSize + BerEncoder_determineLengthSize(elementsSize); } return size; } static int encodeStructuredAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode) { if (value == NULL) // TODO report internal error return 0; int componentsSize = 0; int i; int size; int components = value->value.structure.size; for (i = 0; i < components; i++) { MmsValue* component = value->value.structure.components[i]; componentsSize += mmsServer_encodeAccessResult(component, NULL, 0, false); } if (encode) { buffer[bufPos++] = 0xa2; /* tag for structure */ bufPos = BerEncoder_encodeLength(componentsSize, buffer, bufPos); for (i = 0; i < components; i++) { MmsValue* component = value->value.structure.components[i]; bufPos = mmsServer_encodeAccessResult(component, buffer, bufPos, true); } size = bufPos; } else { size = 1 + componentsSize + BerEncoder_determineLengthSize(componentsSize); } return size; } int mmsServer_encodeAccessResult(MmsValue* value, uint8_t* buffer, int bufPos, bool encode) { // if (value == NULL) // TODO report internal error // return 0; int size; switch (value->type) { case MMS_BOOLEAN: if (encode) bufPos = BerEncoder_encodeBoolean(0x83, value->value.boolean, buffer, bufPos); else size = 3; break; case MMS_STRUCTURE: if (encode) bufPos = encodeStructuredAccessResult(value, buffer, bufPos, true); else size = encodeStructuredAccessResult(value, buffer, bufPos, false); break; case MMS_ARRAY: if (encode) bufPos = encodeArrayAccessResult(value, buffer, bufPos, true); else size = encodeArrayAccessResult(value, buffer, bufPos, false); break; case MMS_DATA_ACCESS_ERROR: if (encode) { int length = BerEncoder_UInt32determineEncodedSize((uint32_t) value->value.dataAccessError); bufPos = BerEncoder_encodeTL(0x80, length, buffer, bufPos); bufPos = BerEncoder_encodeUInt32((uint32_t) value->value.dataAccessError, buffer, bufPos); } else size = 2 + BerEncoder_UInt32determineEncodedSize((uint32_t) value->value.dataAccessError); break; case MMS_VISIBLE_STRING: if (encode) bufPos = BerEncoder_encodeStringWithTag(0x8a, value->value.visibleString.buf, buffer, bufPos); else size = BerEncoder_determineEncodedStringSize(value->value.visibleString.buf); break; case MMS_UNSIGNED: if (encode) bufPos = BerEncoder_encodeAsn1PrimitiveValue(0x86, value->value.integer, buffer, bufPos); else size = 2 + value->value.integer->size; break; case MMS_INTEGER: if (encode) bufPos = BerEncoder_encodeAsn1PrimitiveValue(0x85, value->value.integer, buffer, bufPos); else size = 2 + value->value.integer->size; break; case MMS_UTC_TIME: if (encode) bufPos = BerEncoder_encodeOctetString(0x91, value->value.utcTime, 8, buffer, bufPos); else size = 10; break; case MMS_BIT_STRING: if (encode) bufPos = BerEncoder_encodeBitString(0x84, value->value.bitString.size, value->value.bitString.buf, buffer, bufPos); else size = BerEncoder_determineEncodedBitStringSize(value->value.bitString.size); break; case MMS_BINARY_TIME: if (encode) bufPos = BerEncoder_encodeOctetString(0x8c, value->value.binaryTime.buf, value->value.binaryTime.size, buffer, bufPos); else size = 2 + value->value.binaryTime.size; break; case MMS_OCTET_STRING: if (encode) bufPos = BerEncoder_encodeOctetString(0x89, value->value.octetString.buf, value->value.octetString.size, buffer, bufPos); else size = 1 + BerEncoder_determineLengthSize(value->value.octetString.size) + value->value.octetString.size; break; case MMS_FLOAT: { int floatSize = (value->value.floatingPoint.formatWidth / 8) + 1; if (encode) { bufPos = BerEncoder_encodeTL(0x87, floatSize, buffer, bufPos); bufPos = BerEncoder_encodeFloat(value->value.floatingPoint.buf, value->value.floatingPoint.formatWidth, value->value.floatingPoint.exponentWidth, buffer, bufPos); } else size = floatSize + 2; /* 2 for tag and length */ } break; case MMS_STRING: if (encode) bufPos = BerEncoder_encodeStringWithTag(0x90, value->value.visibleString.buf, buffer, bufPos); else size = BerEncoder_determineEncodedStringSize(value->value.visibleString.buf); break; default: if (DEBUG_MMS_SERVER) printf("encodeAccessResult: error unsupported type!\n"); size = 0; break; } if (encode) return bufPos; else return size; }