ip2cparser.cpp
1 //------------------------------------------------------------------------------
2 // ip2cparser.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301 USA
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2009 Braden "Blzut3" Obrzut <admin@maniacsvault.net>
22 //------------------------------------------------------------------------------
23 #include "ip2cparser.h"
24 
25 #include "datastreamoperatorwrapper.h"
26 #include "global.h"
27 #include "log.h"
28 #include <QBuffer>
29 #include <QFile>
30 #include <QMap>
31 #include <QMutexLocker>
32 #include <QTime>
33 
34 IP2CParser::IP2CParser(IP2C *pTargetDatabase)
35 {
36  currentParsingThread = nullptr;
37  this->pTargetDatabase = pTargetDatabase;
38  bIsParsing = false;
39 }
40 
41 bool IP2CParser::doReadDatabase(const QString &filePath)
42 {
43  QMutexLocker mutexLocker(&thisLock);
44 
45  // This will set proper state whenever and wherever this method finishes.
46  ConstructorDestructorParserStateSetter stateSetter(this);
47 
48  QFile dataBase(filePath);
49  gLog << tr("Parsing IP2C database: %1").arg(dataBase.fileName());
50 
51  if (!dataBase.exists()
52  || !dataBase.open(QIODevice::ReadOnly)
53  || !dataBase.isReadable())
54  {
55  gLog << tr("Unable to open IP2C file.");
56  return false;
57  }
58 
59  QTime time;
60  time.start();
61 
62  QByteArray dataArray = dataBase.readAll();
63 
64  // Read version.
65  int pos = 4;
66  if (pos >= dataArray.size())
67  return false;
68 
69  const char *data = dataArray.constData();
70  unsigned short version = READINT16(&data[pos]);
71 
72  bool wasReadSuccessful = false;
73  switch (version)
74  {
75  case 2:
76  wasReadSuccessful = readDatabaseVersion2(dataArray);
77  break;
78 
79  default:
80  wasReadSuccessful = false;
81  break;
82  }
83 
84  if (!wasReadSuccessful)
85  return false;
86 
87  gLog << tr("IP2C database read in %1 ms. Entries read: %2").arg(time.elapsed()).arg(pTargetDatabase->numKnownEntries());
88  return true;
89 }
90 
91 void IP2CParser::parsingThreadFinished()
92 {
93  bool bSuccessState = currentParsingThread->bSuccessState;
94  gLog << tr("IP2C parsing thread has finished.");
95 
96  delete currentParsingThread;
97  currentParsingThread = nullptr;
98 
99  emit parsingFinished(bSuccessState);
100 }
101 
102 bool IP2CParser::readDatabase(const QString &filePath)
103 {
104  bool bSuccess = doReadDatabase(filePath);
105  emit parsingFinished(bSuccess);
106 
107  return bSuccess;
108 }
109 
110 void IP2CParser::readDatabaseThreaded(const QString &filePath)
111 {
112  if (currentParsingThread != nullptr)
113  return;
114 
115  auto pParsingThread = new ParsingThread(this, filePath);
116  connect(pParsingThread, SIGNAL(finished()), this, SLOT(parsingThreadFinished()));
117 
118  currentParsingThread = pParsingThread;
119 
120  pParsingThread->start();
121 }
122 
123 bool IP2CParser::readDatabaseVersion2(const QByteArray &dataArray)
124 {
125  QBuffer buffer;
126  buffer.setData(dataArray);
127  buffer.open(QIODevice::ReadOnly);
128  QDataStream dstream(&buffer);
129  dstream.setByteOrder(QDataStream::LittleEndian);
130  DataStreamOperatorWrapper stream(&dstream);
131  stream.skipRawData(6); // skip file tag and version number
132 
133  // We need to store the addresses in such hash table to make sure they
134  // are ordered in proper, ascending order. Otherwise the whole library
135  // will not work!
136  QMap<unsigned, IP2C::IP2CData> hashTable;
137 
138  while (stream.hasRemaining())
139  {
140  // Base entry for each IP read from the file
141  IP2C::IP2CData baseEntry;
142 
143  baseEntry.countryFullName = QString::fromUtf8(stream.readRawUntilByte('\0'));
144  baseEntry.country = QString::fromUtf8(stream.readRawUntilByte('\0'));
145  if (!stream.hasRemaining())
146  return false;
147 
148  quint32 numOfIpBlocks = stream.readQUInt32();
149 
150  for (quint32 x = 0; x < numOfIpBlocks; ++x)
151  {
152  // Create new entry from the base.
153  IP2C::IP2CData entry = baseEntry;
154 
155  entry.ipStart = stream.readQUInt32();
156  if (!stream.hasRemaining())
157  return false;
158  entry.ipEnd = stream.readQUInt32();
159 
160  hashTable[entry.ipStart] = entry;
161  }
162  }
163 
164  pTargetDatabase->setDatabase(hashTable.values());
165 
166  return true;
167 }
168 
170 
171 IP2CParser::ConstructorDestructorParserStateSetter::ConstructorDestructorParserStateSetter(IP2CParser *pParser)
172 {
173  this->pParser = pParser;
174  pParser->bIsParsing = true;
175 }
176 
177 IP2CParser::ConstructorDestructorParserStateSetter::~ConstructorDestructorParserStateSetter()
178 {
179  pParser->bIsParsing = false;
180 }
181 
183 
184 void IP2CParser::ParsingThread::run()
185 {
186  bSuccessState = pParser->doReadDatabase(filePath);
187 }
void setDatabase(const QList< IP2CData > &sortedCountryData)
Sets database contents to the list specified.
Definition: ip2c.h:134
Wraps around QDataStream stream operators to provide cleaner reading interface.
IP2C * pTargetDatabase
Database to which the IP2C parser will save the data it retrieves from IP2C file. ...
Definition: ip2cparser.h:142
IP to Country database handler.
Definition: ip2c.h:48
void parsingFinished(bool bSuccess)
A signal emitted when parser finishes its job.