1424 lines
46 KiB
C++
1424 lines
46 KiB
C++
/************************************************************************
|
|
MeOS - Orienteering Software
|
|
Copyright (C) 2009-2018 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 <http://www.gnu.org/licenses/>.
|
|
|
|
Melin Software HB - software@melin.nu - www.melin.nu
|
|
Eksoppsvägen 16, SE-75646 UPPSALA, Sweden
|
|
|
|
************************************************************************/
|
|
|
|
// csvparser.cpp: implementation of the csvparser class.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stdafx.h"
|
|
#include "meos.h"
|
|
#include "csvparser.h"
|
|
#include "oEvent.h"
|
|
#include "SportIdent.h"
|
|
#include "meos_util.h"
|
|
#include "localizer.h"
|
|
#include "importformats.h"
|
|
|
|
#include "meosexception.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[]=__FILE__;
|
|
#define new DEBUG_NEW
|
|
#endif
|
|
|
|
#include <vector>
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
const int externalSourceId = 17000017;
|
|
extern gdioutput *gdi_main;
|
|
|
|
static int wtoi(const wstring &sp) {
|
|
return _wtoi(sp.c_str());
|
|
}
|
|
csvparser::csvparser()
|
|
{
|
|
LineNumber=0;
|
|
}
|
|
|
|
csvparser::~csvparser()
|
|
{
|
|
|
|
}
|
|
|
|
int csvparser::iscsv(const wstring &file)
|
|
{
|
|
fin.open(file);
|
|
|
|
if (!fin.good())
|
|
return false;
|
|
|
|
char bf[2048];
|
|
fin.getline(bf, 2048);
|
|
|
|
while(fin.good() && strlen(bf)<3)
|
|
fin.getline(bf, 2048);
|
|
|
|
fin.close();
|
|
|
|
vector<char *> sp;
|
|
split(bf, sp);
|
|
|
|
if (sp.size()==1 && strcmp(sp[0], "RAIDDATA")==0)
|
|
return 3;
|
|
|
|
if (sp.size()<5)//No csv
|
|
return 0;
|
|
|
|
if (_stricmp(sp[1], "Descr")==0 || _stricmp(sp[1], "Namn")==0
|
|
|| _stricmp(sp[1], "Descr.")==0 || _stricmp(sp[1], "Navn")==0) //OS-fil (SWE/ENG)??
|
|
return 2;
|
|
else return 1; //OE?!
|
|
}
|
|
|
|
RunnerStatus ConvertOEStatus(int i)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 0:
|
|
return StatusOK;
|
|
case 1: // Ej start
|
|
return StatusDNS;
|
|
case 2: // Utg.
|
|
return StatusDNF;
|
|
case 3: // Felst.
|
|
return StatusMP;
|
|
case 4: //Disk
|
|
return StatusDQ;
|
|
case 5: //Maxtid
|
|
return StatusMAX;
|
|
}
|
|
return StatusUnknown;
|
|
}
|
|
|
|
|
|
//Stno;Descr;Block;nc;Start;Time;Classifier;Club no.;Cl.name;City;Nat;Cl. no.;Short;Long;Legs;Num1;Num2;Num3;Text1;Text2;Text3;Start fee;Paid;Surname;First name;YB;S;Start;Finish;Time;Classifier;Chip;Rented;Database Id;Surname;First name;YB;S;Start;Finish;Time;Classifier;Chip;Rented;Database Id;Surname;First name;YB;S;Start;Finish;Time;Classifier;Chip;Rented;Database Id;(may be more) ...
|
|
|
|
bool csvparser::importOS_CSV(oEvent &event, const wstring &file)
|
|
{
|
|
enum {OSstno=0, OSdesc=1, OSstart=4, OStime=5, OSstatus=6, OSclubno=7, OSclub=9,
|
|
OSnat=10, OSclassno=11, OSclass=12, OSlegs=14, OSfee=21, OSpaid=22};
|
|
|
|
const int Offset=23;
|
|
const int PostSize=11;
|
|
|
|
enum {OSRsname=0, OSRfname=1, OSRyb=2, OSRsex=3, OSRstart=4,
|
|
OSRfinish=5, OSRstatus=7, OSRcard=8, OSRrentcard=9};
|
|
/*
|
|
fin.open(file);
|
|
|
|
if (!fin.good())
|
|
return false;
|
|
|
|
char bf[1024];
|
|
fin.getline(bf, 1024);
|
|
*/
|
|
nimport=0;
|
|
list< vector<wstring> > allLines;
|
|
parse(file, allLines);
|
|
//vector<wchar_t *> sp;
|
|
list< vector<wstring> >::iterator it = allLines.begin();
|
|
// Skip first line
|
|
while (++it != allLines.end()) {
|
|
//fin.getline(bf, 1024);
|
|
//split(bf, sp);
|
|
const vector<wstring> &sp = *it;
|
|
|
|
if (sp.size()>20 && sp[OSclub].size()>0)
|
|
{
|
|
nimport++;
|
|
|
|
//Create club with this club number...
|
|
int ClubId=wtoi(sp[OSclubno]);
|
|
pClub pclub=event.getClubCreate(ClubId, sp[OSclub]);
|
|
|
|
if (pclub){
|
|
pclub->getDI().setString("Nationality", sp[OSnat]);
|
|
pclub->synchronize(true);
|
|
}
|
|
|
|
//Create class with this class number...
|
|
int ClassId=wtoi(sp[OSclassno]);
|
|
event.getClassCreate(ClassId, sp[OSclass]);
|
|
|
|
//Club is autocreated...
|
|
pTeam team=event.addTeam(sp[OSclub] + L" " + sp[OSdesc], ClubId, ClassId);
|
|
team->setEntrySource(externalSourceId);
|
|
|
|
team->setStartNo(wtoi(sp[OSstno]), false);
|
|
|
|
if (sp[12].length()>0)
|
|
team->setStatus( ConvertOEStatus( wtoi(sp[OSstatus]) ), true, false);
|
|
|
|
team->setStartTime(event.convertAbsoluteTime(sp[OSstart]), true, false);
|
|
|
|
if (sp[OStime].length()>0)
|
|
team->setFinishTime( event.convertAbsoluteTime(sp[OSstart])+event.convertAbsoluteTime(sp[OStime])-event.getZeroTimeNum() );
|
|
|
|
if (team->getStatus()==StatusOK && team->getFinishTime()==0)
|
|
team->setStatus(StatusUnknown, true, false);
|
|
|
|
unsigned rindex=Offset;
|
|
|
|
oDataInterface teamDI=team->getDI();
|
|
|
|
teamDI.setInt("Fee", wtoi(sp[OSfee]));
|
|
teamDI.setInt("Paid", wtoi(sp[OSpaid]));
|
|
teamDI.setString("Nationality", sp[OSnat]);
|
|
|
|
//Import runners!
|
|
int runner=0;
|
|
while( (rindex+OSRrentcard)<sp.size() && sp[rindex+OSRfname].length()>0 ){
|
|
int year = extendYear(wtoi(sp[rindex+OSRyb]));
|
|
int cardNo = wtoi(sp[rindex+OSRcard]);
|
|
wstring sname = sp[rindex+OSRsname] + L", " + sp[rindex+OSRfname];
|
|
pRunner r = event.addRunner(sname, ClubId,
|
|
ClassId, cardNo, year, false);
|
|
|
|
r->setEntrySource(externalSourceId);
|
|
oDataInterface DI=r->getDI();
|
|
r->setSex(interpretSex(sp[rindex + OSRsex]));
|
|
DI.setString("Nationality", sp[OSnat]);
|
|
|
|
if (sp[rindex+OSRrentcard].length() > 0)
|
|
DI.setInt("CardFee", event.getDCI().getInt("CardFee"));
|
|
|
|
//r->setCardNo(atoi(sp[rindex+OSRcard]), false);
|
|
r->setStartTime(event.convertAbsoluteTime(sp[rindex+OSRstart]), true, false);
|
|
r->setFinishTime( event.convertAbsoluteTime(sp[rindex+OSRfinish]) );
|
|
|
|
if (sp[rindex+OSRstatus].length()>0)
|
|
r->setStatus( ConvertOEStatus( wtoi(sp[rindex+OSRstatus]) ), true, false);
|
|
|
|
if (r->getStatus()==StatusOK && r->getRunningTime()==0)
|
|
r->setStatus(StatusUnknown, true, false);
|
|
|
|
r->addClassDefaultFee(false);
|
|
|
|
team->setRunner(runner++, r, true);
|
|
|
|
rindex+=PostSize;
|
|
}
|
|
//int nrunners=team->GetNumRunners();
|
|
pClass pc=event.getClass(ClassId);
|
|
|
|
if (pc && runner>(int)pc->getNumStages())
|
|
pc->setNumStages(runner);
|
|
|
|
team->apply(true, 0, false);
|
|
}
|
|
}
|
|
fin.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool csvparser::importOE_CSV(oEvent &event, const wstring &file) {
|
|
|
|
enum {OEstno=0, OEcard=1, OEid=2, OEsurname=3, OEfirstname=4,
|
|
OEbirth=5, OEsex=6, OEstart=9, OEfinish=10, OEstatus=12,
|
|
OEclubno=13, OEclub=14, OEclubcity=15, OEnat=16, OEclassno=17, OEclass=18, OEbib=23,
|
|
OErent=35, OEfee=36, OEpaid=37, OEcourseno=38, OEcourse=39,
|
|
OElength=40};
|
|
|
|
/* fin.open(file);
|
|
|
|
if (!fin.good())
|
|
return false;
|
|
|
|
char bf[1024];
|
|
fin.getline(bf, 1024);
|
|
*/
|
|
list< vector<wstring> > allLines;
|
|
parse(file, allLines);
|
|
list< vector<wstring> >::iterator it = allLines.begin();
|
|
// Skip first line
|
|
|
|
|
|
nimport=0;
|
|
while (++it != allLines.end()) {
|
|
//fin.getline(bf, 1024);
|
|
//split(bf, sp);
|
|
const vector<wstring> &sp = *it;
|
|
if (sp.size()>20) {
|
|
nimport++;
|
|
|
|
int clubId = wtoi(sp[OEclubno]);
|
|
wstring clubName;
|
|
wstring shortClubName;
|
|
//string clubCity;
|
|
|
|
clubName = sp[OEclubcity];
|
|
shortClubName = sp[OEclub];
|
|
|
|
if (clubName.empty() && !shortClubName.empty())
|
|
swap(clubName, shortClubName);
|
|
|
|
pClub pclub = event.getClubCreate(clubId, clubName);
|
|
|
|
if (pclub) {
|
|
if (sp[OEnat].length()>0)
|
|
pclub->getDI().setString("Nationality", sp[OEnat]);
|
|
|
|
pclub->getDI().setString("ShortName", shortClubName.substr(0, 8));
|
|
pclub->setExtIdentifier(clubId);
|
|
pclub->synchronize(true);
|
|
}
|
|
|
|
__int64 extId = oBase::converExtIdentifierString(sp[OEid]);
|
|
int id = oBase::idFromExtId(extId);
|
|
pRunner pr = 0;
|
|
|
|
if (id>0)
|
|
pr = event.getRunner(id, 0);
|
|
|
|
while (pr) { // Check that the exact match is OK
|
|
if (extId == pr->getExtIdentifier())
|
|
break;
|
|
id++;
|
|
pr = event.getRunner(id, 0);
|
|
}
|
|
|
|
if (pr) {
|
|
if (pr->getEntrySource() != externalSourceId) {
|
|
// If not same source, do not accept match (will not work with older versions of MeOS files)
|
|
pr = 0;
|
|
id = 0;
|
|
}
|
|
}
|
|
|
|
const bool newEntry = (pr == 0);
|
|
|
|
if (pr == 0) {
|
|
if (id==0) {
|
|
oRunner r(&event);
|
|
pr = event.addRunner(r, true);
|
|
}
|
|
else {
|
|
oRunner r(&event, id);
|
|
pr = event.addRunner(r, true);
|
|
}
|
|
}
|
|
|
|
if (pr==0)
|
|
continue;
|
|
|
|
pr->setExtIdentifier(extId);
|
|
pr->setEntrySource(externalSourceId);
|
|
|
|
if (!pr->hasFlag(oAbstractRunner::FlagUpdateName)) {
|
|
wstring name = sp[OEsurname] + L", " + sp[OEfirstname];
|
|
pr->setName(name, false);
|
|
}
|
|
pr->setClubId(pclub ? pclub->getId():0);
|
|
pr->setCardNo( wtoi(sp[OEcard]), false );
|
|
|
|
pr->setStartTime(event.convertAbsoluteTime(sp[OEstart]), true, false);
|
|
pr->setFinishTime(event.convertAbsoluteTime(sp[OEfinish]));
|
|
|
|
if (sp[OEstatus].length()>0)
|
|
pr->setStatus( ConvertOEStatus( wtoi(sp[OEstatus]) ), true, false);
|
|
|
|
if (pr->getStatus()==StatusOK && pr->getRunningTime()==0)
|
|
pr->setStatus(StatusUnknown, true, false);
|
|
|
|
//Autocreate class if it does not exist...
|
|
int classId=wtoi(sp[OEclassno]);
|
|
if (classId>0 && !pr->hasFlag(oAbstractRunner::FlagUpdateClass)) {
|
|
pClass pc=event.getClassCreate(classId, sp[OEclass]);
|
|
|
|
if (pc) {
|
|
pc->synchronize();
|
|
if (pr->getClassId(false) == 0 || !pr->hasFlag(oAbstractRunner::FlagUpdateClass))
|
|
pr->setClassId(pc->getId(), false);
|
|
}
|
|
}
|
|
int stno=wtoi(sp[OEstno]);
|
|
bool needSno = pr->getStartNo() == 0 || newEntry;
|
|
bool needBib = pr->getBib().empty();
|
|
|
|
if (needSno || newEntry) {
|
|
if (stno>0)
|
|
pr->setStartNo(stno, false);
|
|
else
|
|
pr->setStartNo(nimport, false);
|
|
}
|
|
oDataInterface DI=pr->getDI();
|
|
|
|
pr->setSex(interpretSex(sp[OEsex]));
|
|
DI.setInt("BirthYear", extendYear(wtoi(sp[OEbirth])));
|
|
DI.setString("Nationality", sp[OEnat]);
|
|
|
|
if (sp.size()>OEbib && needBib)
|
|
pr->setBib(sp[OEbib], 0, false, false);
|
|
|
|
if (sp.size()>=38) {//ECO
|
|
DI.setInt("Fee", wtoi(sp[OEfee]));
|
|
DI.setInt("CardFee", wtoi(sp[OErent]));
|
|
DI.setInt("Paid", wtoi(sp[OEpaid]));
|
|
}
|
|
|
|
if (sp.size()>=40) {//Course
|
|
if (pr->getCourse(false) == 0) {
|
|
const wstring &cid=sp[OEcourseno];
|
|
const int courseid=wtoi(cid);
|
|
if (courseid>0) {
|
|
pCourse course=event.getCourse(courseid);
|
|
|
|
if (!course) {
|
|
oCourse oc(&event, courseid);
|
|
oc.setLength(int(_wtof(sp[OElength].c_str())*1000));
|
|
oc.setName(sp[OEcourse]);
|
|
course = event.addCourse(oc);
|
|
if (course)
|
|
course->synchronize();
|
|
}
|
|
if (course) {
|
|
if (pr->getClassId(false) != 0)
|
|
event.getClass(pr->getClassId(false))->setCourse(course);
|
|
else
|
|
pr->setCourseId(course->getId());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (pr)
|
|
pr->synchronize();
|
|
}
|
|
}
|
|
fin.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool csvparser::openOutput(const wstring &filename, bool writeUTF)
|
|
{
|
|
checkWriteAccess(filename);
|
|
fout.open(filename);
|
|
|
|
if (fout.bad())
|
|
return false;
|
|
|
|
if (writeUTF) {
|
|
fout.put(-17);
|
|
fout.put(-69);
|
|
fout.put(-65);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool csvparser::outputRow(const string &row)
|
|
{
|
|
fout << row << endl;
|
|
return true;
|
|
}
|
|
bool csvparser::outputRow(const vector<string> &out)
|
|
{
|
|
int size=out.size();
|
|
|
|
for(int i=0;i<size;i++){
|
|
string p=out[i];
|
|
|
|
//Replace " with '
|
|
int found=p.find_first_of("\"");
|
|
while (found!=string::npos){
|
|
p[found]='\'';
|
|
found=p.find_first_of("\"",found+1);
|
|
}
|
|
|
|
if (i>0) fout << ";";
|
|
|
|
if (p.find_first_of("; ,\t.")!=string::npos)
|
|
fout << "\"" << p << "\"";
|
|
else fout << p;
|
|
}
|
|
fout << endl;
|
|
fout.flush();
|
|
return true;
|
|
}
|
|
|
|
bool csvparser::closeOutput()
|
|
{
|
|
fout.close();
|
|
return true;
|
|
}
|
|
|
|
|
|
int csvparser::split(char *line, vector<char *> &split_vector)
|
|
{
|
|
split_vector.clear();
|
|
int len=strlen(line);
|
|
bool cite=false;
|
|
|
|
for(int m=0;m<len;m++)
|
|
{
|
|
char *ptr=&line[m];
|
|
|
|
if (*ptr=='"')
|
|
ptr++;
|
|
|
|
while(line[m])
|
|
{
|
|
if (!cite && line[m]==';')
|
|
line[m]=0;
|
|
else
|
|
{
|
|
if (line[m]=='"')
|
|
{
|
|
cite=!cite;
|
|
line[m]=0;
|
|
if (cite)
|
|
ptr=&line[m+1];
|
|
}
|
|
m++;
|
|
}
|
|
}
|
|
line[m]=0;
|
|
|
|
split_vector.push_back(ptr);
|
|
|
|
//m++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int csvparser::split(wchar_t *line, vector<wchar_t *> &split_vector)
|
|
{
|
|
split_vector.clear();
|
|
int len=wcslen(line);
|
|
bool cite=false;
|
|
|
|
for(int m=0;m<len;m++)
|
|
{
|
|
wchar_t *ptr=&line[m];
|
|
|
|
if (*ptr=='"')
|
|
ptr++;
|
|
|
|
while(line[m])
|
|
{
|
|
if (!cite && line[m]==';')
|
|
line[m]=0;
|
|
else
|
|
{
|
|
if (line[m]=='"')
|
|
{
|
|
cite=!cite;
|
|
line[m]=0;
|
|
if (cite)
|
|
ptr=&line[m+1];
|
|
}
|
|
m++;
|
|
}
|
|
}
|
|
line[m]=0;
|
|
|
|
split_vector.push_back(ptr);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
bool csvparser::importOCAD_CSV(oEvent &event, const wstring &file, bool addClasses) {
|
|
list< vector<wstring> > allLines;
|
|
parse(file, allLines);
|
|
list< vector<wstring> >::iterator it = allLines.begin();
|
|
|
|
while(it != allLines.end()) {
|
|
const vector<wstring> &sp = *it;
|
|
++it;
|
|
|
|
if (sp.size()>7) {
|
|
size_t firstIndex = 7;
|
|
bool hasLengths = true;
|
|
int offset = 0;
|
|
if (wtoi(sp[firstIndex]) < 30) {
|
|
firstIndex = 6;
|
|
offset = -1;
|
|
}
|
|
|
|
if (wtoi(sp[firstIndex])<30 || wtoi(sp[firstIndex])>1000) {
|
|
wstring str = L"Ogiltig banfil. Kontroll förväntad på position X, men hittade 'Y'.#"
|
|
+ itow(firstIndex+1) + L"#" + sp[firstIndex];
|
|
throw meosException(str.c_str());
|
|
}
|
|
|
|
while (firstIndex > 0 && wtoi(sp[firstIndex])>30 && wtoi(sp[firstIndex])>1000) {
|
|
firstIndex--;
|
|
}
|
|
wstring Start = lang.tl(L"Start ") + L"1";
|
|
double Length = 0;
|
|
wstring Course = event.getAutoCourseName();
|
|
wstring Class = L"";
|
|
|
|
if (firstIndex>=6) {
|
|
Class = sp[0];
|
|
Course = sp[1+offset];
|
|
Start = sp[5+offset];
|
|
Length = _wtof(sp[3+offset].c_str());
|
|
|
|
if (Start[0]=='S') {
|
|
int num = wtoi(Start.substr(1));
|
|
if (num>0)
|
|
Start = lang.tl(L"Start ") + Start.substr(1);
|
|
}
|
|
}
|
|
else
|
|
hasLengths = false;
|
|
|
|
//Get controls
|
|
pCourse pc=event.getCourse(Course);
|
|
|
|
if (!pc) {
|
|
pc = event.addCourse(Course, int(Length*1000));
|
|
}
|
|
else {
|
|
// Reset control
|
|
pc->importControls("", false);
|
|
pc->setLength(int(Length*1000));
|
|
}
|
|
|
|
|
|
vector<int> legLengths;
|
|
|
|
if (hasLengths) {
|
|
double legLen = _wtof(sp[firstIndex-1].c_str()); // Length in km
|
|
if (legLen > 0.001 && legLen < 30)
|
|
legLengths.push_back(int(legLen*1000));
|
|
}
|
|
|
|
if (pc) {
|
|
for (size_t k=firstIndex; k<sp.size()-1;k+=(hasLengths ? 2 : 1)) {
|
|
wstring ctrlStr = trim(sp[k]);
|
|
if (!ctrlStr.empty()) {
|
|
int ctrl = wtoi(ctrlStr.c_str());
|
|
|
|
if (ctrl == 0 && trim(sp[k+1]).length() == 0)
|
|
break; // Done
|
|
|
|
if (ctrl >= 30 && ctrl < 1000)
|
|
pc->addControl(wtoi(sp[k]));
|
|
else {
|
|
wstring str = L"Oväntad kontroll 'X' i bana Y.#" + ctrlStr + L"#" + pc->getName();
|
|
throw meosException(str);
|
|
}
|
|
}
|
|
if (hasLengths) {
|
|
double legLen = _wtof(sp[k+1].c_str()); // Length in km
|
|
if (legLen > 0.001 && legLen < 30)
|
|
legLengths.push_back(int(legLen*1000));
|
|
}
|
|
}
|
|
pc->setLength(int(Length*1000));
|
|
pc->setStart(Start, true);
|
|
|
|
if (legLengths.size() == pc->getNumControls()+1)
|
|
pc->setLegLengths(legLengths);
|
|
|
|
if (!Class.empty() && addClasses) {
|
|
pClass cls = event.getBestClassMatch(Class);
|
|
if (!cls)
|
|
cls = event.addClass(Class);
|
|
|
|
if (cls->getNumStages()==0) {
|
|
cls->setCourse(pc);
|
|
}
|
|
else {
|
|
for (size_t i = 0; i<cls->getNumStages(); i++)
|
|
cls->addStageCourse(i, pc->getId());
|
|
}
|
|
|
|
cls->synchronize();
|
|
}
|
|
|
|
pc->synchronize();
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
bool csvparser::importRAID(oEvent &event, const wstring &file)
|
|
{
|
|
enum {RAIDid=0, RAIDteam=1, RAIDcity=2, RAIDedate=3, RAIDclass=4,
|
|
RAIDclassid=5, RAIDrunner1=6, RAIDrunner2=7, RAIDcanoe=8};
|
|
|
|
list< vector<wstring> > allLines;
|
|
parse(file, allLines);
|
|
list< vector<wstring> >::iterator it = allLines.begin();
|
|
nimport=0;
|
|
while (++it != allLines.end()) {
|
|
const vector<wstring> &sp = *it;
|
|
|
|
if (sp.size()>7) {
|
|
nimport++;
|
|
|
|
int ClubId=0;
|
|
//Create class with this class number...
|
|
int ClassId=wtoi(sp[RAIDclassid]);
|
|
pClass pc = event.getClassCreate(ClassId, sp[RAIDclass]);
|
|
ClassId = pc->getId();
|
|
|
|
//Club is autocreated...
|
|
pTeam team=event.addTeam(sp[RAIDteam], ClubId, ClassId);
|
|
|
|
team->setStartNo(wtoi(sp[RAIDid]), false);
|
|
if (sp.size()>8)
|
|
team->getDI().setInt("SortIndex", wtoi(sp[RAIDcanoe]));
|
|
oDataInterface teamDI=team->getDI();
|
|
teamDI.setDate("EntryDate", sp[RAIDedate]);
|
|
|
|
if (pc) {
|
|
if (pc->getNumStages()<2)
|
|
pc->setNumStages(2);
|
|
|
|
pc->setLegType(0, LTNormal);
|
|
pc->setLegType(1, LTIgnore);
|
|
}
|
|
|
|
//Import runners!
|
|
pRunner r1=event.addRunner(sp[RAIDrunner1], ClubId, ClassId, 0, 0, false);
|
|
team->setRunner(0, r1, false);
|
|
|
|
pRunner r2=event.addRunner(sp[RAIDrunner2], ClubId, ClassId, 0, 0, false);
|
|
team->setRunner(1, r2, false);
|
|
|
|
team->apply(true, 0, false);
|
|
}
|
|
}
|
|
fin.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
int csvparser::selectPunchIndex(const wstring &competitionDate, const vector<wstring> &sp,
|
|
int &cardIndex, int &timeIndex, int &dateIndex,
|
|
wstring &processedTime, wstring &processedDate) {
|
|
int ci = -1;
|
|
int ti = -1;
|
|
int di = -1;
|
|
wstring pt, date;
|
|
int maxCardNo = 0;
|
|
processedDate.clear();
|
|
for (size_t k = 0; k < sp.size(); k++) {
|
|
processGeneralTime(sp[k], pt, date);
|
|
if (!pt.empty()) {
|
|
if (ti == -1) {
|
|
ti = k;
|
|
pt.swap(processedTime);
|
|
}
|
|
else {
|
|
return -1; // Not a unique time
|
|
}
|
|
if (!date.empty()) {
|
|
date.swap(processedDate);
|
|
di = k;
|
|
}
|
|
}
|
|
else if (k == 2 && sp[k].length() == 2 && processedDate.empty()) {
|
|
processedDate = sp[k]; // Old weekday format
|
|
dateIndex = 2;
|
|
}
|
|
else {
|
|
int cno = wtoi(sp[k]);
|
|
if (cno > maxCardNo) {
|
|
maxCardNo = cno;
|
|
ci = k;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (ti == -1)
|
|
return 0; // No time found
|
|
if (ci == -1)
|
|
return 0; // No card number found
|
|
|
|
if (timeIndex >= 0 && timeIndex != ti)
|
|
return -1; // Inconsistent
|
|
|
|
if (cardIndex >= 0 && cardIndex != ci)
|
|
return -1; // Inconsistent
|
|
|
|
timeIndex = ti;
|
|
cardIndex = ci;
|
|
dateIndex = di;
|
|
return 1;
|
|
}
|
|
|
|
bool csvparser::importPunches(const oEvent &oe, const wstring &file, vector<PunchInfo> &punches)
|
|
{
|
|
punches.clear();
|
|
/* fin.clear();
|
|
fin.open(file);
|
|
if (!fin.good())
|
|
return false;
|
|
*/
|
|
list< vector<wstring> > allLines;
|
|
parse(file, allLines);
|
|
list< vector<wstring> >::iterator it = allLines.begin();
|
|
|
|
|
|
//const size_t siz = 1024 * 1;
|
|
//char bf[siz];
|
|
//string bfs;
|
|
|
|
//fin.getline(bf, siz);
|
|
//std::getline(fin, bfs);
|
|
|
|
nimport=0;
|
|
int cardIndex = -1;
|
|
int timeIndex = -1;
|
|
int dateIndex = -1;
|
|
|
|
wstring processedTime, processedDate;
|
|
const wstring date = oe.getDate();
|
|
//vector<char *> sp;
|
|
while (++it != allLines.end()) {
|
|
const vector<wstring> &sp = *it;
|
|
//if (fin.fail())
|
|
// throw meosException("Reading file failed.");
|
|
|
|
//fin.getline(bf, siz);
|
|
//std::getline(fin, bfs);
|
|
/*sp.clear();
|
|
char *bf = (char *)bfs.c_str();
|
|
split(bf, sp);
|
|
*/
|
|
|
|
|
|
int ret = selectPunchIndex(date, sp, cardIndex, timeIndex, dateIndex,
|
|
processedTime, processedDate);
|
|
if (ret == -1)
|
|
return false; // Invalid file
|
|
if (ret > 0) {
|
|
int card = wtoi(sp[cardIndex]);
|
|
int time = oe.getRelativeTime(processedTime);
|
|
|
|
if (card>0) {
|
|
PunchInfo pi;
|
|
pi.card = card;
|
|
pi.time = time;
|
|
string pd(processedDate.begin(), processedDate.end());
|
|
strncpy_s(pi.date, sizeof(pi.date), pd.c_str(), 26);
|
|
pi.date[26] = 0;
|
|
punches.push_back(pi);
|
|
nimport++;
|
|
}
|
|
}
|
|
}
|
|
fin.close();
|
|
|
|
return true;
|
|
}
|
|
|
|
int analyseSITime(const oEvent &oe, const wchar_t *dow, const wchar_t *time)
|
|
{
|
|
int t=-1;
|
|
if (trim(dow).length()>0)
|
|
t = oe.getRelativeTime(time);
|
|
else
|
|
t = oe.getRelativeTimeFrom12Hour(time);
|
|
|
|
if (t<0)
|
|
t=0;
|
|
|
|
return t;
|
|
}
|
|
|
|
void csvparser::checkSIConfigHeader(const vector<wstring> &sp) {
|
|
siconfigmap.clear();
|
|
if (sp.size() < 200)
|
|
return;
|
|
|
|
//No;Read on;SIID;Start no;Clear CN;Clear DOW;Clear time;Clear_r CN;Clear_r DOW;Clear_r time;Check CN;Check DOW;Check time;Start CN;Start DOW;Start time;Start_r CN;Start_r DOW;Start_r time;Finish CN;Finish DOW;Finish time;Finish_r CN;Finish_r DOW;Finish_r time;Class;First name;Last name;Club;Country;Email;Date of birth;Sex;Phone;Street;ZIP;City;Hardware version;Software version;Battery date;Battery voltage;Clear count;Character set;SEL_FEEDBACK;No. of records;Record 1 CN;Record 1 DOW;Record 1 time;Record 2 CN;Record 2 DOW;Record 2 time;Record 3 CN;Record 3 DOW;Record 3 time;Record 4 CN;Record 4 DOW;Record 4 time;Record 5 CN;Record 5 DOW;Record 5 time;Record 6 CN;Record 6 DOW;Record 6 time;Record 7 CN;Record 7 DOW;Record 7 time;Record 8 CN;Record 8 DOW;Record 8 time;Record 9 CN;Record 9 DOW;Record 9 time;Record 10 CN;Record 10 DOW;Record 10 time;Record 11 CN;Record 11 DOW;Record 11 time;Record 12 CN;Record 12 DOW;Record 12 time;Record 13 CN;Record 13 DOW;Record 13 time;Record 14 CN;Record 14 DOW;Record 14 time;Record 15 CN;Record 15 DOW;Record 15 time;Record 16 CN;Record 16 DOW;Record 16 time;Record 17 CN;Record 17 DOW;Record 17 time;Record 18 CN;Record 18 DOW;Record 18 time;Record 19 CN;Record 19 DOW;Record 19 time;Record 20 CN;Record 20 DOW;Record 20 time;Record 21 CN;Record 21 DOW;Record 21 time;Record 22 CN;Record 22 DOW;Record 22 time;Record 23 CN;Record 23 DOW;Record 23 time;Record 24 CN;Record 24 DOW;Record 24 time;Record 25 CN;Record 25 DOW;Record 25 time;Record 26 CN;Record 26 DOW;Record 26 time;Record 27 CN;Record 27 DOW;Record 27 time;Record 28 CN;Record 28 DOW;Record 28 time;Record 29 CN;Record 29 DOW;Record 29 time;Record 30 CN;Record 30 DOW;Record 30 time;Record 31 CN;Record 31 DOW;Record 31 time;Record 32 CN;Record 32 DOW;Record 32 time;Record 33 CN;Record 33 DOW;Record 33 time;Record 34 CN;Record 34 DOW;Record 34 time;Record 35 CN;Record 35 DOW;Record 35 time;Record 36 CN;Record 36 DOW;Record 36 time;Record 37 CN;Record 37 DOW;Record 37 time;Record 38 CN;Record 38 DOW;Record 38 time;Record 39 CN;Record 39 DOW;Record 39 time;Record 40 CN;Record 40 DOW;Record 40 time;Record 41 CN;Record 41 DOW;Record 41 time;Record 42 CN;Record 42 DOW;Record 42 time;Record 43 CN;Record 43 DOW;Record 43 time;Record 44 CN;Record 44 DOW;Record 44 time;Record 45 CN;Record 45 DOW;Record 45 time;Record 46 CN;Record 46 DOW;Record 46 time;Record 47 CN;Record 47 DOW;Record 47 time;Record 48 CN;Record 48 DOW;Record 48 time;Record 49 CN;Record 49 DOW;Record 49 time;Record 50 CN;Record 50 DOW;Record 50 time;Record 51 CN;Record 51 DOW;Record 51 time;Record 52 CN;Record 52 DOW;Record 52 time;Record 53 CN;Record 53 DOW;Record 53 time;Record 54 CN;Record 54 DOW;Record 54 time;Record 55 CN;Record 55 DOW;Record 55 time;Record 56 CN;Record 56 DOW;Record 56 time;Record 57 CN;Record 57 DOW;Record 57 time;Record 58 CN;Record 58 DOW;Record 58 time;Record 59 CN;Record 59 DOW;Record 59 time;Record 60 CN;Record 60 DOW;Record 60 time;Record 61 CN;Record 61 DOW;Record 61 time;Record 62 CN;Record 62 DOW;Record 62 time;Record 63 CN;Record 63 DOW;Record 63 time;Record 64 CN;Record 64 DOW;Record 64 time;Record 65 CN;Record 65 DOW;Record 65 time;Record 66 CN;Record 66 DOW;Record 66 time;Record 67 CN;Record 67 DOW;Record 67 time;Record 68 CN;Record 68 DOW;Record 68 time;Record 69 CN;Record 69 DOW;Record 69 time;Record 70 CN;Record 70 DOW;Record 70 time;Record 71 CN;Record 71 DOW;Record 71 time;Record 72 CN;Record 72 DOW;Record 72 time;Record 73 CN;Record 73 DOW;Record 73 time;Record 74 CN;Record 74 DOW;Record 74 time;Record 75 CN;Record 75 DOW;Record 75 time;Record 76 CN;Record 76 DOW;Record 76 time;Record 77 CN;Record 77 DOW;Record 77 time;Record 78 CN;Record 78 DOW;Record 78 time;Record 79 CN;Record 79 DOW;Record 79 time;Record 80 CN;Record 80 DOW;Record 80 time;Record 81 CN;Record 81 DOW;Record 81 time;Record 82 CN;Record 82 DOW;Record 82 time;Record 83 CN;Record 83 DOW;Record 83 time;Record 84 CN;Record 84 DOW;Record 84 time;Record 85 CN;Record 85 DOW;Record 85 time;Record 86 CN;Record 86 DOW;Record 86 time;Record 87 CN;Record 87 DOW;Record 87 time;Record 88 CN;Record 88 DOW;Record 88 time;Record 89 CN;Record 89 DOW;Record 89 time;Record 90 CN;Record 90 DOW;Record 90 time;Record 91 CN;Record 91 DOW;Record 91 time;Record 92 CN;Record 92 DOW;Record 92 time;Record 93 CN;Record 93 DOW;Record 93 time;Record 94 CN;Record 94 DOW;Record 94 time;Record 95 CN;Record 95 DOW;Record 95 time;Record 96 CN;Record 96 DOW;Record 96 time;Record 97 CN;Record 97 DOW;Record 97 time;Record 98 CN;Record 98 DOW;Record 98 time;Record 99 CN;Record 99 DOW;Record 99 time;Record 100 CN;Record 100 DOW;Record 100 time;Record 101 CN;Record 101 DOW;Record 101 time;Record 102 CN;Record 102 DOW;Record 102 time;Record 103 CN;Record 103 DOW;Record 103 time;Record 104 CN;Record 104 DOW;Record 104 time;Record 105 CN;Record 105 DOW;Record 105 time;Record 106 CN;Record 106 DOW;Record 106 time;Record 107 CN;Record 107 DOW;Record 107 time;Record 108 CN;Record 108 DOW;Record 108 time;Record 109 CN;Record 109 DOW;Record 109 time;Record 110 CN;Record 110 DOW;Record 110 time;Record 111 CN;Record 111 DOW;Record 111 time;Record 112 CN;Record 112 DOW;Record 112 time;Record 113 CN;Record 113 DOW;Record 113 time;Record 114 CN;Record 114 DOW;Record 114 time;Record 115 CN;Record 115 DOW;Record 115 time;Record 116 CN;Record 116 DOW;Record 116 time;Record 117 CN;Record 117 DOW;Record 117 time;Record 118 CN;Record 118 DOW;Record 118 time;Record 119 CN;Record 119 DOW;Record 119 time;Record 120 CN;Record 120 DOW;Record 120 time;Record 121 CN;Record 121 DOW;Record 121 time;Record 122 CN;Record 122 DOW;Record 122 time;Record 123 CN;Record 123 DOW;Record 123 time;Record 124 CN;Record 124 DOW;Record 124 time;Record 125 CN;Record 125 DOW;Record 125 time;Record 126 CN;Record 126 DOW;Record 126 time;Record 127 CN;Record 127 DOW;Record 127 time;Record 128 CN;Record 128 DOW;Record 128 time;Record 129 CN;Record 129 DOW;Record 129 time;Record 130 CN;Record 130 DOW;Record 130 time;Record 131 CN;Record 131 DOW;Record 131 time;Record 132 CN;Record 132 DOW;Record 132 time;Record 133 CN;Record 133 DOW;Record 133 time;Record 134 CN;Record 134 DOW;Record 134 time;Record 135 CN;Record 135 DOW;Record 135 time;Record 136 CN;Record 136 DOW;Record 136 time;Record 137 CN;Record 137 DOW;Record 137 time;Record 138 CN;Record 138 DOW;Record 138 time;Record 139 CN;Record 139 DOW;Record 139 time;Record 140 CN;Record 140 DOW;Record 140 time;Record 141 CN;Record 141 DOW;Record 141 time;Record 142 CN;Record 142 DOW;Record 142 time;Record 143 CN;Record 143 DOW;Record 143 time;Record 144 CN;Record 144 DOW;Record 144 time;Record 145 CN;Record 145 DOW;Record 145 time;Record 146 CN;Record 146 DOW;Record 146 time;Record 147 CN;Record 147 DOW;Record 147 time;Record 148 CN;Record 148 DOW;Record 148 time;Record 149 CN;Record 149 DOW;Record 149 time;Record 150 CN;Record 150 DOW;Record 150 time;Record 151 CN;Record 151 DOW;Record 151 time;Record 152 CN;Record 152 DOW;Record 152 time;Record 153 CN;Record 153 DOW;Record 153 time;Record 154 CN;Record 154 DOW;Record 154 time;Record 155 CN;Record 155 DOW;Record 155 time;Record 156 CN;Record 156 DOW;Record 156 time;Record 157 CN;Record 157 DOW;Record 157 time;Record 158 CN;Record 158 DOW;Record 158 time;Record 159 CN;Record 159 DOW;Record 159 time;Record 160 CN;Record 160 DOW;Record 160 time;Record 161 CN;Record 161 DOW;Record 161 time;Record 162 CN;Record 162 DOW;Record 162 time;Record 163 CN;Record 163 DOW;Record 163 time;Record 164 CN;Record 164 DOW;Record 164 time;Record 165 CN;Record 165 DOW;Record 165 time;Record 166 CN;Record 166 DOW;Record 166 time;Record 167 CN;Record 167 DOW;Record 167 time;Record 168 CN;Record 168 DOW;Record 168 time;Record 169 CN;Record 169 DOW;Record 169 time;Record 170 CN;Record 170 DOW;Record 170 time;Record 171 CN;Record 171 DOW;Record 171 time;Record 172 CN;Record 172 DOW;Record 172 time;Record 173 CN;Record 173 DOW;Record 173 time;Record 174 CN;Record 174 DOW;Record 174 time;Record 175 CN;Record 175 DOW;Record 175 time;Record 176 CN;Record 176 DOW;Record 176 time;Record 177 CN;Record 177 DOW;Record 177 time;Record 178 CN;Record 178 DOW;Record 178 time;Record 179 CN;Record 179 DOW;Record 179 time;Record 180 CN;Record 180 DOW;Record 180 time;Record 181 CN;Record 181 DOW;Record 181 time;Record 182 CN;Record 182 DOW;Record 182 time;Record 183 CN;Record 183 DOW;Record 183 time;Record 184 CN;Record 184 DOW;Record 184 time;Record 185 CN;Record 185 DOW;Record 185 time;Record 186 CN;Record 186 DOW;Record 186 time;Record 187 CN;Record 187 DOW;Record 187 time;Record 188 CN;Record 188 DOW;Record 188 time;Record 189 CN;Record 189 DOW;Record 189 time;Record 190 CN;Record 190 DOW;Record 190 time;Record 191 CN;Record 191 DOW;Record 191 time;Record 192 CN;Record 192 DOW;Record 192 time;
|
|
wstring key;
|
|
for (size_t k = 0; k < sp.size(); k++) {
|
|
key = sp[k];
|
|
if (key == L"SIID" || key == L"SI-Card")
|
|
siconfigmap[sicSIID] = k;
|
|
else if (key == L"Check CN" || key == L"CHK_CN") {
|
|
siconfigmap[sicCheck] = k;
|
|
siconfigmap[sicCheckDOW] = k + 1;
|
|
siconfigmap[sicCheckTime] = k + 2;
|
|
}
|
|
else if (key == L"Check time") {
|
|
siconfigmap[sicCheckTime] = k;
|
|
}
|
|
else if (key == L"Start CN" || key == L"ST_CN") {
|
|
siconfigmap[sicStart] = k;
|
|
siconfigmap[sicStartDOW] = k + 1;
|
|
siconfigmap[sicStartTime] = k + 2;
|
|
}
|
|
else if (key == L"Start time") {
|
|
siconfigmap[sicStartTime] = k;
|
|
}
|
|
else if (key == L"Finish CN" || key == L"FI_CN") {
|
|
siconfigmap[sicFinish] = k;
|
|
siconfigmap[sicFinishDOW] = k + 1;
|
|
siconfigmap[sicFinishTime] = k + 2;
|
|
}
|
|
else if (key == L"Finish time") {
|
|
siconfigmap[sicFinishTime] = k;
|
|
}
|
|
else if (key == L"First name") {
|
|
siconfigmap[sicFirstName] = k;
|
|
}
|
|
else if (key == L"Last name") {
|
|
siconfigmap[sicLastName] = k;
|
|
}
|
|
else if (key == L"No. of records" || key == L"No. of punches") {
|
|
siconfigmap[sicNumPunch] = k;
|
|
}
|
|
else if (siconfigmap.count(sicRecordStart) == 0) {
|
|
size_t pos = key.find(L"Record 1");
|
|
if (pos == string::npos) {
|
|
pos = key.find(L"1.CN");
|
|
}
|
|
if (pos != string::npos) {
|
|
siconfigmap[sicRecordStart] = k;
|
|
if (siconfigmap.count(sicRecordStart) == 0 && k > 0)
|
|
siconfigmap[sicNumPunch] = k-1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!siconfigmap.empty()) {
|
|
|
|
}
|
|
}
|
|
|
|
const wchar_t *csvparser::getSIC(SIConfigFields sic, const vector<wstring> &sp) const {
|
|
map<SIConfigFields, int>::const_iterator res = siconfigmap.find(sic);
|
|
if (res == siconfigmap.end() || size_t(res->second) >= sp.size())
|
|
return L"";
|
|
|
|
return sp[res->second].c_str();
|
|
}
|
|
|
|
bool csvparser::checkSIConfigLine(const oEvent &oe, const vector<wstring> &sp, SICard &card) {
|
|
if (siconfigmap.empty())
|
|
return false;
|
|
|
|
int startIx = siconfigmap[sicRecordStart];
|
|
if (startIx == 0)
|
|
return false;
|
|
|
|
int cardNo = wtoi(getSIC(sicSIID, sp));
|
|
|
|
if (cardNo < 1000 || cardNo > 99999999)
|
|
return false;
|
|
|
|
int check = analyseSITime(oe, getSIC(sicCheckDOW, sp), getSIC(sicCheckTime, sp));
|
|
int start = analyseSITime(oe, getSIC(sicStartDOW, sp), getSIC(sicStartTime, sp));
|
|
int finish = analyseSITime(oe, getSIC(sicFinishDOW, sp), getSIC(sicFinishTime, sp));
|
|
int startCode = wtoi(getSIC(sicStart, sp));
|
|
int finishCode = wtoi(getSIC(sicFinish, sp));
|
|
int checkCode = wtoi(getSIC(sicCheck, sp));
|
|
wstring fname = getSIC(sicFirstName, sp);
|
|
wstring lname = getSIC(sicLastName, sp);
|
|
|
|
vector< pair<int, int> > punches;
|
|
int np = wtoi(getSIC(sicNumPunch, sp));
|
|
|
|
|
|
for (int k=0; k < np; k++) {
|
|
size_t ix = startIx + k*3;
|
|
if (ix+2 >= sp.size())
|
|
return false;
|
|
int code = wtoi(sp[ix]);
|
|
int time = analyseSITime(oe, sp[ix+1].c_str(), sp[ix+2].c_str());
|
|
if (code > 0) {
|
|
punches.push_back(make_pair(code, time));
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if ( (finish > 0 && finish != NOTIME) || punches.size() > 2) {
|
|
card.clear(0);
|
|
card.CardNumber = cardNo;
|
|
if (start > 0 && start != NOTIME) {
|
|
card.StartPunch.Code = startCode;
|
|
card.StartPunch.Time = start;
|
|
}
|
|
else {
|
|
card.StartPunch.Time = 0;
|
|
card.StartPunch.Code = -1;
|
|
}
|
|
|
|
if (finish > 0 && finish != NOTIME) {
|
|
card.FinishPunch.Code = finishCode;
|
|
card.FinishPunch.Time = finish;
|
|
}
|
|
else {
|
|
card.FinishPunch.Time = 0;
|
|
card.FinishPunch.Code = -1;
|
|
}
|
|
|
|
if (check > 0 && check != NOTIME) {
|
|
card.CheckPunch.Code = checkCode;
|
|
card.CheckPunch.Time = check;
|
|
}
|
|
else {
|
|
card.CheckPunch.Time = 0;
|
|
card.CheckPunch.Code = -1;
|
|
}
|
|
|
|
for (size_t k = 0; k<punches.size(); k++) {
|
|
card.Punch[k].Code = punches[k].first;
|
|
card.Punch[k].Time = punches[k].second;
|
|
}
|
|
|
|
wcsncpy_s(card.FirstName, fname.c_str(), 20);
|
|
card.FirstName[20] = 0;
|
|
wcsncpy_s(card.LastName, lname.c_str(), 20);
|
|
card.LastName[20] = 0;
|
|
card.nPunch = punches.size();
|
|
card.convertedTime = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool csvparser::checkSimanLine(const oEvent &oe, const vector<wstring> &sp, SICard &card) {
|
|
if (sp.size() <= 11)
|
|
return false;
|
|
|
|
int cardNo = wtoi(sp[1]);
|
|
|
|
if (wcschr(sp[1].c_str(), '-') != 0)
|
|
cardNo = 0; // Ensure not a date 2017-02-14
|
|
|
|
if (cardNo < 1000 || cardNo > 99999999)
|
|
return false;
|
|
|
|
int start = convertAbsoluteTimeMS(sp[5]);
|
|
int finish = convertAbsoluteTimeMS(sp[6]);
|
|
vector< pair<int, int> > punches;
|
|
for (size_t k=10; k + 1<sp.size(); k+=2) {
|
|
int code = wtoi(sp[k]);
|
|
int time = convertAbsoluteTimeMS(sp[k+1]);
|
|
if (code > 0) {
|
|
punches.push_back(make_pair(code, time));
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (punches.size() > 2) {
|
|
card.clear(0);
|
|
card.CardNumber = cardNo;
|
|
if (start > 0) {
|
|
card.StartPunch.Code = 0;
|
|
card.StartPunch.Time = start;
|
|
}
|
|
else {
|
|
card.StartPunch.Code = -1;
|
|
}
|
|
|
|
if (finish > 0) {
|
|
card.FinishPunch.Code = 0;
|
|
card.FinishPunch.Time = finish;
|
|
}
|
|
else {
|
|
card.FinishPunch.Code = -1;
|
|
}
|
|
|
|
for (size_t k = 0; k<punches.size(); k++) {
|
|
card.Punch[k].Code = punches[k].first;
|
|
card.Punch[k].Time = punches[k].second;
|
|
}
|
|
card.nPunch = punches.size();
|
|
card.convertedTime = false;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool csvparser::importCards(const oEvent &oe, const wstring &file, vector<SICard> &cards)
|
|
{
|
|
cards.clear();
|
|
list< vector<wstring> > allLines;
|
|
parse(file, allLines);
|
|
//vector<wchar_t *> sp;
|
|
list< vector<wstring> >::iterator it = allLines.begin();
|
|
if (it == allLines.end())
|
|
return false;
|
|
// fin.clear();
|
|
// fin.open(file);
|
|
|
|
// if (!fin.good())
|
|
// return false;
|
|
|
|
//[1024*16];
|
|
//int s = 1024*256;
|
|
//vector<char> bbf(s);
|
|
//char *bf = &bbf[0];
|
|
//fin.getline(bf, s);
|
|
//vector<char *> sp;
|
|
//split(bf, sp);
|
|
checkSIConfigHeader(*it);
|
|
nimport=0;
|
|
|
|
while (++it != allLines.end()) {
|
|
//fin.getline(bf, s);
|
|
//split(bf, sp);
|
|
const vector<wstring> &sp = *it;
|
|
|
|
SICard card;
|
|
|
|
if (checkSimanLine(oe, sp, card)) {
|
|
cards.push_back(card);
|
|
nimport++;
|
|
}
|
|
else if (checkSIConfigLine(oe,sp, card)) {
|
|
cards.push_back(card);
|
|
nimport++;
|
|
}
|
|
else if (sp.size()>28) {
|
|
int no = wtoi(sp[0]);
|
|
card.CardNumber = wtoi(sp[2]);
|
|
wcsncpy_s(card.FirstName, sp[5].c_str(), 20);
|
|
wcsncpy_s(card.LastName, sp[6].c_str(), 20);
|
|
wcsncpy_s(card.Club, sp[7].c_str(), 40);
|
|
|
|
if (trim(sp[21]).length()>1) {
|
|
card.CheckPunch.Code = wtoi(sp[19]);
|
|
card.CheckPunch.Time = analyseSITime(oe, sp[20].c_str(), sp[21].c_str());
|
|
}
|
|
else {
|
|
card.CheckPunch.Code = -1;
|
|
card.CheckPunch.Time = 0;
|
|
}
|
|
|
|
if (trim(sp[24]).length()>1) {
|
|
card.StartPunch.Code = wtoi(sp[22]);
|
|
card.StartPunch.Time = analyseSITime(oe, sp[23].c_str(), sp[24].c_str());
|
|
}
|
|
else {
|
|
card.StartPunch.Code = -1;
|
|
card.StartPunch.Time = 0;
|
|
}
|
|
|
|
if (trim(sp[27]).length()>1) {
|
|
card.FinishPunch.Code = wtoi(sp[25]);
|
|
card.FinishPunch.Time = analyseSITime(oe, sp[26].c_str(), sp[27].c_str());
|
|
}
|
|
else {
|
|
card.FinishPunch.Code = -1;
|
|
card.FinishPunch.Time = 0;
|
|
}
|
|
|
|
card.nPunch = wtoi(sp[28]);
|
|
if (no>0 && card.CardNumber>0 && card.nPunch>0 && card.nPunch < 200) {
|
|
if (sp.size()>28+3*card.nPunch) {
|
|
for (unsigned k=0;k<card.nPunch;k++) {
|
|
card.Punch[k].Code = wtoi(sp[29+k*3]);
|
|
card.Punch[k].Time = analyseSITime(oe, sp[30+k*3].c_str(), sp[31+k*3].c_str());
|
|
}
|
|
card.PunchOnly = false;
|
|
nimport++;
|
|
card.convertedTime = true;
|
|
cards.push_back(card);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fin.close();
|
|
|
|
return true;
|
|
}
|
|
/*
|
|
void csvparser::parse(const wstring &file, list< vector<string> > &data) {
|
|
data.clear();
|
|
|
|
fin.open(file);
|
|
const size_t bf_size = 4096;
|
|
char bf[4096];
|
|
if (!fin.good())
|
|
throw meosException("Failed to read file");
|
|
|
|
bool isUTF8 = false;
|
|
bool isUnicode = false;
|
|
bool firstLine = true;
|
|
wstring wideString;
|
|
vector<char *> sp;
|
|
|
|
while(!fin.eof()) {
|
|
memset(bf, 0, bf_size);
|
|
fin.getline(bf, bf_size);
|
|
if (firstLine) {
|
|
if (bf[0] == -17 && bf[1] == -69 && bf[2] == -65) {
|
|
isUTF8 = true;
|
|
for (int k = 0; k <bf_size-3; k++) {
|
|
bf[k] = bf[k+3];
|
|
}
|
|
}
|
|
else if (bf[0] == -1 && bf[1] == -2) {
|
|
isUnicode = true;
|
|
for (int k = 0; k < bf_size-2; k++) {
|
|
bf[k] = bf[k+2];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isUnicode) {
|
|
int len = 0;
|
|
if (bf[len] == 0 && bf[len+1] != 0)
|
|
len++;
|
|
wideString.clear();
|
|
while ((bf[len] != 0 || bf[len+1] != 0) && len < (bf_size -2)) {
|
|
wchar_t &c = *(wchar_t *)&bf[len];
|
|
wideString.push_back(c);
|
|
len+=2;
|
|
}
|
|
if (wideString.length() > 0) {
|
|
int untranslated;
|
|
WideCharToMultiByte(CP_ACP, 0, wideString.c_str(), wideString.length(), bf, bf_size-2, "?", &untranslated);
|
|
bf[wideString.length()-1] = 0;
|
|
}
|
|
else {
|
|
bf[0] = 0;
|
|
}
|
|
}
|
|
|
|
firstLine = false;
|
|
split(bf, sp);
|
|
|
|
if (!sp.empty()) {
|
|
data.push_back(vector<string>());
|
|
data.back().resize(sp.size());
|
|
for (size_t k = 0; k < sp.size(); k++) {
|
|
data.back()[k] = sp[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isUTF8) {
|
|
list< vector<string> > dataCopy;
|
|
for (list< vector<string> >::iterator it = data.begin(); it != data.end(); ++it) {
|
|
vector<string> &de = *it;
|
|
dataCopy.push_back(vector<string>());
|
|
vector<string> &out = dataCopy.back();
|
|
|
|
wchar_t buff[buff_pre_alloc];
|
|
char outstr[buff_pre_alloc];
|
|
for (size_t k = 0; k < de.size(); k++) {
|
|
if (de[k].empty()) {
|
|
out.push_back("");
|
|
continue;
|
|
}
|
|
int len = de[k].size();
|
|
len = min(min(len+1, 1024), buff_pre_alloc-10);
|
|
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0, de[k].c_str(), len, buff, buff_pre_alloc);
|
|
buff[wlen-1] = 0;
|
|
|
|
BOOL untranslated = false;
|
|
WideCharToMultiByte(CP_ACP, 0, buff, wlen, outstr, buff_pre_alloc, "?", &untranslated);
|
|
outstr[wlen-1] = 0;
|
|
out.push_back(outstr);
|
|
}
|
|
}
|
|
data.swap(dataCopy);
|
|
}
|
|
|
|
fin.close();
|
|
}*/
|
|
|
|
|
|
void csvparser::parseUnicode(const wstring &file, list< vector<wstring> > &data) {
|
|
fin.open(file, ifstream::in | ifstream::binary);
|
|
fin.seekg(0, ios_base::end);
|
|
size_t len = int(fin.tellg())-2;
|
|
if (len == 0)
|
|
return;
|
|
fin.seekg(2); // BOM
|
|
assert(len % 2 == 0);
|
|
vector<wchar_t> bf(len / 2 + 1);
|
|
fin.read((char *)&bf[0], len);
|
|
vector<wstring> rows;
|
|
int spp = 0;
|
|
for (size_t k = 0; k < len / 2; k++) {
|
|
if (bf[spp] == '\r')
|
|
spp++;
|
|
if (bf[k] == '\n') {
|
|
bf[k] = 0;
|
|
if (k > 0 && bf[k - 1] == '\r')
|
|
bf[k - 1] = 0;
|
|
wstring r = &bf[spp];
|
|
spp = k + 1;
|
|
rows.push_back(r);
|
|
}
|
|
}
|
|
if (size_t(spp + 1) < len / 2) {
|
|
wstring r = &bf[spp];
|
|
rows.push_back(r);
|
|
}
|
|
vector<wchar_t *> sp;
|
|
|
|
for (size_t k = 0; k < rows.size(); k++) {
|
|
split(const_cast<wchar_t*>(rows[k].c_str()), sp);
|
|
|
|
if (!sp.empty()) {
|
|
data.push_back(vector<wstring>());
|
|
data.back().resize(sp.size());
|
|
for (size_t k = 0; k < sp.size(); k++) {
|
|
data.back()[k] = sp[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void csvparser::parse(const wstring &file, list< vector<wstring> > &data) {
|
|
data.clear();
|
|
|
|
fin.open(file);
|
|
|
|
fin.seekg(0, ios_base::end);
|
|
auto len = fin.tellg();
|
|
fin.seekg(0);
|
|
|
|
string rbf;
|
|
|
|
if (!fin.good())
|
|
throw meosException("Failed to read file");
|
|
|
|
bool isUTF8 = false;
|
|
bool firstLine = true;
|
|
vector<wchar_t *> sp;
|
|
vector<wchar_t> wbf_a;
|
|
wbf_a.resize(size_t(len));
|
|
wchar_t *wbf = &wbf_a[0];
|
|
wstring w;
|
|
while(std::getline(fin, rbf)) {
|
|
const char *bf = rbf.c_str();
|
|
if (firstLine) {
|
|
if (rbf.length() > 3 && rbf[0] == -17 && rbf[1] == -69 && rbf[2] == -65) {
|
|
isUTF8 = true;
|
|
bf += 3;
|
|
}
|
|
else if (bf[0] == -1 && bf[1] == -2) {
|
|
fin.close();
|
|
vector<wchar_t>().swap(wbf_a);
|
|
parseUnicode(file, data);
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (isUTF8) {
|
|
int len = strlen(bf);
|
|
int wlen = MultiByteToWideChar(CP_UTF8, 0, bf, len, wbf, buff_pre_alloc);
|
|
wbf[wlen] = 0;
|
|
split(&wbf[0], sp);
|
|
}
|
|
else {
|
|
w = gdi_main->recodeToWide(bf);
|
|
wchar_t *wbfL = const_cast<wchar_t *>(w.c_str());
|
|
split(wbfL, sp);
|
|
}
|
|
firstLine = false;
|
|
|
|
if (!sp.empty()) {
|
|
data.push_back(vector<wstring>());
|
|
data.back().resize(sp.size());
|
|
for (size_t k = 0; k < sp.size(); k++) {
|
|
data.back()[k] = sp[k];
|
|
}
|
|
}
|
|
}
|
|
|
|
fin.close();
|
|
}
|
|
|
|
void csvparser::importTeamLineup(const wstring &file,
|
|
const map<wstring, int> &classNameToNumber,
|
|
vector<TeamLineup> &teams) {
|
|
list< vector<wstring> > data;
|
|
parse(file, data);
|
|
teams.clear();
|
|
teams.reserve(data.size()/3);
|
|
int membersToRead = 0;
|
|
int lineNo = 1;
|
|
while (!data.empty()) {
|
|
vector<wstring> &line = data.front();
|
|
if (!line.empty()) {
|
|
if (membersToRead == 0) {
|
|
if (line.size() < 2 || line.size() > 3)
|
|
throw meosException(L"Ogiltigt lag på rad X.#" + itow(lineNo) + L": " + line[0]);
|
|
const wstring cls = trim(line[0]);
|
|
map<wstring, int>::const_iterator res = classNameToNumber.find(cls);
|
|
if (res == classNameToNumber.end())
|
|
throw meosException(L"Okänd klass på rad X.#" + itow(lineNo) + L": " + cls);
|
|
if (res->second <= 1)
|
|
throw meosException(L"Klassen X är individuell.#" + cls);
|
|
|
|
membersToRead = res->second;
|
|
teams.push_back(TeamLineup());
|
|
teams.back().teamClass = cls;
|
|
teams.back().teamName = trim(line[1]);
|
|
if (line.size() >= 3)
|
|
teams.back().teamClub = trim(line[2]);
|
|
}
|
|
else {
|
|
membersToRead--;
|
|
teams.back().members.push_back(TeamLineup::TeamMember());
|
|
TeamLineup::TeamMember &member = teams.back().members.back();
|
|
member.name = trim(line[0]);
|
|
if (line.size()>1)
|
|
member.cardNo = _wtoi(line[1].c_str());
|
|
else
|
|
member.cardNo = 0;
|
|
|
|
if (line.size()>2)
|
|
member.club = trim(line[2]);
|
|
|
|
if (line.size() > 3)
|
|
member.course = trim(line[3]);
|
|
|
|
if (line.size() > 4)
|
|
member.cls = trim(line[4]);
|
|
}
|
|
}
|
|
else if (membersToRead>0) {
|
|
membersToRead--;
|
|
teams.back().members.push_back(TeamLineup::TeamMember());
|
|
}
|
|
lineNo++;
|
|
data.pop_front();
|
|
}
|
|
}
|