diff options
Diffstat (limited to 'libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c')
-rwxr-xr-x | libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c new file mode 100755 index 00000000..8e547743 --- /dev/null +++ b/libccnx-common/ccnx/common/codec/ccnxCodec_TlvDecoder.c @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2017 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * We use a 2-byte T and a 2-byte L + * + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <LongBow/runtime.h> +#include <parc/algol/parc_Memory.h> +#include <parc/algol/parc_Buffer.h> +#include <ccnx/common/codec/ccnxCodec_NetworkBuffer.h> + +#include <ccnx/common/codec/ccnxCodec_TlvDecoder.h> + +struct ccnx_codec_tlv_decoder { + // we use a read only buffer because we want independent + // position and limit from whatever the user gives us. + PARCBuffer *buffer; + + CCNxCodecError *error; +}; + +CCNxCodecTlvDecoder * +ccnxCodecTlvDecoder_Create(PARCBuffer *buffer) +{ + assertNotNull(buffer, "Parameter buffer must be non-null"); + + CCNxCodecTlvDecoder *decoder = parcMemory_AllocateAndClear(sizeof(CCNxCodecTlvDecoder)); + assertNotNull(decoder, "parcMemory_AllocateAndClear(%zu) returned NULL", sizeof(CCNxCodecTlvDecoder)); + + // create a reference but with independent position + limit from what the user gives us + decoder->buffer = parcBuffer_Slice(buffer); + + return decoder; +} + +void +ccnxCodecTlvDecoder_Destroy(CCNxCodecTlvDecoder **decoderPtr) +{ + assertNotNull(decoderPtr, "Parameter must be non-null double pointer"); + assertNotNull(*decoderPtr, "Parameter must dereferecne to non-null pointer"); + CCNxCodecTlvDecoder *decoder = *decoderPtr; + parcBuffer_Release(&decoder->buffer); + + + if (decoder->error) { + ccnxCodecError_Release(&decoder->error); + } + + parcMemory_Deallocate((void **) &decoder); + *decoderPtr = NULL; +} + +bool +ccnxCodecTlvDecoder_IsEmpty(CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return (!parcBuffer_HasRemaining(decoder->buffer)); +} + +bool +ccnxCodecTlvDecoder_EnsureRemaining(CCNxCodecTlvDecoder *decoder, size_t bytes) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return parcBuffer_Remaining(decoder->buffer) >= bytes; +} + +size_t +ccnxCodecTlvDecoder_Remaining(const CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return parcBuffer_Remaining(decoder->buffer); +} + +uint16_t +ccnxCodecTlvDecoder_PeekType(CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + size_t position = parcBuffer_Position(decoder->buffer); + uint16_t type = parcBuffer_GetUint16(decoder->buffer); + parcBuffer_SetPosition(decoder->buffer, position); + return type; +} + +uint16_t +ccnxCodecTlvDecoder_GetType(CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return parcBuffer_GetUint16(decoder->buffer); +} + +uint16_t +ccnxCodecTlvDecoder_GetLength(CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return parcBuffer_GetUint16(decoder->buffer); +} + +PARCBuffer * +ccnxCodecTlvDecoder_GetValue(CCNxCodecTlvDecoder *decoder, uint16_t length) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + PARCBuffer *value = NULL; + + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { + value = parcBuffer_Slice(decoder->buffer); + parcBuffer_SetLimit(value, length); + + size_t position = parcBuffer_Position(decoder->buffer); + position += length; + parcBuffer_SetPosition(decoder->buffer, position); + } + + return value; +} + +PARCBuffer * +ccnxCodecTlvDecoder_GetBuffer(CCNxCodecTlvDecoder *decoder, uint16_t type) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + + PARCBuffer *output = NULL; + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, 4)) { + if (ccnxCodecTlvDecoder_PeekType(decoder) == type) { + (void) ccnxCodecTlvDecoder_GetType(decoder); + uint16_t length = ccnxCodecTlvDecoder_GetLength(decoder); + output = ccnxCodecTlvDecoder_GetValue(decoder, length); + } + } + return output; +} + +CCNxCodecTlvDecoder * +ccnxCodecTlvDecoder_GetContainer(CCNxCodecTlvDecoder *decoder, uint16_t length) +{ + CCNxCodecTlvDecoder *innerDecoder = NULL; + if (ccnxCodecTlvDecoder_EnsureRemaining(decoder, length)) { + PARCBuffer *value = ccnxCodecTlvDecoder_GetValue(decoder, length); + innerDecoder = ccnxCodecTlvDecoder_Create(value); + parcBuffer_Release(&value); + } + return innerDecoder; +} + +bool +ccnxCodecTlvDecoder_GetUint8(CCNxCodecTlvDecoder *decoder, uint16_t type, uint8_t *output) +{ + const size_t valueLength = 1; + bool success = false; + if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) { + if (ccnxCodecTlvDecoder_PeekType(decoder) == type) { + // advance the buffer + (void) ccnxCodecTlvDecoder_GetType(decoder); + if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) { + *output = parcBuffer_GetUint8(decoder->buffer); + success = true; + } + } + } + return success; +} + +bool +ccnxCodecTlvDecoder_GetUint16(CCNxCodecTlvDecoder *decoder, uint16_t type, uint16_t *output) +{ + const size_t valueLength = 2; + bool success = false; + if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) { + if (ccnxCodecTlvDecoder_PeekType(decoder) == type) { + // advance the buffer + (void) ccnxCodecTlvDecoder_GetType(decoder); + if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) { + *output = parcBuffer_GetUint16(decoder->buffer); + success = true; + } + } + } + return success; +} + +bool +ccnxCodecTlvDecoder_GetUint32(CCNxCodecTlvDecoder *decoder, uint16_t type, uint32_t *output) +{ + const size_t valueLength = 4; + bool success = false; + if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) { + if (ccnxCodecTlvDecoder_PeekType(decoder) == type) { + // advance the buffer + (void) ccnxCodecTlvDecoder_GetType(decoder); + if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) { + *output = parcBuffer_GetUint32(decoder->buffer); + success = true; + } + } + } + return success; +} + +bool +ccnxCodecTlvDecoder_GetUint64(CCNxCodecTlvDecoder *decoder, uint16_t type, uint64_t *output) +{ + const size_t valueLength = 8; + bool success = false; + if (parcBuffer_Remaining(decoder->buffer) >= 4 + valueLength) { + if (ccnxCodecTlvDecoder_PeekType(decoder) == type) { + // advance the buffer + (void) ccnxCodecTlvDecoder_GetType(decoder); + if (ccnxCodecTlvDecoder_GetLength(decoder) == valueLength) { + *output = parcBuffer_GetUint64(decoder->buffer); + success = true; + } + } + } + return success; +} + + +size_t +ccnxCodecTlvDecoder_Position(CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return parcBuffer_Position(decoder->buffer); +} + +bool +ccnxCodecTlvDecoder_Advance(CCNxCodecTlvDecoder *decoder, uint16_t length) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + bool success = false; + if (parcBuffer_Remaining(decoder->buffer) >= length) { + size_t position = parcBuffer_Position(decoder->buffer); + position += length; + parcBuffer_SetPosition(decoder->buffer, position); + success = true; + } + return success; +} + +bool +ccnxCodecTlvDecoder_BufferToVarInt(PARCBuffer *buffer, uint16_t length, uint64_t *output) +{ + assertNotNull(buffer, "Parameter buffer must be non-null"); + assertNotNull(output, "Parameter output must be non-null"); + + bool success = false; + if (length >= 1 && length <= 8 && parcBuffer_Remaining(buffer) >= length) { + uint64_t value = 0; + for (int i = 0; i < length; i++) { + value = value << 8 | parcBuffer_GetUint8(buffer); + } + *output = value; + success = true; + } + return success; +} + +bool +ccnxCodecTlvDecoder_GetVarInt(CCNxCodecTlvDecoder *decoder, uint16_t length, uint64_t *output) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return ccnxCodecTlvDecoder_BufferToVarInt(decoder->buffer, length, output); +} + +bool +ccnxCodecTlvDecoder_HasError(const CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + if (decoder->error) { + return true; + } + + return false; +} + + +bool +ccnxCodecTlvDecoder_SetError(CCNxCodecTlvDecoder *decoder, CCNxCodecError *error) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + if (ccnxCodecTlvDecoder_HasError(decoder)) { + return false; + } + + decoder->error = ccnxCodecError_Acquire(error); + return true; +} + + +void +ccnxCodecTlvDecoder_ClearError(CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + if (ccnxCodecTlvDecoder_HasError(decoder)) { + ccnxCodecError_Release(&decoder->error); + } +} + + +CCNxCodecError * +ccnxCodecTlvDecoder_GetError(const CCNxCodecTlvDecoder *decoder) +{ + assertNotNull(decoder, "Parameter decoder must be non-null"); + return decoder->error; +} |