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 = NULL;
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  {
68  return false;
69  }
70 
71  const char* data = dataArray.constData();
72  unsigned short version = READINT16(&data[pos]);
73 
74  bool wasReadSuccessful = false;
75  switch (version)
76  {
77  case 2:
78  wasReadSuccessful = readDatabaseVersion2(dataArray);
79  break;
80 
81  default:
82  wasReadSuccessful = false;
83  break;
84  }
85 
86  if (!wasReadSuccessful)
87  {
88  return false;
89  }
90 
91  gLog << tr("IP2C database read in %1 ms. Entries read: %2").arg(time.elapsed()).arg(pTargetDatabase->numKnownEntries());
92  return true;
93 }
94 
95 void IP2CParser::parsingThreadFinished()
96 {
97  bool bSuccessState = currentParsingThread->bSuccessState;
98  gLog << tr("IP2C parsing thread has finished.");
99 
100  delete currentParsingThread;
101  currentParsingThread = NULL;
102 
103  emit parsingFinished(bSuccessState);
104 }
105 
106 bool IP2CParser::readDatabase(const QString& filePath)
107 {
108  bool bSuccess = doReadDatabase(filePath);
109  emit parsingFinished(bSuccess);
110 
111  return bSuccess;
112 }
113 
114 void IP2CParser::readDatabaseThreaded(const QString& filePath)
115 {
116  if (currentParsingThread != NULL)
117  {
118  return;
119  }
120 
121  ParsingThread* pParsingThread = new ParsingThread(this, filePath);
122  connect(pParsingThread, SIGNAL( finished() ), this, SLOT( parsingThreadFinished() ) );
123 
124  currentParsingThread = pParsingThread;
125 
126  pParsingThread->start();
127 }
128 
129 bool IP2CParser::readDatabaseVersion2(const QByteArray& dataArray)
130 {
131  QBuffer buffer;
132  buffer.setData(dataArray);
133  buffer.open(QIODevice::ReadOnly);
134  QDataStream dstream(&buffer);
135  dstream.setByteOrder(QDataStream::LittleEndian);
136  DataStreamOperatorWrapper stream(&dstream);
137  stream.skipRawData(6); // skip file tag and version number
138 
139  // We need to store the addresses in such hash table to make sure they
140  // are ordered in proper, ascending order. Otherwise the whole library
141  // will not work!
142  QMap<unsigned, IP2C::IP2CData> hashTable;
143 
144  while (stream.hasRemaining())
145  {
146  // Base entry for each IP read from the file
147  IP2C::IP2CData baseEntry;
148 
149  baseEntry.countryFullName = QString::fromUtf8(stream.readRawUntilByte('\0'));
150  baseEntry.country = QString::fromUtf8(stream.readRawUntilByte('\0'));
151  if (!stream.hasRemaining()) return false;
152 
153  quint32 numOfIpBlocks = stream.readQUInt32();
154 
155  for (quint32 x = 0; x < numOfIpBlocks; ++x)
156  {
157  // Create new entry from the base.
158  IP2C::IP2CData entry = baseEntry;
159 
160  entry.ipStart = stream.readQUInt32();
161  if (!stream.hasRemaining()) return false;
162  entry.ipEnd = stream.readQUInt32();
163 
164  hashTable[entry.ipStart] = entry;
165  }
166  }
167 
168  pTargetDatabase->setDatabase(hashTable.values());
169 
170  return true;
171 }
172 
174 
175 IP2CParser::ConstructorDestructorParserStateSetter::ConstructorDestructorParserStateSetter(IP2CParser* pParser)
176 {
177  this->pParser = pParser;
178  pParser->bIsParsing = true;
179 }
180 
181 IP2CParser::ConstructorDestructorParserStateSetter::~ConstructorDestructorParserStateSetter()
182 {
183  pParser->bIsParsing = false;
184 }
185 
187 
188 void IP2CParser::ParsingThread::run()
189 {
190  bSuccessState = pParser->doReadDatabase(filePath);
191 }
void setDatabase(const QList< IP2CData > &sortedCountryData)
Sets database contents to the list specified.
Definition: ip2c.h:122
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:136
IP to Country database handler.
Definition: ip2c.h:48
void parsingFinished(bool bSuccess)
A signal emitted when parser finishes its job.