Skip to content

Commit

Permalink
Merge pull request #30 from sagar-apple/tlv
Browse files Browse the repository at this point in the history
Add TLV Parser

Merging per 3 approvals. Thanks
  • Loading branch information
woody-apple authored Mar 10, 2020
2 parents 5d5588d + c8beb25 commit f2cf5eb
Show file tree
Hide file tree
Showing 12 changed files with 6,180 additions and 6 deletions.
465 changes: 465 additions & 0 deletions src/lib/core/CHIPTLV.h

Large diffs are not rendered by default.

398 changes: 398 additions & 0 deletions src/lib/core/CHIPTLVData.hpp

Large diffs are not rendered by default.

382 changes: 382 additions & 0 deletions src/lib/core/CHIPTLVDebug.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,382 @@
/*
*
* <COPYRIGHT>
*
* 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.
*/

/**
* @file
* This file implements interfaces for debugging and logging
* CHIP TLV.
*
*/

#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif

#include <ctype.h>
#include <inttypes.h>
#include <string.h>

#include <CHIPTLV.h>
#include <CHIPTLVDebug.hpp>
#include <CHIPTLVUtilities.hpp>
#include <support/CodeUtils.h>
#include <support/logging/CHIPLogging.h>

namespace chip {

namespace TLV {

namespace Debug {

/**
* Dump the TLV element referenced by @a aReader in human-readable form using
* @a aWriter.
*
* @param[in] aWriter The writer to log the TLV data.
* @param[in] aIndent The indentation for logging the current depth into
* the TLV data.
* @param[in] aReader A read-only reference to the TLV reader containing
* the TLV data to log.
* @param[in] aDepth The current depth into the TLV data.
*
*/
static void DumpHandler(DumpWriter aWriter, const char *aIndent, const TLVReader &aReader, size_t aDepth)
{
const TLVType type = aReader.GetType();
const uint64_t tag = aReader.GetTag();
const uint32_t len = aReader.GetLength();
const uint8_t *strbuf = NULL;
CHIP_ERROR err = CHIP_NO_ERROR;
TLVReader temp;
TLVTagControl tagControl;

temp.Init(aReader);
tagControl = static_cast<TLVTagControl>(temp.GetControlByte() & kTLVTagControlMask);

aWriter("%zd ", aDepth);

for (size_t i = 0; i < aDepth; i++)
aWriter("%s", aIndent);

aWriter("%p, ", temp.GetReadPoint());

if (IsProfileTag(tag))
{
aWriter("tag[%s]: 0x%x::0x%x::0x%x, ", DecodeTagControl(tagControl), VendorIdFromTag(tag), ProfileNumFromTag(tag), TagNumFromTag(tag));
}
else if (IsContextTag(tag))
{
aWriter("tag[%s]: 0x%x, ", DecodeTagControl(tagControl), (uint32_t)ContextTag(tag));
}
else if (IsSpecialTag(tag))
{

aWriter("tag[%s]: 0x%x, ", DecodeTagControl(tagControl), tag);
}
else
{
aWriter("tag[unknown]: 0x%x, ", tag);
}

aWriter("type: %s (0x%02x), ", DecodeType(type), type);


if (TLVTypeIsContainer(type))
{
aWriter("container: ");
}
else
{
if (type == kTLVType_UTF8String || type == kTLVType_ByteString)
aWriter("length: %" PRIu32 ", ", len);

aWriter("value: ");

switch (type) {

case kTLVType_SignedInteger:
int64_t sVal;
err = temp.Get(sVal);
VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_SignedInteger"));
aWriter("%" PRIi64, sVal);
break;

case kTLVType_UnsignedInteger:
uint64_t uVal;
err = temp.Get(uVal);
VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_UnsignedInteger"));
aWriter("%" PRIu64, uVal);
break;

case kTLVType_Boolean:
bool bVal;
err = temp.Get(bVal);
VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_Boolean"));
aWriter("%s", bVal ? "true" : "false");
break;

case kTLVType_FloatingPointNumber:
double fpVal;
err = temp.Get(fpVal);
VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_FloatingPointNumber"));
aWriter("%lf", fpVal);
break;

case kTLVType_UTF8String:
err = temp.GetDataPtr(strbuf);
VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_UTF8String"));
aWriter("\"%-.*s\"", static_cast<int>(len), strbuf);
break;

case kTLVType_ByteString:
err = temp.GetDataPtr(strbuf);
VerifyOrExit(err == CHIP_NO_ERROR, aWriter("Error in kTLVType_ByteString"));
aWriter("%p\n", strbuf);
break;

case kTLVType_Null:
aWriter("NULL");
break;

case kTLVType_NotSpecified:
aWriter("Not Specified");
break;

default:
aWriter("Error: Type is not primitive.");
break;

}
}

exit:
aWriter("\n");
}

/**
* Decode a TLV tag control with a descriptive string.
*
* @param[in] aTagControl The TLV tag control to decode and for which to return
* a descriptive string.
*
* @return A pointer to a NULL-terminated string describing the specified
* tag control on success; otherwise, NULL.
*
*/
const char *DecodeTagControl(const TLVTagControl aTagControl)
{
const char *retval;

switch (aTagControl)
{

case kTLVTagControl_Anonymous:
retval = "Anonymous";
break;

case kTLVTagControl_ContextSpecific:
retval = "Context Specific";
break;

case kTLVTagControl_CommonProfile_2Bytes:
retval = "Common Profile (2 Bytes)";
break;

case kTLVTagControl_CommonProfile_4Bytes:
retval = "Common Profile (4 Bytes)";
break;

case kTLVTagControl_ImplicitProfile_2Bytes:
retval = "Implicit Profile (2 Bytes)";
break;

case kTLVTagControl_ImplicitProfile_4Bytes:
retval = "Implicit Profile (4 Bytes)";
break;

case kTLVTagControl_FullyQualified_6Bytes:
retval = "Fully Qualified (6 Bytes)";
break;

case kTLVTagControl_FullyQualified_8Bytes:
retval = "Fully Qualified (8 Bytes)";
break;

default:
retval = NULL;
break;

}

return retval;
}

/**
* Decode a TLV type with a descriptive string.
*
* @param[in] aType The TLV type to decode and for which to return
* a descriptive string.
*
* @return A pointer to a NULL-terminated string describing the specified
* type on success; otherwise, NULL.
*
*/
const char *DecodeType(const TLVType aType)
{
const char *retval;

switch (aType)
{

case kTLVType_NotSpecified:
retval = "Not Specified";
break;

case kTLVType_SignedInteger:
retval = "Signed Fixed Point";
break;

case kTLVType_UnsignedInteger:
retval = "Unsigned Fixed Point";
break;

case kTLVType_Boolean:
retval = "Boolean";
break;

case kTLVType_FloatingPointNumber:
retval = "Floating Point";
break;

case kTLVType_UTF8String:
retval = "UTF-8 String";
break;

case kTLVType_ByteString:
retval = "Data";
break;

case kTLVType_Null:
retval = "Null";
break;

case kTLVType_Structure:
retval = "Structure";
break;

case kTLVType_Array:
retval = "Array";
break;

case kTLVType_Path:
retval = "Path";
break;

default:
retval = NULL;
break;

}

return retval;
}

/**
* Log the TLV data within the specified reader in human-readable form to
* the specified writer.
*
* @param[in] aWriter The writer to log the TLV data.
* @param[in] aReader A read-only reference to the TLV reader containing
* the TLV data to log.
*
* @retval #CHIP_NO_ERROR Unconditionally.
*
*/
CHIP_ERROR DumpIterator(DumpWriter aWriter, const TLVReader &aReader)
{
const char * tabs = "";
const size_t depth = 0;
CHIP_ERROR retval = CHIP_NO_ERROR;

DumpHandler(aWriter, tabs, aReader, depth);

return retval;
}

/**
* Log the TLV data within the specified reader in human-readable form.
*
* @param[in] aReader A read-only reference to the TLV reader containing
* the TLV data to log.
* @param[in] aDepth The current depth into the TLV data.
* @param[inout] aContext A pointer to the handler-specific context.
*
* @retval #CHIP_NO_ERROR On success.
*
* @retval #CHIP_ERROR_INVALID_ARGUMENT If aContext is NULL or if
* aContext->mWriter is NULL.
*
*/
CHIP_ERROR DumpHandler(const TLVReader &aReader, size_t aDepth, void *aContext)
{
static const char indent[] = " ";
CHIP_ERROR retval = CHIP_NO_ERROR;
DumpContext * context;

VerifyOrExit(aContext != NULL, retval = CHIP_ERROR_INVALID_ARGUMENT);

context = static_cast<DumpContext *>(aContext);

VerifyOrExit(context->mWriter != NULL, retval = CHIP_ERROR_INVALID_ARGUMENT);

DumpHandler(context->mWriter,
indent,
aReader,
aDepth);

exit:
return retval;
}

/**
* Dump the TLV data within the specified reader in human-readable form with
* the specified writer.
*
* @param[in] aReader A read-only reference to the TLV reader containing
* the TLV data to log.
*
* @param[in] aWriter A dump writer to log the TLV data of the TLV reader.
*
* @retval #CHIP_NO_ERROR On success.
*
*/
CHIP_ERROR Dump(const TLVReader &aReader, DumpWriter aWriter)
{
void * context = NULL;
DumpContext dumpContext = { aWriter, context };
CHIP_ERROR retval;

retval = Utilities::Iterate(aReader, DumpHandler, &dumpContext);

return retval;
}

} // namespace Debug

} // namespace TLV

} // namespace chip
Loading

0 comments on commit f2cf5eb

Please sign in to comment.