From 6e5effe43ebb051a0ab9ab2f05cc6b10bf078b6c Mon Sep 17 00:00:00 2001 From: matthiasmiller Date: Wed, 25 Jan 2006 01:10:49 +0000 Subject: [PATCH] work on big-endian support, including automated tests git-svn-id: https://svn.code.sf.net/p/keepassx/code/trunk@22 b624d157-de02-0410-bad0-e51aec6abb33 --- src/Database.h | 4 +- src/PwManager.cpp | 348 +++++++++++++++++++++++++++++++++++++--------- src/PwManager.h | 4 + src/main.cpp | 5 + 4 files changed, 293 insertions(+), 68 deletions(-) diff --git a/src/Database.h b/src/Database.h index db4f25b..5ccb4b6 100644 --- a/src/Database.h +++ b/src/Database.h @@ -45,7 +45,7 @@ QDateTime LastAccess; QDateTime Expire; Q_UINT8 *pBinaryData; Q_UINT32 BinaryDataLength; -Q_UINT32 PasswordLength; +/*Q_UINT32 PasswordLength;*/ bool ReadEntryField(Q_UINT16 FieldType, Q_UINT32 FieldSize, Q_UINT8 *pData); bool operator==(const CEntry&) const; }; @@ -57,7 +57,7 @@ CGroup(); ~CGroup(); Q_UINT32 ID; Q_UINT32 ImageID; -Q_UINT32 NumEntries; +/*Q_UINT32 NumEntries;*/ QString Name; QDateTime Creation; QDateTime LastMod; diff --git a/src/PwManager.cpp b/src/PwManager.cpp index 3189b6e..5e6c117 100755 --- a/src/PwManager.cpp +++ b/src/PwManager.cpp @@ -608,156 +608,156 @@ int pos=DB_HEADER_SIZE; // Skip the header, it will be written later for(int i=0; i < Groups.size(); i++){ FieldType = 0x0001; FieldSize = 4; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; - memcpy(buffer+pos, &Groups[i].ID, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; + memcpyToLEnd32(buffer+pos, &Groups[i].ID); pos += 4; FieldType = 0x0002; FieldSize = Groups[i].Name.utf8().length() + 1; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Groups[i].Name.utf8(),FieldSize); pos += FieldSize; FieldType = 0x0003; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Groups[i].Creation,(unsigned char*)buffer+pos); pos += 5; FieldType = 0x0004; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Groups[i].LastMod,(unsigned char*)buffer+pos);pos += 5; FieldType = 0x0005; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Groups[i].LastAccess,(unsigned char*)buffer+pos);pos += 5; FieldType = 0x0006; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Groups[i].Expire,(unsigned char*)buffer+pos);pos += 5; FieldType = 0x0007; FieldSize = 4; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; - memcpy(buffer+pos, &Groups[i].ImageID, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; + memcpyToLEnd32(buffer+pos, &Groups[i].ImageID); pos += 4; FieldType = 0x0008; FieldSize = 2; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; - memcpy(buffer+pos, &Groups[i].Level, 2); pos += 2; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; + memcpyToLEnd16(buffer+pos, &Groups[i].Level); pos += 2; FieldType = 0x0009; FieldSize = 4; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; - memcpy(buffer+pos, &Groups[i].Flags, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; + memcpyToLEnd32(buffer+pos, &Groups[i].Flags); pos += 4; FieldType = 0xFFFF; FieldSize = 0; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; } for(int i = 0; i < Entries.size(); i++){ FieldType = 0x0001; FieldSize = 16; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, &Entries[i].ID, 16); pos += 16; FieldType = 0x0002; FieldSize = 4; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; - memcpy(buffer+pos, &Entries[i].GroupID, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; + memcpyToLEnd32(buffer+pos, &Entries[i].GroupID); pos += 4; FieldType = 0x0003; FieldSize = 4; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; - memcpy(buffer+pos, &Entries[i].ImageID, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; + memcpyToLEnd32(buffer+pos, &Entries[i].ImageID); pos += 4; FieldType = 0x0004; FieldSize = Entries[i].Title.utf8().length() + 1; // Add terminating NULL character space - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Entries[i].Title.utf8(),FieldSize); pos += FieldSize; FieldType = 0x0005; FieldSize = Entries[i].URL.utf8().length() + 1; // Add terminating NULL character space - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Entries[i].URL.utf8(),FieldSize); pos += FieldSize; FieldType = 0x0006; FieldSize = Entries[i].UserName.utf8().length() + 1; // Add terminating NULL character space - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Entries[i].UserName.utf8(),FieldSize); pos += FieldSize; FieldType = 0x0007; FieldSize = Entries[i].Password.length() + 1; // Add terminating NULL character space - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Entries[i].Password.getString(),FieldSize); pos += FieldSize; Entries[i].Password.delRef(); FieldType = 0x0008; FieldSize = Entries[i].Additional.utf8().length() + 1; // Add terminating NULL character space - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Entries[i].Additional.utf8(),FieldSize); pos += FieldSize; FieldType = 0x0009; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Entries[i].Creation,(unsigned char*)buffer+pos); pos+=5; FieldType = 0x000A; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Entries[i].LastMod,(unsigned char*)buffer+pos); pos+=5; FieldType = 0x000B; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Entries[i].LastAccess,(unsigned char*)buffer+pos); pos+=5; FieldType = 0x000C; FieldSize = 5; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; dateToPackedStruct5(Entries[i].Expire,(unsigned char*)buffer+pos); pos+=5; FieldType = 0x000D; FieldSize = Entries[i].BinaryDesc.utf8().length() + 1; // Add terminating NULL character space - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; memcpy(buffer+pos, Entries[i].BinaryDesc.utf8(),FieldSize); pos += FieldSize; FieldType = 0x000E; FieldSize = Entries[i].BinaryDataLength; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; if((Entries[i].pBinaryData != NULL) && (FieldSize != 0)) memcpy(buffer+pos, Entries[i].pBinaryData, FieldSize); pos += FieldSize; FieldType = 0xFFFF; FieldSize = 0; - memcpy(buffer+pos, &FieldType, 2); pos += 2; - memcpy(buffer+pos, &FieldSize, 4); pos += 4; + memcpyToLEnd16(buffer+pos, &FieldType); pos += 2; + memcpyToLEnd32(buffer+pos, &FieldSize); pos += 4; } sha256_context context; sha256_starts(&context); sha256_update(&context,(unsigned char*)buffer+DB_HEADER_SIZE, pos - DB_HEADER_SIZE); sha256_finish(&context,(unsigned char*)ContentsHash); -memcpy(buffer,&Signature1,4); -memcpy(buffer+4,&Signature2,4); -memcpy(buffer+8,&Flags,4); -memcpy(buffer+12,&Version,4); +memcpyToLEnd32(buffer,&Signature1); +memcpyToLEnd32(buffer+4,&Signature2); +memcpyToLEnd32(buffer+8,&Flags); +memcpyToLEnd32(buffer+12,&Version); memcpy(buffer+16,FinalRandomSeed,16); memcpy(buffer+32,EncryptionIV,16); -memcpy(buffer+48,&NumGroups,4); -memcpy(buffer+52,&NumEntries,4); +memcpyToLEnd32(buffer+48,&NumGroups); +memcpyToLEnd32(buffer+52,&NumEntries); memcpy(buffer+56,ContentsHash,32); memcpy(buffer+88,TrafoRandomSeed,32); -memcpy(buffer+120,&KeyEncRounds,4); +memcpyToLEnd32(buffer+120,&KeyEncRounds); transformKey(MasterKey,TransformedMasterKey,TrafoRandomSeed,KeyEncRounds); Q_UINT8 FinalKey[32]; sha256_starts(&context); @@ -787,7 +787,6 @@ EncryptedPartSize = (unsigned long)twofish.padEncrypt((Q_UINT8*)buffer+DB_HEADER pos - DB_HEADER_SIZE, (Q_UINT8*)buffer+DB_HEADER_SIZE); } - if((EncryptedPartSize > 2147483446) || (EncryptedPartSize == 0)){ //TODO:ERR_MSG delete [] buffer; @@ -1041,6 +1040,28 @@ else memcpy(dst,src,2); } +void memcpyToLEnd32(char* dst,Q_UINT32* src){ + +if(QSysInfo::ByteOrder==QSysInfo::BigEndian){ + memcpy(dst+0,((char*)src)+3,1); + memcpy(dst+1,((char*)src)+2,1); + memcpy(dst+2,((char*)src)+1,1); + memcpy(dst+3,((char*)src)+0,1); +} +else + memcpy(dst,src,4); +} + +void memcpyToLEnd16(char* dst,Q_UINT16* src){ + +if(QSysInfo::ByteOrder==QSysInfo::BigEndian){ + memcpy(dst+0,((char*)src)+1,1); + memcpy(dst+1,((char*)src)+0,1); +} +else + memcpy(dst,src,2); +} + const QDateTime Date_Never(QDate(2999,12,28),QTime(23,59,59)); QDateTime dateFromPackedStruct5(const unsigned char* pBytes){ @@ -1053,7 +1074,7 @@ int d = (dw3 >> 1) & 0x0000001F; int h = ((dw3 & 0x00000001) << 4) | (dw4 >> 4); int min = ((dw4 & 0x0000000F) << 2) | (dw5 >> 6); int s = dw5 & 0x0000003F; -return QDateTime(QDate(y,mon,d),QTime(h,min)); +return QDateTime(QDate(y,mon,d),QTime(h,min,s)); } @@ -1063,4 +1084,199 @@ pBytes[1] = (Q_UINT8)((((Q_UINT32)d.date().year() & 0x0000003F) << 2) | (((Q_UIN pBytes[2] = (Q_UINT8)((((Q_UINT32)d.date().month() & 0x00000003) << 6) | (((Q_UINT32)d.date().day() & 0x0000001F) << 1) | (((Q_UINT32)d.time().hour() >> 4) & 0x00000001)); pBytes[3] = (Q_UINT8)((((Q_UINT32)d.time().hour() & 0x0000000F) << 4) | (((Q_UINT32)d.time().minute() >> 2) & 0x0000000F)); pBytes[4] = (Q_UINT8)((((Q_UINT32)d.time().minute() & 0x00000003) << 6) | ((Q_UINT32)d.time().second() & 0x0000003F)); -} \ No newline at end of file +} + + +class KPTestResults{ +public: + KPTestResults(){passed=failed=0;} + int passed, failed; +}; + +/* assumes context of failed/passed variables */ +#define kp_assert(results, x) \ + do {\ + if (x){\ + (results).passed++;\ + }else{\ + (results).failed++;\ + cout << __FILE__ << ":" << __LINE__ << ": assert failed: " << #x << endl; \ + }\ + } while(0) + +void testDateConv(KPTestResults& results, const QDateTime& d){ + unsigned char binDate[5]; + dateToPackedStruct5(d, binDate); + kp_assert(results, d.toTime_t() == dateFromPackedStruct5(binDate).toTime_t()); +} + +void assertGroupsEq(KPTestResults& results, CGroup* left, CGroup* right){ + unsigned long size = 0; + + kp_assert(results, left->ID == right->ID); + size += sizeof(left->ID); + + kp_assert(results, left->ImageID == right->ImageID); + size += sizeof(left->ImageID); + + kp_assert(results, left->Name == right->Name); + size += sizeof(left->Name); + + kp_assert(results, left->Creation.toTime_t() == right->Creation.toTime_t()); + size += sizeof(left->Creation); + + kp_assert(results, left->LastMod.toTime_t() == right->LastMod.toTime_t()); + size += sizeof(left->LastMod); + + kp_assert(results, left->LastAccess.toTime_t() == right->LastAccess.toTime_t()); + size += sizeof(left->LastAccess); + + kp_assert(results, left->Expire.toTime_t() == right->Expire.toTime_t()); + size += sizeof(left->Expire); + + kp_assert(results, left->Level == right->Level); + size += sizeof(left->Level); + + kp_assert(results, left->Flags == right->Flags); + size += sizeof(left->Flags); + + /* ignore expansion */ + size += sizeof(left->UI_ItemIsExpanded); + + /* make sure that all members were checked */ + + /* CGroup is padded with two additional bytes */ + kp_assert(results, size + 2 == sizeof(CGroup)); + kp_assert(results, 40 == sizeof(CGroup)); +} + +void assertEntriesEq(KPTestResults& results, CEntry* left, CEntry* right){ + unsigned long size = 0; + + kp_assert(results, memcmp(left->ID, right->ID, sizeof(left->ID)) == 0); + size += sizeof(left->ID); + + kp_assert(results, left->sID == right->sID); + size += sizeof(left->sID); + + kp_assert(results, left->GroupID == right->GroupID); + size += sizeof(left->GroupID); + + kp_assert(results, left->ImageID == right->ImageID); + size += sizeof(left->ImageID); + + kp_assert(results, left->Title == right->Title); + size += sizeof(left->Title); + + kp_assert(results, left->URL == right->URL); + size += sizeof(left->URL); + + kp_assert(results, left->UserName == right->UserName); + size += sizeof(left->UserName); + + kp_assert(results, left->Password.getString() == right->Password.getString()); + size += sizeof(left->Password); + + kp_assert(results, left->Additional == right->Additional); + size += sizeof(left->Additional); + + kp_assert(results, left->BinaryDesc == right->BinaryDesc); + size += sizeof(left->BinaryDesc); + + kp_assert(results, left->Creation.toTime_t() == right->Creation.toTime_t()); + size += sizeof(left->Creation); + + kp_assert(results, left->LastMod.toTime_t() == right->LastMod.toTime_t()); + size += sizeof(left->LastMod); + + kp_assert(results, left->LastAccess.toTime_t() == right->LastAccess.toTime_t()); + size += sizeof(left->LastAccess); + + kp_assert(results, left->Expire.toTime_t() == right->Expire.toTime_t()); + size += sizeof(left->Expire); + + kp_assert(results, left->BinaryDataLength == right->BinaryDataLength); + kp_assert(results, (left->pBinaryData == NULL && right->pBinaryData == NULL) || + memcmp(left->pBinaryData, right->pBinaryData, left->BinaryDataLength) == 0); + size += sizeof(left->pBinaryData); + size += sizeof(left->BinaryDataLength); + + kp_assert(results, size == sizeof(CEntry)); +} + +void assertDatabasesEq(KPTestResults& results, PwDatabase* left, PwDatabase* right){ + /* check groups */ + kp_assert(results, left->Groups.size() == right->Groups.size()); + int numGroups = min(left->Groups.size(), right->Groups.size()); + for(int i=0;iGroups[i], &right->Groups[i]); + + /* check entries */ + kp_assert(results, left->Entries.size() == right->Entries.size()); + int numEntries = min(left->Entries.size(), right->Entries.size()); + for(int j=0;jEntries[j], &right->Entries[j]); +} + +bool testDatabase(){ + KPTestResults results; + + /* test the date/time serialization */ + QDateTime now = QDateTime::currentDateTime(); + testDateConv(results, now); + testDateConv(results, Date_Never); + + QString dbPassword("keepass-db-test"); + const QString dbPath("/tmp/keepass-db-test"); + + /* create a test database */ + PwDatabase database; + kp_assert(results, database.CalcMasterKeyByPassword(dbPassword)); + database.filename = dbPath; + database.CryptoAlgorithmus = ALGO_TWOFISH; + + CGroup* main = database.addGroup(NULL); + CGroup* child = database.addGroup(main); + child->Name = ""; + + QString entry1pw("password"); + CEntry* entry1 = database.addEntry(); + database.moveEntry(entry1, main); + entry1->Title = "title"; + entry1->URL = "http://keepass.berlios.de/"; + entry1->UserName = "username"; + entry1->Password.setString(entry1pw); + entry1->Additional = "additional"; + entry1->BinaryDesc = "binarydesc"; + + QString entry2pw("password"); + CEntry* entry2 = database.addEntry(); + database.moveEntry(entry2, child); + entry2->Title = "TITLE"; + entry2->URL = "http://keepass.berlios.de/"; + entry2->UserName = "USERNAME"; + entry2->Password.setString(entry2pw); + entry2->Additional = "ADDITIONAL"; + entry2->BinaryDesc = "BINARYDESC"; + + /* save the database */ + kp_assert(results, database.saveDatabase()); + + /* reload the database */ + PwDatabase cloneDatabase; + kp_assert(results, cloneDatabase.CalcMasterKeyByPassword(dbPassword)); + QString err; + bool loadedDB = cloneDatabase.loadDatabase(dbPath, err); + if (!loadedDB){ + kp_assert(results, loadedDB); + cout << err.ascii() << endl; + } + + assertDatabasesEq(results, &database, &cloneDatabase); + + /* compare the databases */ + cout << results.passed << "/" << (results.passed+results.failed) << " ok" << endl; + return results.failed == 0; +} + + diff --git a/src/PwManager.h b/src/PwManager.h index 4bb672f..1137187 100755 --- a/src/PwManager.h +++ b/src/PwManager.h @@ -88,7 +88,11 @@ private: extern const QDateTime Date_Never; void memcpyFromLEnd32(Q_UINT32* dst,char* src); void memcpyFromLEnd16(Q_UINT16* dst,char* src); + void memcpyToLEnd32(char* src,Q_UINT32* dst); + void memcpyToLEnd16(char* src,Q_UINT16* dst); QDateTime dateFromPackedStruct5(const unsigned char* pBytes); void dateToPackedStruct5(const QDateTime& datetime, unsigned char* dst); + bool testDatabase(); + #endif diff --git a/src/main.cpp b/src/main.cpp index 57e3c03..0275b41 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -31,6 +31,7 @@ #include "main.h" #include "PwmConfig.h" +#include "PwManager.h" #include "mainwindow.h" using namespace std; @@ -278,6 +279,10 @@ int i=1; if(i-1==argc) cout << "No configuration file specified." << endl; else{ArgCfg=QString::fromUtf8(argv[i+1]); i++;} } + else if(QString(argv[i])=="-test"){ + if (testDatabase()) exit(0); + else exit(1); + } else{cout << "** Unrecognized argument: " << argv[i] << endl; exit(1);} }