23 #include "ip2cparser.h"
30 #include <QMutexLocker>
33 IP2CParser::IP2CParser(
IP2C* pTargetDatabase)
35 currentParsingThread = NULL;
42 if (downloadedData.isEmpty())
48 QByteArray binaryData;
51 QFile out(outFilePath);
52 if(out.open(QIODevice::WriteOnly) && out.isWritable())
54 out.write(binaryData);
67 unsigned fileId = MAKEID(
'I',
'P',
'2',
'C');
68 unsigned short version = 2;
69 output += QByteArray((
const char*)&fileId, 4);
70 output += QByteArray((
const char*)&version,
sizeof(
unsigned short));
73 for (it = countries.constBegin(); it != countries.constEnd(); ++it)
76 if (!it.value().empty())
79 unsigned ipBlocksNum = it.value().count();
81 output += val.countryFullName;
82 output += QByteArray(1, 0);
83 output += val.country;
84 output += QByteArray(1, 0);
85 output += QByteArray((
const char*)&ipBlocksNum,
sizeof(ipBlocksNum));
90 const char ipStart[4] = { WRITEINT32_DIRECT(
char,val.ipStart) };
91 const char ipEnd[4] = { WRITEINT32_DIRECT(
char,val.ipEnd) };
93 output += QByteArray(ipStart, 4);
94 output += QByteArray(ipEnd, 4);
99 bool IP2CParser::doReadDatabase(
const QString& filePath)
101 QMutexLocker mutexLocker(&thisLock);
104 ConstructorDestructorParserStateSetter stateSetter(
this);
106 QFile dataBase(filePath);
107 gLog << tr(
"Parsing IP2C database: %1").arg(dataBase.fileName());
109 if (!dataBase.exists()
110 || !dataBase.open(QIODevice::ReadOnly)
111 || !dataBase.isReadable())
113 gLog << tr(
"Unable to open IP2C file.");
121 QString signature = dataBase.read(4);
123 if (signature.compare(
"IP2C") != 0)
125 gLog << tr(
"IP2C database is not in compacted format. Performing conversion!");
126 QByteArray contents = dataBase.readAll();
132 gLog << tr(
"IP2C database conversion failed");
137 gLog << tr(
"IP2C database converted in %1 ms").arg(time.elapsed());
138 gLog << tr(
"Parsing now compacted IP2C database");
143 dataBase.setFileName(filePath);
144 if (!dataBase.open(QIODevice::ReadOnly))
152 QByteArray dataArray = dataBase.readAll();
156 if (pos >= dataArray.size())
161 const char* data = dataArray.constData();
162 unsigned short version = READINT16(&data[pos]);
164 bool wasReadSuccessful =
false;
168 wasReadSuccessful = readDatabaseVersion1(dataArray);
172 wasReadSuccessful = readDatabaseVersion2(dataArray);
176 wasReadSuccessful =
false;
180 if (!wasReadSuccessful)
185 gLog << tr(
"IP2C database read in %1 ms. Entries read: %2").arg(time.elapsed()).arg(
pTargetDatabase->numKnownEntries());
189 void IP2CParser::parsingThreadFinished()
191 bool bSuccessState = currentParsingThread->bSuccessState;
192 gLog << tr(
"IP2C parsing thread has finished.");
194 delete currentParsingThread;
195 currentParsingThread = NULL;
200 bool IP2CParser::readDatabase(
const QString& filePath)
202 bool bSuccess = doReadDatabase(filePath);
208 void IP2CParser::readDatabaseThreaded(
const QString& filePath)
210 if (currentParsingThread != NULL)
215 ParsingThread* pParsingThread =
new ParsingThread(
this, filePath);
216 connect(pParsingThread, SIGNAL( finished() ),
this, SLOT( parsingThreadFinished() ) );
218 currentParsingThread = pParsingThread;
220 pParsingThread->start();
223 bool IP2CParser::readDatabaseVersion1(
const QByteArray& dataArray)
226 const char* data = dataArray.constData();
228 while (pos < dataArray.size())
234 if (pos + 4 > dataArray.size())
return false;
235 entry.ipStart = READINT32(&data[pos]);
238 if (pos + 4 > dataArray.size())
return false;
239 entry.ipEnd = READINT32(&data[pos]);
242 entry.country = &data[pos];
243 pos += entry.country.size() + 1;
251 bool IP2CParser::readDatabaseVersion2(
const QByteArray& dataArray)
254 const char* data = dataArray.constData();
259 QMap<unsigned, IP2C::IP2CData> hashTable;
261 while (pos < dataArray.size())
266 baseEntry.countryFullName = &data[pos];
267 pos += baseEntry.countryFullName.size() + 1;
269 baseEntry.country = &data[pos];
270 pos += baseEntry.country.size() + 1;
272 if (pos + 4 > dataArray.size())
return false;
273 unsigned numOfIpBlocks = READINT32(&data[pos]);
276 for (
unsigned x = 0; x < numOfIpBlocks; ++x)
283 if (pos + 4 > dataArray.size())
return false;
284 entry.ipStart = READINT32(&data[pos]);
287 if (pos + 4 > dataArray.size())
return false;
288 entry.ipEnd = READINT32(&data[pos]);
291 hashTable[entry.ipStart] = entry;
303 int indexOfNewLine = -1;
304 while(textDatabase[indexOfNewLine + 1] ==
'#')
306 indexOfNewLine = textDatabase.indexOf(
'\n', indexOfNewLine + 1);
310 textDatabase = textDatabase.right(textDatabase.size() - indexOfNewLine);
312 Scanner sc(textDatabase.constData(), textDatabase.count());
314 while(sc.tokensLeft())
319 if(!sc.checkToken(TK_StringConst))
break;
320 entry.ipStart = sc->str().toUInt(&ok);
321 if(!ok || !sc.checkToken(
','))
break;
322 if(!sc.checkToken(TK_StringConst))
break;
323 entry.ipEnd = sc->str().toUInt(&ok);
324 if(!ok || !sc.checkToken(
','))
break;
325 if(!sc.checkToken(TK_StringConst))
break;
326 if(!sc.checkToken(
','))
break;
327 if(!sc.checkToken(TK_StringConst))
break;
328 if(!sc.checkToken(
','))
break;
329 if(!sc.checkToken(TK_StringConst))
break;
330 if(!sc.checkToken(
','))
break;
331 if(!sc.checkToken(TK_StringConst))
break;
332 entry.country = sc->str();
333 if(!sc.checkToken(
','))
break;
334 if(!sc.checkToken(TK_StringConst))
break;
335 entry.countryFullName = sc->str();
338 if (countries.contains(entry.country))
340 countries[entry.country].append(entry);
344 QList<IP2C::IP2CData> list;
346 countries[entry.country] = list;
353 IP2CParser::ConstructorDestructorParserStateSetter::ConstructorDestructorParserStateSetter(
IP2CParser* pParser)
355 this->pParser = pParser;
356 pParser->bIsParsing =
true;
359 IP2CParser::ConstructorDestructorParserStateSetter::~ConstructorDestructorParserStateSetter()
361 pParser->bIsParsing =
false;
366 void IP2CParser::ParsingThread::run()
368 bSuccessState = pParser->doReadDatabase(filePath);
void setDatabase(const QList< IP2CData > &sortedCountryData)
Sets database contents to the list specified.
void appendEntryToDatabase(const IP2CData &entry)
Adds new country entry to the database.
IP2C * pTargetDatabase
Database to which the IP2C parser will save the data it retrieves from IP2C file. ...
void convertCountriesIntoBinaryData(const Countries &countries, QByteArray &output)
IP to Country database handler.
QHash< QString, QList< IP2C::IP2CData > > Countries
void parsingFinished(bool bSuccess)
A signal emitted when parser finishes its job.
void readTextDatabase(QByteArray &textDatabase, Countries &countries)
Scanner reads scripts by checking individual tokens.
bool convertAndSaveDatabase(QByteArray &downloadedData, const QString &outFilePath)