/*
 *  Copyright (c) 2005-2026, Karsten Ohme
 *  This file is part of GlobalPlatform.
 *
 *  GlobalPlatform is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  GlobalPlatform 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 Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with GlobalPlatform.  If not, see <https://www.gnu.org/licenses/>.
 *
 * In addition, as a special exception, the copyright holders give
 * permission to link the code of portions of this program with the
 * OpenSSL library under certain conditions as described in each
 * individual source file, and distribute linked combinations
 * including the two.
 * You must obey the GNU Lesser General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * file(s) with this exception, you may extend this exception to your
 * version of the file(s), but you are not obligated to do so.  If you
 * do not wish to do so, delete this exception statement from your
 * version.
 */

/*! \file
 * This file contains all GlobalPlatform utility functionality.
*/

#ifndef OPGP_UTIL_H
#define OPGP_UTIL_H

#ifdef __cplusplus
extern "C"
{
#endif

#ifdef WIN32
#include "stdafx.h"
#endif

#include "globalplatform/types.h"
#include "globalplatform/library.h"
#include "globalplatform/error.h"

/**
 * A TLV object.
 **/
typedef struct {
	USHORT tag; //!< The Tag.
	DWORD length; //!< The length of the value.
	BYTE value[256]; //!< The value.
	PBYTE extendedValue; //!< The extended value if length > 256. Must be manually allocated and deallocated.
	DWORD tlvLength; //!< The length of the whole TLV.
} TLV;

/**
 * A lightweight TLV view.
 **/
typedef struct {
	USHORT tag; //!< The Tag.
	const BYTE *value; //!< Pointer into the source buffer.
	DWORD length; //!< The length of the value.
	DWORD tlvLength; //!< The length of the whole TLV.
} GP_SIMPLE_TLV;

//! \brief Reads a TLV struct from the given buffer
OPGP_NO_API
LONG read_TLV(const BYTE *buffer, DWORD length, TLV *tlv);

//! \brief Reads a TLV view from the given buffer without copying the value.
OPGP_NO_API
LONG parse_simple_tlv(const BYTE *buffer, DWORD length, GP_SIMPLE_TLV *tlv);

//! \brief Appends a TLV to the given buffer.
OPGP_NO_API
OPGP_ERROR_STATUS append_tlv(PBYTE buffer, DWORD bufferSize, PDWORD offset, USHORT tag, const BYTE *value, DWORD valueLength);

//! \brief Converts a ISO 7816-4 Le Byte into its value.
OPGP_NO_API
DWORD convert_byte(BYTE b);

//! \brief Returns an unsigned short int from the given position
OPGP_NO_API
DWORD get_short(PBYTE buf, DWORD offset);

//! \brief Returns an unsigned int from the given position
OPGP_NO_API
DWORD get_int(PBYTE buf, DWORD offset);

//! \brief Returns an unsigned int from the given position by taking just numLength bytes starting at offset into account.
DWORD get_number(PBYTE buf, DWORD offset, BYTE numLength);

//! \brief Parse the APDU case.
OPGP_NO_API
LONG parse_apdu_case(PBYTE apduCommand, DWORD apduCommandLength, PBYTE caseAPDU, PDWORD lc, PDWORD le);

//! \brief Writes a TLV length field following DER BER rules.
OPGP_NO_API
LONG write_TLV_length(PBYTE buffer, DWORD offset, DWORD lengthLeft, USHORT length);

//! \brief Parses a DER encoded OID into a numeric string (e.g. "1.2.840.113549").
OPGP_NO_API
LONG parse_OID_numeric_string(PBYTE oid, DWORD oidLength, char *out, DWORD outLength);

#ifdef __cplusplus
}
#endif

#endif
