You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
libiec61850/src/mms/iso_mms/server/mms_access_result.c

227 lines
7.0 KiB
C

/*
* 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 <http://www.gnu.org/licenses/>.
*
* 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;
}