Files
ANSCORE/anslicensing/bitstruct.h

379 lines
8.1 KiB
C
Raw Normal View History

2026-03-28 16:54:11 +11:00
#pragma once
#include <memory>
#include <map>
#include "bitstream.h"
#include "uniconv.h"
#include "except.h"
#ifndef _WIN32
#include <alloca.h>
#else
#include <malloc.h>
#endif
using namespace std;
class BitStruct {
public:
enum FIELD_TYPE
{
RAW,
INTEGER,
STRING,
DATE14,
DATE13,
DATE16,
};
private:
class Field {
public:
Field():
m_fieldType(FIELD_TYPE::INTEGER),
m_offset(0),
m_size(0)
{
}
Field(FIELD_TYPE fieldType, int offset, int size)
{
m_fieldType = fieldType;
m_offset = offset;
m_size = size;
}
public:
FIELD_TYPE m_fieldType;
int m_offset;
int m_size;
};
typedef std::map<string, Field> FieldMap;
public:
BitStruct(int bitSize = 0) :
m_bits(bitSize)
{
}
BitStruct(vector<unsigned char>& buf, int bitSize):
m_bits(buf, bitSize)
{
}
void Create(int bitSize = 0)
{
m_bits.Create(bitSize);
}
void Attach(vector<unsigned char>& buf, int bitSize)
{
m_bits.Attach(buf, bitSize);
}
void AddField(const char * fieldName, FIELD_TYPE fieldType, int fieldBitSize, int offset = -1 )
{
if (offset == -1)
offset = currentFieldOffset;
m_fieldMap.insert(FieldMap::value_type(fieldName, Field(fieldType, offset, fieldBitSize)));
currentFieldOffset = offset + fieldBitSize;
}
bool GetField(const char * fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * fieldOffset) const
{
FieldMap::const_iterator iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end())
return false;
*fieldType = iter->second.m_fieldType;
*fieldSize = iter->second.m_size;
*fieldOffset = iter->second.m_offset;
return true;
}
bool EnumFields(void **enumHandle, const char **fieldName, FIELD_TYPE * fieldType, int * fieldSize, int * offset)
{
FieldMap::iterator * pIter;
static string name;
if (*enumHandle == NULL)
{
pIter = new FieldMap::iterator(m_fieldMap.begin());
if (!pIter)
return false;
}
else
pIter = (FieldMap::iterator *)(*enumHandle);
if (*pIter == m_fieldMap.end())
{
delete pIter;
return false;
}
name = (*pIter)->first;
*fieldName = name.c_str();
*fieldType = (*pIter)->second.m_fieldType;
*fieldSize = (*pIter)->second.m_size;
*offset = (*pIter)->second.m_offset;
pIter->operator ++(); // *Iter++ does not work. Think why :)
*enumHandle = pIter;
return true;
}
void Set(const char * fieldName, const void * buf, unsigned len)
{
int offset = 0, size = m_bits.GetSize();
if (fieldName)
{
FieldMap::iterator iter;
iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end())
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
offset = iter->second.m_offset;
size = iter->second.m_size;
}
m_bits.Seek(offset);
int bitlen = len << 3;
if (bitlen >= size)
m_bits.Write(buf, size);
else
{
int bits = size - bitlen;
unsigned char * zeroes = (unsigned char *)_alloca((bits + 7) >> 3);
memset(zeroes, 0, (bits + 7) >> 3);
m_bits.Write(buf, bitlen);
m_bits.Write(zeroes, bits);
}
}
void Set(const char * fieldName, const char * data)
{
Set(fieldName, data, (unsigned)strlen(data));
}
void Set(const char * fieldName, int data)
{
#ifndef LICENSING_BIG_ENDIAN
Set(fieldName, &data, sizeof(data));
#else
unsigned char buf[sizeof(int)] = { 0, 0, 0, 0 };
buf[0] = (unsigned char)(data & 0xFF);
buf[1] = (unsigned char)((data >> 8) & 0xFF);
buf[2] = (unsigned char)((data >> 16) & 0xFF);
buf[3] = (unsigned char)((data >> 24) & 0xFF);
Set(fieldName, buf, sizeof(data));
#endif
}
void Set(const char * fieldName, int year, int month, int day)
{
FieldMap::iterator iter;
iter = m_fieldMap.find(fieldName);
if (iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
int date;
switch (iter->second.m_fieldType)
{
case FIELD_TYPE_DATE13:
date = PackDate13(year, month, day);
break;
case FIELD_TYPE_DATE14:
date = PackDate14(year, month, day);
break;
case FIELD_TYPE_DATE16:
date = PackDate16(year, month, day);
break;
default:
throw new LicensingException(STATUS_INVALID_PARAM, "A data value is being set to a non-date field");
}
Set(fieldName, date);
}
void Get(const char * dataField, void * buf, int * len)
{
if (dataField)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
if ( *len < ( iter->second.m_size + 7 ) >> 3 )
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
m_bits.Seek(iter->second.m_offset);
m_bits.Read(buf, iter->second.m_size);
*len = (iter->second.m_size + 7) >> 3;
} else
{
int validationDataLen = (m_bits.GetSize() + 7) >> 3;
if (*len < validationDataLen)
{
*len = validationDataLen;
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
}
memcpy(buf, m_bits.GetBuffer(), validationDataLen);
*len = validationDataLen;
}
}
int GetInt(const char * dataField)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
unsigned char buf[sizeof(int)] = {0, 0, 0, 0};
if ( sizeof(buf) < ( iter->second.m_size + 7 ) >> 3 )
throw new LicensingException(STATUS_BUFFER_TOO_SMALL);
m_bits.Seek(iter->second.m_offset);
m_bits.Read(buf, iter->second.m_size);
#ifndef LICENSING_BIG_ENDIAN
return *(int *)buf;
#else
return ((int)buf[3] << 24) | ((int)buf[2] << 16) | ((int)buf[1] << 8) | (int)buf[0];
#endif
}
void GetDate(const char * dataField, int * year, int * month, int * day)
{
FieldMap::const_iterator iter;
iter = m_fieldMap.find(dataField);
if ( iter == m_fieldMap.end() )
throw new LicensingException(STATUS_FIELD_NOT_FOUND);
unsigned short packedDate = (unsigned short)GetInt(dataField);
switch (iter->second.m_fieldType)
{
case FIELD_TYPE_DATE13:
UnpackDate13(packedDate, year, month, day);
break;
case FIELD_TYPE_DATE14:
UnpackDate14(packedDate, year, month, day);
break;
case FIELD_TYPE_DATE16:
UnpackDate16(packedDate, year, month, day);
break;
default:
throw new LicensingException(STATUS_INVALID_PARAM, "An attempt was made to query a date from a non-date field");
}
}
void * GetBuffer(int * sizeInBits = NULL)
{
return m_bits.GetBuffer(sizeInBits);
}
BitStream& GetBitStream()
{
return m_bits;
}
int GetCurrentFieldOffset()
{
return currentFieldOffset;
}
void ResetFieldOffset()
{
currentFieldOffset = 0;
}
int GetSize()
{
return m_bits.GetSize();
}
private:
unsigned short PackDate13(int year, int month, int day)
{
if (year < 2012 || year > 2027)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 13-bit date. Allowed values are 2012-2027");
return (unsigned short)(((month - 1) << 9) | ((day - 1) << 4) | (year - 2012));
}
void UnpackDate13(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2012 + (packedDate & 0x0F);
*month = 1 + (packedDate >> 9);
*day = 1 + ((packedDate >> 4) & 0x1F);
}
unsigned short PackDate14(int year, int month, int day)
{
if (year < 2010 || year > 2041)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 14-bit date. Allowed values are 2010-2041");
return (unsigned short)(((month - 1) << 10) | ((day - 1) << 5) | (year - 2010));
}
void UnpackDate14(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2010 + (packedDate & 0x1F);
*month = 1 + (packedDate >> 10);
*day = 1 + ((packedDate >> 5) & 0x1F);
}
unsigned short PackDate16(int year, int month, int day)
{
if (year < 2000 || year > 2127)
throw new LicensingException(STATUS_INVALID_PARAM, "Invalid year for a 16-bit date. Allowed values are 2010-2127");
return (unsigned short)(((year - 2000) << 9) | (month << 5) | day);
}
void UnpackDate16(unsigned short packedDate, int * year, int * month, int * day)
{
*year = 2000 + (packedDate >> 9);
*month = (packedDate & 0x01FF) >> 5;
*day = packedDate & 0x001F;
}
FieldMap m_fieldMap;
BitStream m_bits;
int currentFieldOffset;
};