* This file is part of the openHiTLS project.
*
* openHiTLS is licensed under the Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
#include "hitls_build.h"
#ifdef HITLS_BSL_PRINT
#include <stdarg.h>
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "bsl_err_internal.h"
#include "bsl_sal.h"
#include "bsl_print.h"
#define BSL_PRINT_LEN 1024
#define BSL_PRINT_MAX_LAYER 10
#define BSL_PRINT_EACH_LAYER_INDENT 4
#define BSL_PRINT_MAX_INDENT ((BSL_PRINT_EACH_LAYER_INDENT) * (BSL_PRINT_MAX_LAYER))
#define BSL_PRINT_WIDTH 16
#define BSL_PRINT_MAX_WIDTH 20
#define BSL_ASN1_HEX_TO_COLON_HEX 3
#define BSL_PRINT_HEX_LEN (BSL_PRINT_MAX_WIDTH * BSL_ASN1_HEX_TO_COLON_HEX + 1)
#define BSL_PRINT_NEW_LINE "\n"
static int32_t WriteBuff(BSL_UIO *uio, const void *buff, uint32_t buffLen)
{
uint32_t writeLen = 0;
int32_t ret = BSL_UIO_Write(uio, buff, buffLen, &writeLen);
return ret != BSL_SUCCESS ? ret : (writeLen != buffLen ? BSL_PRINT_ERR_BUF : BSL_SUCCESS);
}
static int32_t PrintBuff(uint32_t layer, BSL_UIO *uio, const void *buff, uint32_t buffLen)
{
int32_t ret;
char *indent[BSL_PRINT_MAX_INDENT + 1] = {0};
memset(indent, ' ', BSL_PRINT_MAX_INDENT);
if (layer > 0) {
ret = WriteBuff(uio, indent, layer * BSL_PRINT_EACH_LAYER_INDENT);
if (ret != BSL_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
}
if (buffLen == 0) {
return BSL_SUCCESS;
}
ret = WriteBuff(uio, buff, buffLen);
if (ret != BSL_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
}
return ret;
}
int32_t BSL_PRINT_Buff(uint32_t layer, BSL_UIO *uio, const void *buff, uint32_t buffLen)
{
if (layer > BSL_PRINT_MAX_LAYER || uio == NULL || (buffLen != 0 && buff == NULL)) {
BSL_ERR_PUSH_ERROR(BSL_INVALID_ARG);
return BSL_INVALID_ARG;
}
return PrintBuff(layer, uio, buff, buffLen);
}
static int32_t PrintHexOnOneLine(uint32_t layer, const uint8_t *data, uint32_t dataLen, BSL_UIO *uio)
{
char hexStr[BSL_PRINT_HEX_LEN] = {0};
uint32_t strIdx = 0;
bool isEnd;
bool needIndent = true;
int32_t ret;
for (uint32_t i = 0; i < dataLen; i++) {
isEnd = (i + 1) == dataLen;
size_t avail = BSL_PRINT_HEX_LEN - strIdx * BSL_ASN1_HEX_TO_COLON_HEX;
int n = snprintf(hexStr + strIdx * BSL_ASN1_HEX_TO_COLON_HEX, avail, isEnd ? "%02x\n" : "%02x:", data[i]);
if (n < 0 || (size_t)n >= avail) {
BSL_ERR_PUSH_ERROR(BSL_PRINT_ERR_BUF);
return BSL_PRINT_ERR_BUF;
}
strIdx++;
if (isEnd || strIdx == BSL_PRINT_MAX_WIDTH) {
ret = PrintBuff(needIndent ? layer : 0, uio, hexStr, strIdx * BSL_ASN1_HEX_TO_COLON_HEX);
if (ret != BSL_SUCCESS) {
BSL_ERR_PUSH_ERROR(ret);
return ret;
}
needIndent = false;
strIdx = 0;
}
}
return BSL_SUCCESS;
}
int32_t BSL_PRINT_Hex(uint32_t layer, bool oneLine, const uint8_t *data, uint32_t dataLen, BSL_UIO *uio)
{
if (layer > BSL_PRINT_MAX_LAYER || data == NULL || dataLen == 0 || uio == NULL) {
BSL_ERR_PUSH_ERROR(BSL_INVALID_ARG);
return BSL_INVALID_ARG;
}
if (oneLine) {
return PrintHexOnOneLine(layer, data, dataLen, uio);
}
char hexStr[BSL_PRINT_HEX_LEN] = {0};
uint32_t lineLen = dataLen <= BSL_PRINT_MAX_WIDTH ? BSL_PRINT_MAX_WIDTH : BSL_PRINT_WIDTH;
uint32_t strIdx = 0;
bool isLineEnd;
for (uint32_t i = 0; i < dataLen; i++) {
isLineEnd = (i + 1) % lineLen == 0 || (i + 1) == dataLen;
size_t avail = BSL_PRINT_HEX_LEN - strIdx * BSL_ASN1_HEX_TO_COLON_HEX;
int n = snprintf(hexStr + strIdx * BSL_ASN1_HEX_TO_COLON_HEX, avail, isLineEnd ? "%02x\n" : "%02x:", data[i]);
if (n < 0 || (size_t)n >= avail) {
BSL_ERR_PUSH_ERROR(BSL_PRINT_ERR_BUF);
return BSL_PRINT_ERR_BUF;
}
strIdx++;
if (!isLineEnd) {
continue;
}
if (PrintBuff(layer, uio, hexStr, strIdx * BSL_ASN1_HEX_TO_COLON_HEX) != 0) {
BSL_ERR_PUSH_ERROR(BSL_PRINT_ERR_BUF);
return BSL_PRINT_ERR_BUF;
}
strIdx = 0;
}
return BSL_SUCCESS;
}
int32_t BSL_PRINT_Fmt(uint32_t layer, BSL_UIO *uio, const char *fmt, ...)
{
if (layer > BSL_PRINT_MAX_LAYER || uio == NULL || fmt == NULL) {
BSL_ERR_PUSH_ERROR(BSL_INVALID_ARG);
return BSL_INVALID_ARG;
}
va_list args;
va_start(args, fmt);
char buff[BSL_PRINT_LEN + 1] = {0};
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
int n = vsnprintf(buff, BSL_PRINT_LEN + 1, fmt, args);
#if defined(__clang__) || defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
if (n < 0 || (size_t)n >= BSL_PRINT_LEN + 1) {
va_end(args);
BSL_ERR_PUSH_ERROR(BSL_PRINT_ERR_FMT);
return BSL_PRINT_ERR_FMT;
}
int32_t ret = BSL_PRINT_Buff(layer, uio, buff, (uint32_t)strlen(buff));
va_end(args);
return ret != 0 ? BSL_PRINT_ERR_FMT : BSL_SUCCESS;
}
const char BSL_PRINT_MONTH_STR[12][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int32_t BSL_PRINT_Time(uint32_t layer, const BSL_TIME *time, BSL_UIO *uio)
{
if (time == NULL || time->month < 1 || time->month > 12) {
BSL_ERR_PUSH_ERROR(BSL_INVALID_ARG);
return BSL_INVALID_ARG;
}
return BSL_PRINT_Fmt(layer, uio, BSL_PRINT_TIME_FMT"\n", BSL_PRINT_MONTH_STR[time->month - 1],
time->day, time->hour, time->minute, time->second, time->year);
}
* Only positive numbers can be printed.
*/
int32_t BSL_PRINT_Number(uint32_t layer, const char *title, const uint8_t *data, uint32_t dataLen, BSL_UIO *uio)
{
if (data == NULL || dataLen == 0 || uio == NULL) {
BSL_ERR_PUSH_ERROR(BSL_INVALID_ARG);
return BSL_INVALID_ARG;
}
uint32_t temp = layer;
if (dataLen > (sizeof(uint64_t))) {
if (title != NULL) {
if (BSL_PRINT_Fmt(temp++, uio, "%s:\n", title) != 0) {
BSL_ERR_PUSH_ERROR(BSL_PRINT_ERR_NUMBER);
return BSL_PRINT_ERR_NUMBER;
}
}
return BSL_PRINT_Hex(temp, false, data, dataLen, uio);
}
uint64_t num = 0;
for (uint32_t i = 0; i < dataLen; i++) {
num |= (uint64_t)data[i] << (8 * (dataLen - i - 1));
}
if (title != NULL) {
return BSL_PRINT_Fmt(layer, uio, "%s: %"PRIu64" (0x%"PRIX64")\n", title, num, num);
}
return BSL_PRINT_Fmt(layer, uio, "%"PRIu64" (0x%"PRIX64")\n", num, num);
}
#endif