ip2c.cpp
1 //------------------------------------------------------------------------------
2 // ip2c.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 "ip2c.h"
24 
25 #include <QBuffer>
26 #include <QFile>
27 #include <QFileInfo>
28 #include <QHash>
29 #include <QResource>
30 #include <QTime>
31 #include <QTimeLine>
32 
33 #include "log.h"
34 
35 QMutex IP2C::instanceMutex;
36 IP2C *IP2C::staticInstance = nullptr;
37 
38 IP2C *IP2C::instance()
39 {
40  if (staticInstance == nullptr)
41  {
42  QMutexLocker locker(&instanceMutex);
43  if (staticInstance == nullptr)
44  staticInstance = new IP2C();
45  }
46  return staticInstance;
47 }
48 
49 void IP2C::deinstantiate()
50 {
51  if (staticInstance != nullptr)
52  {
53  delete staticInstance;
54  staticInstance = nullptr;
55  }
56 }
57 
58 IP2C::IP2C()
59  : flagLan(":flags/lan-small"), flagLocalhost(":flags/localhost-small"),
60  flagUnknown(":flags/unknown-small")
61 {
62 }
63 
64 IP2C::~IP2C()
65 {
66 }
67 
68 const QPixmap &IP2C::flag(const QString &countryShortName)
69 {
70  if (flags.contains(countryShortName))
71  return flags[countryShortName];
72 
73  QString resName = ":flags/" + countryShortName;
74  QResource res(resName);
75 
76  if (!res.isValid())
77  {
78  gLog << tr("No flag for country: %1").arg(countryShortName);
79  flags[countryShortName] = flagUnknown;
80  return flagUnknown;
81  }
82 
83  flags[countryShortName] = QPixmap(resName);
84  return flags[countryShortName];
85 }
86 
87 bool IP2C::hasData() const
88 {
89  return !database.empty();
90 }
91 
92 const IP2C::IP2CData &IP2C::lookupIP(unsigned int ipaddress)
93 {
94  if (database.empty())
95  return invalidData;
96 
97  unsigned int upper = database.size() - 1;
98  unsigned int lower = 0;
99  unsigned int index = database.size() / 2;
100  unsigned int lastIndex = 0xFFFFFFFF;
101  while (index != lastIndex) // Infinite loop protection.
102  {
103  lastIndex = index;
104 
105  if (ipaddress < database[index].ipStart)
106  {
107  upper = index;
108  index -= (index - lower) >> 1; // If we're concerning ourselves with speed >>1 is the same as /2, but should be faster.
109  continue;
110  }
111  else if (ipaddress > database[index].ipEnd)
112  {
113  lower = index;
114  index += (upper - index) >> 1;
115  continue;
116  }
117  return database[index];
118  }
119 
120  return invalidData;
121 }
122 
124 {
125  if (isLocalhostAddress(ipaddress))
126  return IP2CCountryInfo(&flagLocalhost, tr("Localhost"));
127 
128  if (isLANAddress(ipaddress))
129  return IP2CCountryInfo(&flagLan, tr("LAN"));
130 
131  if (!hasData())
132  return IP2CCountryInfo();
133 
134  const IP2CData &data = lookupIP(ipaddress);
135 
136  if (!data.isCountryKnown())
137  return IP2CCountryInfo(&flagUnknown, tr("Unknown"));
138 
139  if (!data.isValid())
140  return IP2CCountryInfo();
141 
142  const QPixmap *pFlag = &flag(data.country);
143  return IP2CCountryInfo(pFlag, data.countryFullName);
144 }
145 
146 bool IP2C::IP2CData::isCountryKnown() const
147 {
148  return !country.isEmpty() && country != "ZZZ";
149 }