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  break;
71  }
72  }
73 
74  return true;
75 }
76 
77 bool IP2CParserV3::readSectionIpv4(IP2CParser &self, QByteArray &&section)
78 {
79  QBuffer buffer(&section);
80  buffer.open(QIODevice::ReadOnly);
81  QDataStream dstream(&buffer);
82  dstream.setByteOrder(QDataStream::LittleEndian);
83  DataStreamOperatorWrapper stream(&dstream);
84  // We need to store the addresses in such hash table to make sure they
85  // are ordered in proper, ascending order. Otherwise the whole library
86  // will not work!
87  QMap<unsigned, IP2CRange> hashTable;
88 
89  while (stream.hasRemaining())
90  {
91  auto countryCode = stream.readUtf8CString();
92 
93  // Base entry for each IP read from the file
94  IP2CRange baseEntry;
95  baseEntry.country = countryCode;
96  if (!stream.hasRemaining())
97  return false;
98 
99  quint32 numOfIpBlocks = stream.readQUInt32();
100 
101  for (quint32 x = 0; x < numOfIpBlocks; ++x)
102  {
103  // Create new entry from the base.
104  IP2CRange entry = baseEntry;
105 
106  entry.ipStart = stream.readQUInt32();
107  if (!stream.hasRemaining())
108  return false;
109  entry.ipEnd = stream.readQUInt32();
110 
111  hashTable[entry.ipStart] = entry;
112  }
113  }
114 
115  self.ranges_ = hashTable.values();
116  return true;
117 }
118 
119 bool IP2CParserV3::readSectionLegalNotice(IP2CParser &self, QByteArray &&section)
120 {
121  QBuffer buffer(&section);
122  buffer.open(QIODevice::ReadOnly);
123  QDataStream dstream(&buffer);
124  dstream.setByteOrder(QDataStream::LittleEndian);
125  DataStreamOperatorWrapper stream(&dstream);
126 
127  while (stream.hasRemaining())
128  {
129  auto locale = stream.readUtf8CString();
130  if (stream.hasRemaining())
131  {
132  auto text = stream.readUtf8CString();
133  self.licences_.insert(std::move(locale), std::move(text));
134  }
135  else
136  return false;
137  }
138  return true;
139 }
140 
141 bool IP2CParserV3::readSectionUrl(IP2CParser &self, QByteArray &&section)
142 {
143  QBuffer buffer(&section);
144  buffer.open(QIODevice::ReadOnly);
145  QDataStream dstream(&buffer);
146  dstream.setByteOrder(QDataStream::LittleEndian);
147  DataStreamOperatorWrapper stream(&dstream);
148  self.url_ = DataStreamOperatorWrapper(&dstream).readUtf8CString();
149  return true;
150 }