blob: 0bcf6443050dba03f41c7bbf897be5fbad9baafa [file] [log] [blame]
/*
*
* Copyright (c) 2015-2017 Nest Labs, Inc.
* All rights reserved.
*
* 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
* Weave TLV.
*
*/
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <ctype.h>
#include <inttypes.h>
#include <string.h>
#include <Weave/Core/WeaveTLV.h>
#include <Weave/Core/WeaveTLVDebug.hpp>
#include <Weave/Core/WeaveTLVUtilities.hpp>
#include <Weave/Support/CodeUtils.h>
#include <Weave/Support/logging/WeaveLogging.h>
namespace nl {
namespace Weave {
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] aTabs 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 *aTabs, 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;
WEAVE_ERROR err = WEAVE_NO_ERROR;
TLVReader temp;
TLVTagControl tagControl;
temp.Init(aReader);
tagControl = static_cast<TLVTagControl>(temp.GetControlByte() & kTLVTagControlMask);
aWriter("%zd %s", aDepth, aTabs);
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 == WEAVE_NO_ERROR, aWriter("Error in kTLVType_SignedInteger"));
aWriter("%" PRIi64, sVal);
break;
case kTLVType_UnsignedInteger:
uint64_t uVal;
err = temp.Get(uVal);
VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_UnsignedInteger"));
aWriter("%" PRIu64, uVal);
break;
case kTLVType_Boolean:
bool bVal;
err = temp.Get(bVal);
VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_Boolean"));
aWriter("%s", bVal ? "true" : "false");
break;
case kTLVType_FloatingPointNumber:
double fpVal;
err = temp.Get(fpVal);
VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_FloatingPointNumber"));
aWriter("%lf", fpVal);
break;
case kTLVType_UTF8String:
err = temp.GetDataPtr(strbuf);
VerifyOrExit(err == WEAVE_NO_ERROR, aWriter("Error in kTLVType_UTF8String"));
aWriter("\"%-.*s\"", static_cast<int>(len), strbuf);
break;
case kTLVType_ByteString:
err = temp.GetDataPtr(strbuf);
VerifyOrExit(err == WEAVE_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 #WEAVE_NO_ERROR Unconditionally.
*
*/
WEAVE_ERROR DumpIterator(DumpWriter aWriter, const TLVReader &aReader)
{
const char * tabs = "";
const size_t depth = 0;
WEAVE_ERROR retval = WEAVE_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 #WEAVE_NO_ERROR On success.
*
* @retval #WEAVE_ERROR_INVALID_ARGUMENT If aContext is NULL or if
* aContext->mWriter is NULL.
*
*/
WEAVE_ERROR DumpHandler(const TLVReader &aReader, size_t aDepth, void *aContext)
{
static const char tabs[] = " ";
char tabbuf[48];
WEAVE_ERROR retval = WEAVE_NO_ERROR;
DumpContext * context;
VerifyOrExit(aContext != NULL, retval = WEAVE_ERROR_INVALID_ARGUMENT);
context = static_cast<DumpContext *>(aContext);
VerifyOrExit(context->mWriter != NULL, retval = WEAVE_ERROR_INVALID_ARGUMENT);
strncpy(tabbuf, tabs, aDepth);
tabbuf[aDepth] = 0;
DumpHandler(context->mWriter,
tabbuf,
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 #WEAVE_NO_ERROR On success.
*
*/
WEAVE_ERROR Dump(const TLVReader &aReader, DumpWriter aWriter)
{
void * context = NULL;
DumpContext dumpContext = { aWriter, context };
WEAVE_ERROR retval;
retval = Utilities::Iterate(aReader, DumpHandler, &dumpContext);
return retval;
}
} // namespace Debug
} // namespace TLV
} // namespace Weave
} // namespace nl