ip2cparser_v3.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) 2022 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "ip2cparser_v3.h"
24 
25 #include "ip2c/ip2cparser.h"
26 #include "ip2c/ip2crange.h"
27 
28 #include "datastreamoperatorwrapper.h"
29 #include "global.h"
30 #include <QBuffer>
31 #include <QDataStream>
32 #include <QFile>
33 #include <QMap>
34 
35 #include <cstdint>
36 
37 enum class Section : uint8_t
38 {
39  LICENCE_TEXTS = 0,
40  IPV4 = 1,
41  URL_DB = 2,
42 };
43 
44 bool IP2CParserV3::parse(IP2CParser &self, QIODevice &dataBase)
45 {
46  QDataStream dstream(&dataBase);
47  dstream.setByteOrder(QDataStream::LittleEndian);
48  DataStreamOperatorWrapper stream(&dstream);
49 
50  while (stream.hasRemaining())
51  {
52  auto id = stream.readQUInt8();
53  auto size = stream.readQUInt64();
54  switch (id)
55  {
56  case decltype(id)(Section::LICENCE_TEXTS):
57  if (!readSectionLegalNotice(self, stream.readRaw(size)))
58  return false;
59  break;
60  case decltype(id)(Section::IPV4):
61  if (!readSectionIpv4(self, stream.readRaw(size)))
62  return false;
63  break;
64  case decltype(id)(Section::URL_DB):
65  if (!readSectionUrl(self, stream.readRaw(size)))
66  return false;
67  break;
68  default:
69  stream.skipRawData(size);
70  }
71  }
72 
73  return true;
74 }
75 
76 bool IP2CParserV3::readSectionIpv4(IP2CParser &self, QByteArray &&section)
77 {
78  QBuffer buffer(&section);
79  buffer.open(QIODevice::ReadOnly);
80  QDataStream dstream(&buffer);
81  dstream.setByteOrder(QDataStream::LittleEndian);
82  DataStreamOperatorWrapper stream(&dstream);
83  // We need to store the addresses in such hash table to make sure they
84  // are ordered in proper, ascending order. Otherwise the whole library
85  // will not work!
86  QMap<unsigned, IP2CRange> hashTable;
87 
88  while (stream.hasRemaining())
89  {
90  QString countryCode = QString::fromUtf8(stream.readRawUntilByte('\0'));
91 
92  // Base entry for each IP read from the file
93  IP2CRange baseEntry;
94  baseEntry.country = countryCode;
95  if (!stream.hasRemaining())
96  return false;
97 
98  quint32 numOfIpBlocks = stream.readQUInt32();
99 
100  for (quint32 x = 0; x < numOfIpBlocks; ++x)
101  {
102  // Create new entry from the base.
103  IP2CRange entry = baseEntry;
104 
105  entry.ipStart = stream.readQUInt32();
106  if (!stream.hasRemaining())
107  return false;
108  entry.ipEnd = stream.readQUInt32();
109 
110  hashTable[entry.ipStart] = entry;
111  }
112  }
113 
114  self.ranges_ = hashTable.values();
115  return true;
116 }
117 
118 bool IP2CParserV3::readSectionLegalNotice(IP2CParser &self, QByteArray &&section)
119 {
120  QBuffer buffer(&section);
121  buffer.open(QIODevice::ReadOnly);
122  QDataStream dstream(&buffer);
123  dstream.setByteOrder(QDataStream::LittleEndian);
124  DataStreamOperatorWrapper stream(&dstream);
125 
126  while (stream.hasRemaining())
127  {
128  auto locale = QString::fromUtf8(stream.readRawUntilByte('\0'));
129  if (stream.hasRemaining())
130  {
131  auto text = QString::fromUtf8(stream.readRawUntilByte('\0'));
132  self.licences_.insert(std::move(locale), std::move(text));
133  }
134  else
135  return false;
136  }
137  return true;
138 }
139 
140 bool IP2CParserV3::readSectionUrl(IP2CParser &self, QByteArray &&section)
141 {
142  QBuffer buffer(&section);
143  buffer.open(QIODevice::ReadOnly);
144  QDataStream dstream(&buffer);
145  dstream.setByteOrder(QDataStream::LittleEndian);
146  DataStreamOperatorWrapper stream(&dstream);
147  self.url_ = QString::fromUtf8(DataStreamOperatorWrapper(&dstream).readRawUntilByte('\0'));
148  return true;
149 }