/************************************************************************ MeOS - Orienteering Software Copyright (C) 2009-2017 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 ************************************************************************/ // 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 ////////////////////////////////////////////////////////////////////// // 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 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 > allLines; parse(file, allLines); //vector sp; list< vector >::iterator it = allLines.begin(); // Skip first line while (++it != allLines.end()) { //fin.getline(bf, 1024); //split(bf, sp); const vector &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)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 > allLines; parse(file, allLines); list< vector >::iterator it = allLines.begin(); // Skip first line nimport=0; while (++it != allLines.end()) { //fin.getline(bf, 1024); //split(bf, sp); const vector &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() == 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() != 0) event.getClass(pr->getClassId())->setCourse(course); else pr->setCourseId(course->getId()); } } } } if (pr) pr->synchronize(); } } fin.close(); return true; } bool csvparser::openOutput(const wstring &filename) { checkWriteAccess(filename); fout.open(filename); if (fout.bad()) return false; return true; } bool csvparser::OutputRow(const string &row) { fout << row << endl; return true; } bool csvparser::OutputRow(vector &out) { int size=out.size(); for(int i=0;i0) 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 &split_vector) { split_vector.clear(); int len=strlen(line); bool cite=false; for(int m=0;m &split_vector) { split_vector.clear(); int len=wcslen(line); bool cite=false; for(int m=0;m > allLines; parse(file, allLines); list< vector >::iterator it = allLines.begin(); while(it != allLines.end()) { const vector &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 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= 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; igetNumStages(); 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 > allLines; parse(file, allLines); list< vector >::iterator it = allLines.begin(); nimport=0; while (++it != allLines.end()) { const vector &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 &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 &punches) { punches.clear(); /* fin.clear(); fin.open(file); if (!fin.good()) return false; */ list< vector > allLines; parse(file, allLines); list< vector >::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 sp; while (++it != allLines.end()) { const vector &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 &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 &sp) const { map::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 &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 > 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 &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 > punches; for (size_t k=10; k + 1 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 &cards) { cards.clear(); list< vector > allLines; parse(file, allLines); //vector sp; list< vector >::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 bbf(s); //char *bf = &bbf[0]; //fin.getline(bf, s); //vector sp; //split(bf, sp); checkSIConfigHeader(*it); nimport=0; while (++it != allLines.end()) { //fin.getline(bf, s); //split(bf, sp); const vector &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 > &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 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 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()); data.back().resize(sp.size()); for (size_t k = 0; k < sp.size(); k++) { data.back()[k] = sp[k]; } } } if (isUTF8) { list< vector > dataCopy; for (list< vector >::iterator it = data.begin(); it != data.end(); ++it) { vector &de = *it; dataCopy.push_back(vector()); vector &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::parse(const wstring &file, list< vector > &data) { data.clear(); fin.open(file); // const size_t bf_size = 8192; string rbf; if (!fin.good()) throw meosException("Failed to read file"); bool isUTF8 = false; bool isUnicode = false; bool firstLine = true; vector sp; wchar_t wbf[buff_pre_alloc]; 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) { isUnicode = true; bf += 2; } } if (isUnicode) { int len = 0; if (bf[len] == 0 && bf[len+1] != 0) len++; split((wchar_t*)&bf[len], sp); } else if (isUTF8) { int len = strlen(bf); int wlen = MultiByteToWideChar(CP_UTF8, 0, bf, len, wbf, buff_pre_alloc); wbf[wlen] = 0; split(wbf, sp); } else { w = gdi_main->recodeToWide(bf); wchar_t *wbf = const_cast(w.c_str()); split(wbf, sp); } firstLine = false; if (!sp.empty()) { data.push_back(vector()); 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 &classNameToNumber, vector &teams) { list< vector > data; parse(file, data); teams.clear(); teams.reserve(data.size()/3); int membersToRead = 0; int lineNo = 1; while (!data.empty()) { vector &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::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(); } }