379 lines
8.1 KiB
C++
379 lines
8.1 KiB
C++
#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;
|
|
};
|