/************************************************************************
MeOS - Orienteering Software
Copyright (C) 2009-2019 Melin Software HB
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
Melin Software HB - software@melin.nu - www.melin.nu
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
************************************************************************/
#include "stdafx.h"
#include
#include "oDataContainer.h"
#include "oEvent.h"
#include "gdioutput.h"
#include "xmlparser.h"
#include "Table.h"
#include "meos_util.h"
#include "Localizer.h"
#include "meosException.h"
oDataContainer::oDataContainer(int maxsize) {
dataPointer = 0;
dataMaxSize = maxsize;
stringIndexPointer = 0;
stringArrayIndexPointer = 2;
}
oDataContainer::~oDataContainer(void) {
}
oDataInfo::oDataInfo() {
memset(Name, 0, sizeof(Name));
Index = 0;
Size = 0;
Type = 0;
SubType = 0;
tableIndex = 0;
decimalSize = 0;
decimalScale = 1;
dataDefiner = 0;
zeroSortPadding = 0;
memset(Description, 0, sizeof(Description));
}
oDataInfo::~oDataInfo() {
}
oDataInfo &oDataContainer::addVariableInt(const char *name,
oIntSize isize, const char *description,
const oDataDefiner *dataDef) {
oDataInfo odi;
odi.dataDefiner = dataDef;
odi.Index=dataPointer;
strcpy_s(odi.Name, name);
strcpy_s(odi.Description, description);
if (isize == oIS64)
odi.Size=sizeof(__int64);
else
odi.Size=sizeof(int);
odi.Type=oDTInt;
odi.SubType=isize;
if (dataPointer+odi.Size<=dataMaxSize){
dataPointer+=odi.Size;
return addVariable(odi);
}
else
throw std::exception("oDataContainer: Out of bounds.");
}
oDataInfo &oDataContainer::addVariableDecimal(const char *name, const char *descr, int fixedDeci) {
oDataInfo &odi = addVariableInt(name, oISDecimal, descr);
odi.decimalSize = fixedDeci;
int &s = odi.decimalScale;
s = 1;
for (int k = 0; k < fixedDeci; k++)
s*=10;
return odi;
}
oDataInfo &oDataContainer::addVariableString(const char *name, const char *descr, const oDataDefiner *dataDef) {
return addVariableString(name, -1, descr, dataDef);
}
oDataInfo &oDataContainer::addVariableString(const char *name, int maxChar,
const char *descr, const oDataDefiner *dataDef)
{
oDataInfo odi;
odi.dataDefiner = dataDef;
strcpy_s(odi.Name,name);
strcpy_s(odi.Description,descr);
if (maxChar > 0) {
odi.Index = dataPointer;
odi.Size = sizeof(wchar_t)*(maxChar+1);
odi.Type = oDTString;
odi.SubType = oSSString;
if (dataPointer+odi.Size<=dataMaxSize){
dataPointer+=odi.Size;
return addVariable(odi);
}
else
throw std::exception("oDataContainer: Out of bounds.");
}
else {
odi.Index = stringIndexPointer++;
odi.Size = 0;
odi.Type = oDTStringDynamic;
odi.SubType = oSSString;
return addVariable(odi);
}
}
oDataInfo &oDataContainer::addVariableEnum(const char *name, int maxChar, const char *descr,
const vector< pair > enumValues) {
oDataInfo &odi = addVariableString(name, maxChar, descr);
odi.SubType = oSSEnum;
for (size_t k = 0; k::iterator it=index.find(Name);
if (it == index.end())
return 0;
else return &(it->second);
return 0;*/
int res;
if (index.lookup(hash(name), res)) {
return &ordered[res];
}
return 0;
}
const oDataInfo *oDataContainer::findVariable(const char *name) const
{
if (name == 0)
return 0;
/*map::const_iterator it=index.find(Name);
if (it == index.end())
return 0;
else return &(it->second);
*/
int res;
if (index.lookup(hash(name), res)) {
return &ordered[res];
}
return 0;
}
void oDataContainer::initData(oBase *ob, int datasize) {
if (datasize > *strptr;
ob->getDataBuffers(data, oldData, strptr);
memset(data, 0, dataPointer);
memset(oldData, 0, dataPointer);
if (stringIndexPointer > 0 || stringArrayIndexPointer>2) {
vector< vector > &str = *strptr;
str.clear();
str.resize(stringArrayIndexPointer);
str[0].resize(stringIndexPointer);
str[1].resize(stringIndexPointer);
}
}
bool oDataContainer::setInt(void *data, const char *Name, int V)
{
oDataInfo *odi=findVariable(Name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type!=oDTInt)
throw std::exception("oDataContainer: Variable of wrong type.");
if (odi->SubType == oIS64)
throw std::exception("oDataContainer: Variable to large.");
LPBYTE vd=LPBYTE(data)+odi->Index;
if (*((int *)vd)!=V){
*((int *)vd)=V;
return true;
}
else return false;//Not modified
}
bool oDataContainer::setInt64(void *data, const char *Name, __int64 V)
{
oDataInfo *odi=findVariable(Name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type!=oDTInt)
throw std::exception("oDataContainer: Variable of wrong type.");
if (odi->SubType != oIS64)
throw std::exception("oDataContainer: Variable to large.");
LPBYTE vd=LPBYTE(data)+odi->Index;
if (*((__int64 *)vd)!=V){
*((__int64 *)vd)=V;
return true;
}
else return false;//Not modified
}
int oDataContainer::getInt(const void *data, const char *Name) const
{
const oDataInfo *odi=findVariable(Name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type!=oDTInt)
throw std::exception("oDataContainer: Variable of wrong type.");
if (odi->SubType == oIS64)
throw std::exception("oDataContainer: Variable to large.");
LPBYTE vd=LPBYTE(data)+odi->Index;
return *((int *)vd);
}
__int64 oDataContainer::getInt64(const void *data, const char *Name) const
{
const oDataInfo *odi=findVariable(Name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type!=oDTInt)
throw std::exception("oDataContainer: Variable of wrong type.");
LPBYTE vd=LPBYTE(data)+odi->Index;
if (odi->SubType == oIS64)
return *((__int64 *)vd);
else {
int tmp = *((int *)vd);
return tmp;
}
}
bool oDataContainer::setString(oBase *ob, const char *name, const wstring &v) {
oDataInfo *odi=findVariable(name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
if (odi->Type == oDTString) {
LPBYTE vd=LPBYTE(data)+odi->Index;
if (wcscmp((wchar_t *)vd, v.c_str())!=0){
wcsncpy_s((wchar_t *)vd, odi->Size/sizeof(wchar_t), v.c_str(), (odi->Size-1)/sizeof(wchar_t));
return true;
}
else return false;//Not modified
}
else if (odi->Type == oDTStringDynamic) {
wstring &str = (*strptr)[0][odi->Index];
if (str == v)
return false; // Same string
str = v;
return true;
}
else
throw std::exception("oDataContainer: Variable of wrong type.");
}
const wstring &oDataContainer::formatString(const oBase *ob, const char *Name) const {
const oDataInfo *odi = findVariable(Name);
if (odi->dataDefiner) {
return odi->dataDefiner->formatData(ob);
}
else if (odi->Type == oDTString) {
return getString(ob, Name);
}
else if (odi->Type == oDTInt) {
return itow(getInt(ob, Name));
}
throw std::exception("oDataContainer: Formatting failed.");
}
const wstring &oDataContainer::getString(const oBase *ob, const char *Name) const {
const oDataInfo *odi=findVariable(Name);
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type == oDTString) {
LPBYTE vd=LPBYTE(data)+odi->Index;
wstring &res = StringCache::getInstance().wget();
res = (wchar_t *) vd;
return res;
}
else if (odi->Type == oDTStringDynamic) {
wstring &str = (*strptr)[0][odi->Index];
return str;
}
else
throw std::exception("oDataContainer: Variable of wrong type.");
}
bool oDataContainer::setDate(void *data, const char *Name, const wstring &V)
{
oDataInfo *odi=findVariable(Name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type!=oDTInt)
throw std::exception("oDataContainer: Variable of wrong type.");
int year=0,month=0,day=0;
swscanf_s(V.c_str(), L"%d-%d-%d", &year, &month, &day);
int C=year*10000+month*100+day;
LPBYTE vd=LPBYTE(data)+odi->Index;
if (*((int *)vd)!=C){
*((int *)vd)=C;
return true;
}
else return false;//Not modified
}
const wstring &oDataContainer::getDate(const void *data,
const char *Name) const
{
const oDataInfo *odi=findVariable(Name);
if (!odi)
throw std::exception("oDataContainer: Variable not found.");
if (odi->Type!=oDTInt)
throw std::exception("oDataContainer: Variable of wrong type.");
LPBYTE vd=LPBYTE(data)+odi->Index;
int C=*((int *)vd);
wchar_t bf[24];
if (C%10000!=0 || C==0)
swprintf_s(bf, L"%04d-%02d-%02d", C/10000, (C/100)%100, C%100);
else
swprintf_s(bf, L"%04d", C/10000);
wstring &res = StringCache::getInstance().wget();
res = bf;
return res;
}
bool oDataContainer::write(const oBase *ob, xmlparser &xml) const {
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
xml.startTag("oData");
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.Type==oDTInt){
LPBYTE vd=LPBYTE(data)+di.Index;
if (di.SubType != oIS64) {
int nr;
memcpy(&nr, vd, sizeof(int));
xml.write(di.Name, nr);
}
else {
__int64 nr;
memcpy(&nr, vd, sizeof(__int64));
xml.write64(di.Name, nr);
}
}
else if (di.Type == oDTString){
LPBYTE vd=LPBYTE(data)+di.Index;
wstring out = (wchar_t*)vd;
xml.write(di.Name, out);
}
else if (di.Type == oDTStringDynamic) {
const wstring &str = (*strptr)[0][di.Index];
xml.write(di.Name, str);
}
}
xml.endTag();
return true;
}
void oDataContainer::set(oBase *ob, const xmlobject &xo) {
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
xmlList xl;
xo.getObjects(xl);
xmlList::const_iterator it;
for(it=xl.begin(); it != xl.end(); ++it){
oDataInfo *odi=findVariable(it->getName());
if (odi) {
if (odi->Type == oDTInt){
LPBYTE vd=LPBYTE(data)+odi->Index;
if (odi->SubType != oIS64)
*((int *)vd) = it->getInt();
else
*((__int64 *)vd) = it->getInt64();
}
else if (odi->Type == oDTString) {
LPBYTE vd=LPBYTE(data)+odi->Index;
wcsncpy_s((wchar_t *)vd, odi->Size/sizeof(wchar_t), it->getw(), (odi->Size-1)/sizeof(wchar_t));
}
else if (odi->Type == oDTStringDynamic) {
wstring &str = (*strptr)[0][odi->Index];
str = it->getw();
}
}
}
allDataStored(ob);
}
void oDataContainer::buildDataFields(gdioutput &gdi, int maxFieldSize) const
{
vector fields;
for (size_t k = 0; k < ordered.size(); k++)
fields.push_back(ordered[k].Name);
buildDataFields(gdi, fields, maxFieldSize);
}
void oDataContainer::buildDataFields(gdioutput &gdi, const vector &fields, int maxFieldSize) const
{
for (size_t k=0;k::const_iterator it=index.find(fields[k]);
const oDataInfo *odi = findVariable(fields[k].c_str());
//if (it==index.end())
if (odi == 0)
throw std::exception( ("Bad key: " + fields[k]).c_str());
const oDataInfo &di=*odi;
string Id=di.Name+string("_odc");
if (di.Type==oDTInt){
if (di.SubType == oISDate || di.SubType == oISTime)
gdi.addInput(Id, L"", 10, 0, gdi.widen(di.Description) + L":");
else
gdi.addInput(Id, L"", 6, 0, gdi.widen(di.Description) + L":");
}
else if (di.Type==oDTString){
gdi.addInput(Id, L"", min(di.Size+2, maxFieldSize), 0, gdi.widen(di.Description) + L":");
}
else if (di.Type==oDTStringDynamic){
gdi.addInput(Id, L"", maxFieldSize, 0, gdi.widen(di.Description) + L":");
}
}
}
int oDataContainer::getDataAmountMeasure(const void *data) const
{
int amount = 0;
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.Type==oDTInt) {
LPBYTE vd=LPBYTE(data)+di.Index;
int nr;
memcpy(&nr, vd, sizeof(int));
if (nr != 0)
amount++;
}
else if (di.Type==oDTString) {
LPBYTE vd=LPBYTE(data)+di.Index;
amount += strlen((char *)vd);
}
}
return amount;
}
void oDataContainer::fillDataFields(const oBase *ob, gdioutput &gdi) const
{
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
string Id=di.Name+string("_odc");
if (di.Type==oDTInt){
LPBYTE vd=LPBYTE(data)+di.Index;
if (di.SubType != oIS64) {
int nr;
memcpy(&nr, vd, sizeof(int));
if (di.SubType == oISCurrency) {
if (strcmp(di.Name, "CardFee") == 0 && nr == -1)
nr = 0; //XXX CardFee hack. CardFee = 0 is coded as -1
gdi.setText(Id.c_str(), ob->getEvent()->formatCurrency(nr));
}
else {
wchar_t bf[64];
formatNumber(nr, di, bf);
gdi.setText(Id.c_str(), bf);
}
}
else {
__int64 nr;
memcpy(&nr, vd, sizeof(__int64));
wchar_t bf[16];
oBase::converExtIdentifierString(nr, bf);
gdi.setText(Id.c_str(), bf);
}
}
else if (di.Type==oDTString){
LPBYTE vd=LPBYTE(data)+di.Index;
gdi.setText(Id.c_str(), (wchar_t *)vd);
}
else if (di.Type==oDTStringDynamic){
const wstring &str = (*strptr)[0][di.Index];
gdi.setText(Id.c_str(), str);
}
}
}
bool oDataContainer::saveDataFields(oBase *ob, gdioutput &gdi) {
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
string Id=di.Name+string("_odc");
if (!gdi.hasField(Id)) {
continue;
}
if (di.Type==oDTInt){
int no = 0;
if (di.SubType == oISCurrency) {
no = ob->getEvent()->interpretCurrency(gdi.getText(Id.c_str()));
}
else if (di.SubType == oISDate) {
no = convertDateYMS(gdi.getText(Id.c_str()), true);
}
else if (di.SubType == oISTime) {
no = convertAbsoluteTimeHMS(gdi.getText(Id.c_str()), -1);
}
else if (di.SubType == oISDecimal) {
wstring str = gdi.getText(Id.c_str());
for (size_t k = 0; k < str.length(); k++) {
if (str[k] == ',') {
str[k] = '.';
break;
}
}
double val = _wtof(str.c_str());
no = int(di.decimalScale * val);
}
else {
no = gdi.getTextNo(Id.c_str());
}
LPBYTE vd=LPBYTE(data)+di.Index;
int oldNo = *((int *)vd);
if (oldNo != no) {
*((int *)vd)=no;
ob->updateChanged();
}
}
else if (di.Type == oDTString) {
LPBYTE vd=LPBYTE(data)+di.Index;
wstring oldS = (wchar_t *)vd;
wstring newS = gdi.getText(Id.c_str());
if (oldS != newS) {
wcsncpy_s((wchar_t *)vd, di.Size/sizeof(wchar_t), newS.c_str(), (di.Size-1)/sizeof(wchar_t));
ob->updateChanged();
}
}
else if (di.Type == oDTStringDynamic) {
wstring &oldS = (*strptr)[0][di.Index];
wstring newS = gdi.getText(Id.c_str());
if (oldS != newS) {
oldS = newS;
ob->updateChanged();
}
}
}
return true;
}
string oDataContainer::C_INT64(const string &name)
{
return " `"+name+"` BIGINT NOT NULL DEFAULT 0, ";
}
string oDataContainer::C_INT(const string &name)
{
return " `"+name+"` INT NOT NULL DEFAULT 0, ";
}
string oDataContainer::C_SMALLINT(const string &name)
{
return " `"+name+"` SMALLINT NOT NULL DEFAULT 0, ";
}
string oDataContainer::C_TINYINT(const string &name)
{
return " `"+name+"` TINYINT NOT NULL DEFAULT 0, ";
}
string oDataContainer::C_SMALLINTU(const string &name)
{
return " `"+name+"` SMALLINT UNSIGNED NOT NULL DEFAULT 0, ";
}
string oDataContainer::C_TINYINTU(const string &name)
{
return " `"+name+"` TINYINT UNSIGNED NOT NULL DEFAULT 0, ";
}
string oDataContainer::C_STRING(const string &name, int len)
{
if (len>0) {
char bf[16];
sprintf_s(bf, "%d", len);
return " `"+name+"` VARCHAR("+ bf +") NOT NULL DEFAULT '', ";
}
else {
return " `"+name+"` MEDIUMTEXT NOT NULL, ";
}
}
string oDataContainer::SQL_quote(const wchar_t *in)
{
int len = wcslen(in);
size_t alloc = len*4+4;
if (alloc < 500) {
char output[512];
int len8 = WideCharToMultiByte(CP_UTF8, 0, in, len+1, output, alloc, 0, 0);
output[len8] = 0;
const char *inutf = output;
char out[1024];
int o=0;
while(*inutf && o<1023){
if (*inutf=='\'')
out[o++]='\'';
if (*inutf=='\\')
out[o++]='\\';
out[o++]=*inutf;
inutf++;
}
out[o]=0;
return out;
}
else {
vector output;
output.resize(alloc);
int len8 = WideCharToMultiByte(CP_UTF8, 0, in, len+1, &output.front(), alloc, 0, 0);
output[len8] = 0;
const char *inutf = &output.front();
vector out;
out.reserve(alloc);
while(*inutf){
if (*inutf=='\'')
out.push_back('\'');
if (*inutf=='\\')
out.push_back('\\');
out.push_back(*inutf);
inutf++;
}
out.push_back(0);
string outs(&out[0]);
return outs;
}
}
string oDataContainer::generateSQLDefinition(const std::set &exclude) const {
string sql;
bool addSyntx = !exclude.empty();
for (size_t k = 0; k < ordered.size(); k++) {
if (exclude.count(ordered[k].Name) == 0) {
if (addSyntx)
sql += "ADD COLUMN ";
const oDataInfo &di = ordered[k];
string name = di.Name;
if (di.Type==oDTInt){
if (di.SubType==oIS32 || di.SubType==oISDate || di.SubType==oISCurrency ||
di.SubType==oISTime || di.SubType==oISDecimal)
sql+=C_INT(name);
else if (di.SubType==oIS16)
sql+=C_SMALLINT(name);
else if (di.SubType==oIS8)
sql+=C_TINYINT(name);
else if (di.SubType==oIS64)
sql+=C_INT64(name);
else if (di.SubType==oIS16U)
sql+=C_SMALLINTU(name);
else if (di.SubType==oIS8U)
sql+=C_TINYINTU(name);
}
else if (di.Type==oDTString){
sql+=C_STRING(name, di.Size-1);
}
else if (di.Type==oDTStringDynamic || di.Type==oDTStringArray){
sql+=C_STRING(name, -1);
}
}
}
if (addSyntx && !sql.empty())
return sql.substr(0, sql.length() - 2); //Remove trailing comma-space
else
return sql;
}
bool oDataContainer::isModified(const oDataInfo &di,
const void *data,
const void *oldData,
vector< vector > *strptr) const {
if (di.Type == oDTInt) {
LPBYTE vd=LPBYTE(data)+di.Index;
LPBYTE vdOld=LPBYTE(oldData)+di.Index;
if (di.SubType != oIS64) {
return memcmp(vd, vdOld, 4) != 0;
}
else {
return memcmp(vd, vdOld, 8) != 0;
}
}
else if (di.Type == oDTString){
char * vd=(char *)(data)+di.Index;
char * vdOld=(char *)(oldData)+di.Index;
return strcmp(vd, vdOld) != 0;
}
else if (di.Type == oDTStringDynamic){
const wstring &newS = (*strptr)[0][di.Index];
const wstring &oldS = (*strptr)[1][di.Index];
return newS != oldS;
}
else if (di.Type == oDTStringArray){
const vector &newS = (*strptr)[di.Index];
const vector &oldS = (*strptr)[di.Index+1];
return newS != oldS;
}
else
return true;
}
void oDataContainer::allDataStored(const oBase *ob) {
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
memcpy(oldData, data, ob->getDISize());
if (stringIndexPointer > 0 || stringArrayIndexPointer > 2) {
for (size_t k = 0; k < stringArrayIndexPointer; k+=2) {
(*strptr)[k+1] = (*strptr)[k];
}
}
}
namespace {
char *ensureCapacity(int size, vector &bfData, int &alloc) {
assert(alloc > 100);
if (size >= alloc) {
alloc += size;
bfData.resize(alloc);
}
return &bfData[0];
}
}
string oDataContainer::generateSQLSet(const oBase *ob, bool forceSetAll) const {
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
string sql;
int alloc = 256;
vector bfData(alloc);
char *bf = &bfData[0];
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (!forceSetAll && !isModified(di, data, oldData, strptr)) {
continue;
}
if (di.Type==oDTInt) {
LPBYTE vd=LPBYTE(data)+di.Index;
if (di.SubType == oIS8U) {
sprintf_s(bf, alloc, ", `%s`=%u", di.Name, (*((int *)vd))&0xFF);
sql+=bf;
}
else if (di.SubType == oIS16U) {
sprintf_s(bf, alloc, ", `%s`=%u", di.Name, (*((int *)vd))&0xFFFF);
sql+=bf;
}
else if (di.SubType == oIS8) {
char r = (*((int *)vd))&0xFF;
sprintf_s(bf, alloc, ", `%s`=%d", di.Name, (int)r);
sql+=bf;
}
else if (di.SubType == oIS16) {
short r = (*((int *)vd))&0xFFFF;
sprintf_s(bf, alloc, ", `%s`=%d", di.Name, (int)r);
sql+=bf;
}
else if (di.SubType != oIS64) {
sprintf_s(bf, alloc, ", `%s`=%d", di.Name, *((int *)vd));
sql+=bf;
}
else {
char tmp[32];
_i64toa_s(*((__int64 *)vd), tmp, 32, 10);
sprintf_s(bf, alloc, ", `%s`=%s", di.Name, tmp);
sql+=bf;
}
}
else if (di.Type==oDTString) {
LPBYTE vd=LPBYTE(data)+di.Index;
sprintf_s(bf, alloc, ", `%s`='%s'", di.Name, SQL_quote((wchar_t *)vd).c_str());
sql+=bf;
}
else if (di.Type==oDTStringDynamic) {
const wstring &str = (*strptr)[0][di.Index];
bf = ensureCapacity(2 * str.length() + 30, bfData, alloc);
sprintf_s(bf, alloc, ", `%s`='%s'", di.Name, SQL_quote(str.c_str()).c_str());
sql+=bf;
}
else if (di.Type==oDTStringArray) {
const wstring str = encodeArray((*strptr)[di.Index]);
bf = ensureCapacity(2 * str.length() + 30, bfData, alloc);
sprintf_s(bf, alloc, ", `%s`='%s'", di.Name, SQL_quote(str.c_str()).c_str());
sql+=bf;
}
}
return sql;
}
void oDataContainer::getVariableInt(const void *data,
list &var) const {
var.clear();
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.Type == oDTInt) {
LPBYTE vd=LPBYTE(data)+di.Index;
oVariableInt vi;
memcpy(vi.name, di.Name, sizeof(vi.name));
if (di.SubType != oIS64)
vi.data32 = (int *)vd;
else
vi.data64 = (__int64 *)vd;
var.push_back(vi);
}
}
}
void oDataContainer::getVariableString(const oBase *ob,
list &var) const
{
void *data, *oldData;
vector< vector > *strptr;
ob->getDataBuffers(data, oldData, strptr);
var.clear();
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.Type == oDTString){
LPBYTE vd=(LPBYTE)(data)+di.Index;
oVariableString vs((wchar_t *)vd, di.Size);
memcpy(vs.name, di.Name, sizeof(vs.name));
var.push_back(vs);
}
else if (di.Type == oDTStringDynamic) {
oVariableString vs((*strptr)[0], di.Index);
memcpy(vs.name, di.Name, sizeof(vs.name));
var.push_back(vs);
}
else if (di.Type == oDTStringArray) {
oVariableString vs((*strptr)[di.Index]);
memcpy(vs.name, di.Name, sizeof(vs.name));
var.push_back(vs);
}
}
}
oDataInterface oDataContainer::getInterface(void *data, int datasize, oBase *ob)
{
if (datasizeaddDataDefiner(di.Name, di.dataDefiner);
int w = strlen(di.Description)*6;
di.tableIndex = di.dataDefiner->addTableColumn(table, di.Description, w);
}
else if (di.Type == oDTInt) {
bool right = di.SubType == oISCurrency;
bool numeric = di.SubType != oISDate && di.SubType != oISTime;
int w;
if (di.SubType == oISDecimal)
w = max( (di.decimalSize+4)*10, 70);
else
w = 70;
w = max(int(strlen(di.Description))*6, w);
di.tableIndex = table->addColumn(di.Description, w, numeric, right);
}
else if (di.Type == oDTString) {
int w = max(max(di.Size+1, int(strlen(di.Description)))*6, 70);
for (size_t k = 0; k < di.enumDescription.size(); k++)
w = max(w, lang.tl(di.enumDescription[k].second).length() * 6);
if (di.zeroSortPadding)
di.tableIndex = table->addColumnPaddedSort(di.Description, w, di.zeroSortPadding, true);
else
di.tableIndex = table->addColumn(di.Description, w, false);
}
else if (di.Type == oDTStringDynamic) {
int w = 64*6;
di.tableIndex = table->addColumn(di.Description, w, false);
}
}
}
bool oDataContainer::formatNumber(int nr, const oDataInfo &di, wchar_t bf[64]) const {
if (di.SubType == oISDate) {
if (nr>0) {
swprintf_s(bf, 64, L"%d-%02d-%02d", nr/(100*100), (nr/100)%100, nr%100);
}
else {
bf[0] = '-';
bf[1] = 0;
}
return true;
}
else if (di.SubType == oISTime) {
if (nr>0 && nr<(30*24*3600)) {
if (nr < 24*3600)
swprintf_s(bf, 64, L"%02d:%02d:%02d", nr/3600, (nr/60)%60, nr%60);
else {
int days = nr / (24*3600);
nr = nr % (24*3600);
swprintf_s(bf, 64, L"%d+%02d:%02d:%02d", days, nr/3600, (nr/60)%60, nr%60);
}
}
else {
bf[0] = '-';
bf[1] = 0;
}
return true;
}
else if (di.SubType == oISDecimal) {
if (nr) {
int whole = nr / di.decimalScale;
int part = nr - whole * di.decimalScale;
wstring deci = L",";
wstring ptrn = L"%d" + deci + L"%0" + itow(di.decimalSize) + L"d";
swprintf_s(bf, 64, ptrn.c_str(), whole, abs(part));
}
else
bf[0] = 0;
return true;
}
else {
if (nr)
swprintf_s(bf, 64, L"%d", nr);
else
bf[0] = 0;
return true;
}
}
int oDataContainer::fillTableCol(const oBase &owner, Table &table, bool canEdit) const {
void *data, *oldData;
vector< vector > *strptr;
owner.getDataBuffers(data, oldData, strptr);
int nextIndex = 0;
wchar_t bf[64];
oBase &ob = *(oBase *)&owner;
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.dataDefiner != 0) {
table.set(di.tableIndex, ob, 1000+di.tableIndex, di.dataDefiner->formatData(&ob), canEdit);
}
else if (di.Type==oDTInt) {
LPBYTE vd=LPBYTE(data)+di.Index;
if (di.SubType != oIS64) {
int nr;
memcpy(&nr, vd, sizeof(int));
if (di.SubType == oISCurrency) {
table.set(di.tableIndex, ob, 1000+di.tableIndex, ob.getEvent()->formatCurrency(nr), canEdit);
}
else {
formatNumber(nr, di, bf);
table.set(di.tableIndex, ob, 1000+di.tableIndex, bf, canEdit);
}
}
else {
__int64 nr;
memcpy(&nr, vd, sizeof(__int64));
wchar_t bf[16];
oBase::converExtIdentifierString(nr, bf);
table.set(di.tableIndex, ob, 1000+di.tableIndex, bf, canEdit);
}
}
else if (di.Type==oDTString) {
LPBYTE vd=LPBYTE(data)+di.Index;
if (di.SubType == oSSString || !canEdit) {
table.set(di.tableIndex, *((oBase*)&owner), 1000+di.tableIndex, (wchar_t *)vd, canEdit, cellEdit);
}
else {
wstring str((wchar_t *)vd);
for (size_t k = 0; k > *strptr;
ob->getDataBuffers(data, oldData, strptr);
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.tableIndex+1000==id) {
if (di.dataDefiner) {
const wstring &src = di.dataDefiner->formatData(ob);
output = di.dataDefiner->setData(ob, input);
bool ch = output != src;
if (ch && noUpdate == false)
ob->synchronize(true);
return ch;
}
else if (di.Type==oDTInt) {
LPBYTE vd=LPBYTE(data)+di.Index;
int no = 0;
if (di.SubType == oISCurrency) {
no = ob->getEvent()->interpretCurrency(input);
}
else if (di.SubType == oISDate) {
no = convertDateYMS(input, true);
}
else if (di.SubType == oISTime) {
no = convertAbsoluteTimeHMS(input, -1);
}
else if (di.SubType == oISDecimal) {
wstring str = input;
for (size_t k = 0; k < str.length(); k++) {
if (str[k] == ',') {
str[k] = '.';
break;
}
}
double val = _wtof(str.c_str());
no = int(di.decimalScale * val);
}
else if (di.SubType == oIS64) {
//__int64 no64 = _atoi64(input.c_str());
__int64 k64;
memcpy(&k64, vd, sizeof(__int64));
__int64 no64 = oBase::converExtIdentifierString(input);
memcpy(vd, &no64, sizeof(__int64));
__int64 out64 = no64;
if (k64 != no64) {
ob->updateChanged();
if (noUpdate == false)
ob->synchronize(true);
memcpy(&out64, vd, sizeof(__int64));
}
//output = itos(out64);
wchar_t outbf[16];
oBase::converExtIdentifierString(out64, outbf);
output = outbf;
return k64 != no64;
}
else
no = _wtoi(input.c_str());
int k;
memcpy(&k, vd, sizeof(int));
memcpy(vd, &no, sizeof(int));
wchar_t bf[128];
int outN = no;
if (k != no) {
ob->updateChanged();
if (noUpdate == false)
ob->synchronize(true);
memcpy(&outN, vd, sizeof(int));
}
formatNumber(outN, di, bf);
output = bf;
return k != no;
}
else if (di.Type==oDTString) {
LPBYTE vd=LPBYTE(data)+di.Index;
const wchar_t *str = input.c_str();
if (di.SubType == oSSEnum) {
size_t ix = inputId-1;
if (ix < di.enumDescription.size()) {
str = di.enumDescription[ix].first.c_str();
}
}
if (wcscmp((wchar_t *)vd, str)!=0) {
wcsncpy_s((wchar_t *)vd, di.Size/sizeof(wchar_t), str, (di.Size-1)/sizeof(wchar_t));
ob->updateChanged();
if (noUpdate == false)
ob->synchronize(true);
if (di.SubType == oSSEnum) {
size_t ix = inputId-1;
if (ix < di.enumDescription.size()) {
output = lang.tl(di.enumDescription[ix].second);
// This might be incorrect if data was changed on server,
// but this issue is minor, I think: conflicts have no resolution
// Anyway, the row will typically be reloaded
}
else
output=(wchar_t *)vd;
}
else
output=(wchar_t *)vd;
return true;
}
else
output=input;
return false;
}
else if (di.Type == oDTStringDynamic) {
wstring &vd = (*strptr)[0][di.Index];
if (vd != input) {
vd = input;
ob->updateChanged();
if (noUpdate == false)
ob->synchronize(true);
output = (*strptr)[0][di.Index];
return true;
}
else
output=input;
return false;
}
}
}
return true;
}
void oDataContainer::fillInput(const void *data, int id, const char *name,
vector< pair > &out, size_t &selected) const {
const oDataInfo * info = findVariable(name);
if (!info) {
for (size_t kk = 0; kk < ordered.size(); kk++) {
const oDataInfo &di=ordered[kk];
if (di.tableIndex+1000==id && di.Type == oDTString && di.SubType == oSSEnum) {
info = &di;
break;
}
}
}
if (info && info->Type == oDTString && info->SubType == oSSEnum) {
wchar_t *vd = (wchar_t *)(LPBYTE(data)+info->Index);
selected = -1;
for (size_t k = 0; k < info->enumDescription.size(); ++k) {
out.push_back(make_pair(lang.tl(info->enumDescription[k].second), k+1));
if (info->enumDescription[k].first == wstring(vd))
selected = k+1;
}
}
else
throw meosException("Invalid enum");
}
bool oDataContainer::setEnum(oBase *ob, const char *name, int selectedIndex) {
const oDataInfo * info = findVariable(name);
if (info && info->Type == oDTString && info->SubType == oSSEnum) {
if (size_t(selectedIndex - 1) < info->enumDescription.size()) {
return setString(ob, name, info->enumDescription[selectedIndex-1].first);
}
}
throw meosException("Invalid enum");
}
bool oVariableString::store(const wchar_t *in) {
if (data) {
if (wcscmp(in, data) != 0) {
wcsncpy_s(data, maxSize/sizeof(wchar_t), in, (maxSize-1)/sizeof(wchar_t));
return true;
}
return false;
}
else {
vector &str = *strData;
if (strIndex>=0) {
if (str[strIndex] != in) {
str[strIndex] = in;
return true;
}
else
return false;
}
}
return false;
}
wstring oDataContainer::encodeArray(const vector &input) {
return L"";//XXX
}
void oDataContainer::decodeArray(const string &input, vector &output) {
}