source: trunk/Utilities/MaxMindGeoLite/Location.h @ 47

Last change on this file since 47 was 47, checked in by roman, 12 years ago
  • Property svn:keywords set to Id
File size: 13.2 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2012
3// Created by Roman Ryltsov roman@alax.info
4//
5// $Id: Location.h 47 2012-02-11 13:53:43Z roman $
6
7#pragma once
8
9#include <atlenc.h>
10#include "rosockets.h"
11#include "MaxMindGeoLite_i.h"
12
13////////////////////////////////////////////////////////////
14// GeoLiteCity
15
16namespace GeoLiteCity
17{
18        ////////////////////////////////////////////////////////////
19        // CLocation
20
21        class CLocation
22        {
23        public:
24                INT m_nIdentifier;
25                CStringA m_sCountryCode;
26                CStringA m_sRegion;
27                CStringA m_sCity;
28                CStringA m_sPostalCode;
29                DOUBLE m_fLatitude;
30                DOUBLE m_fLongitude;
31                CStringA m_sMetroCode;
32                CStringA m_sAreaCode;
33
34        public:
35        // CLocation
36                CLocation() throw()
37                {
38                }
39                CLocation(LPCSTR pszString)
40                {
41                        Initialize(pszString);
42                }
43                VOID Initialize(LPCSTR pszString)
44                {
45                        CRoArrayT<CStringA> Array;
46                        __D(_StringHelper::GetCommaSeparatedItems(pszString, Array) >= 7, E_UNNAMED);
47                        __D(AtlStringToInteger(Array[0], m_nIdentifier), E_UNNAMED);
48                        m_sCountryCode = Array[1];
49                        m_sRegion = Array[2];
50                        m_sCity = Array[3];
51                        m_sPostalCode = Array[4];
52                        __D(AtlStringToDouble(Array[5], m_fLatitude), E_UNNAMED);
53                        __D(AtlStringToDouble(Array[6], m_fLongitude), E_UNNAMED);
54                        if(Array.GetCount() >= 8)
55                                m_sMetroCode = Array[7];
56                        if(Array.GetCount() >= 9)
57                                m_sAreaCode = Array[8];
58                }
59        };
60
61        ////////////////////////////////////////////////////////////
62        // CLocationArray
63
64        class CLocationArray :
65                protected CRoArrayT<CLocation>
66        {
67        public:
68        // CLocationArray
69                CLocationArray() throw()
70                {
71                }
72                CLocationArray(const CPath& sPath)
73                {
74                        Initialize(sPath);
75                }
76                VOID Initialize(const CPath& sPath)
77                {
78                        CAtlFile File;
79                        __C(File.Create(sPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
80                        ULONGLONG nSize;
81                        __C(File.GetSize(nSize));
82                        CHeapPtr<CHAR> pszData;
83                        __D(pszData.Allocate((SIZE_T) nSize + 1), E_OUTOFMEMORY);
84                        __C(File.Read(pszData, (DWORD) nSize));
85                        pszData[nSize] = 0;
86                        LPCSTR pszDataPointer = pszData;
87                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Copyright line
88                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Header line
89                        for(; *pszDataPointer; )
90                        {
91                                LPCSTR pszSeparator = strchr(pszDataPointer, '\n');
92                                if(!pszSeparator)
93                                        break;
94                                const SIZE_T nLength = pszSeparator - pszDataPointer;
95                                CTempBufferT<CHAR> pszLine(nLength + 1);
96                                strncpy_s(pszLine, nLength + 1, pszDataPointer, _TRUNCATE);
97                                const SIZE_T nIndex = Add();
98                                CLocation& Location = GetAt(nIndex);
99                                Location.Initialize(pszLine);
100                                __D(Location.m_nIdentifier == nIndex + 1, E_UNNAMED);
101                                pszDataPointer = pszSeparator + 1;
102                        }
103                }
104                BOOL Lookup(INT nIdentifier, const CLocation** ppLocation = NULL) const throw()
105                {
106                        if(nIdentifier < 1 || nIdentifier - 1 >= (INT) GetCount())
107                                return FALSE;
108                        const CLocation& Location = GetAt(nIdentifier - 1);
109                        _A(Location.m_nIdentifier == nIdentifier);
110                        if(ppLocation)
111                                *ppLocation = &Location;
112                        return TRUE;
113                }
114        };
115
116        ////////////////////////////////////////////////////////////
117        // CBlock
118
119        class CBlock
120        {
121        public:
122                ULONG m_nStartAddress;
123                ULONG m_nEndAddress;
124                INT m_nLocationIdentifier;
125
126        public:
127        // CBlock
128                CBlock() throw()
129                {
130                }
131                CBlock(LPCSTR pszString)
132                {
133                        Initialize(pszString);
134                }
135                VOID Initialize(LPCSTR pszString)
136                {
137                        CRoArrayT<CStringA> Array;
138                        __D(_StringHelper::GetCommaSeparatedItems(pszString, Array) >= 3, E_UNNAMED);
139                        LONGLONG nStartAddress, nEndAddress;
140                        __D(AtlStringToInteger(Array[0], nStartAddress), E_UNNAMED);
141                        __D(AtlStringToInteger(Array[1], nEndAddress), E_UNNAMED);
142                        m_nStartAddress = (ULONG) nStartAddress;
143                        m_nEndAddress = (ULONG) nEndAddress;
144                        __D(AtlStringToInteger(Array[2], m_nLocationIdentifier), E_UNNAMED);
145                }
146                BOOL Contains(ULONG nAddress) const throw()
147                {
148                        return nAddress >= m_nStartAddress && nAddress <= m_nEndAddress;
149                }
150        };
151
152        ////////////////////////////////////////////////////////////
153        // CBlockArray
154
155        class CBlockArray :
156                protected CRoArrayT<CBlock>
157        {
158        public:
159        // CBlockArray
160                CBlockArray() throw()
161                {
162                }
163                CBlockArray(const CPath& sPath)
164                {
165                        Initialize(sPath);
166                }
167                VOID Initialize(const CPath& sPath)
168                {
169                        CAtlFile File;
170                        __C(File.Create(sPath, GENERIC_READ, FILE_SHARE_READ, OPEN_EXISTING));
171                        ULONGLONG nSize;
172                        __C(File.GetSize(nSize));
173                        CHeapPtr<CHAR> pszData;
174                        __D(pszData.Allocate((SIZE_T) nSize + 1), E_OUTOFMEMORY);
175                        __C(File.Read(pszData, (DWORD) nSize));
176                        pszData[nSize] = 0;
177                        LPCSTR pszDataPointer = pszData;
178                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Copyright line
179                        pszDataPointer = strchr(pszDataPointer, '\n') + 1; // Header line
180                        ULONG nPreviousEndAddress = 0;
181                        for(; *pszDataPointer; )
182                        {
183                                LPCSTR pszSeparator = strchr(pszDataPointer, '\n');
184                                if(!pszSeparator)
185                                        break;
186                                const SIZE_T nLength = pszSeparator - pszDataPointer;
187                                CTempBufferT<CHAR> pszLine(nLength + 1);
188                                strncpy_s(pszLine, nLength + 1, pszDataPointer, _TRUNCATE);
189                                const SIZE_T nIndex = Add();
190                                CBlock& Block = GetAt(nIndex);
191                                Block.Initialize(pszLine);
192                                __D(Block.m_nStartAddress && Block.m_nStartAddress > nPreviousEndAddress, E_UNNAMED);
193                                nPreviousEndAddress = Block.m_nEndAddress;
194                                pszDataPointer = pszSeparator + 1;
195                        }
196                }
197                BOOL Lookup(ULONG nAddress, const CBlock** ppBlock = NULL) const throw()
198                {
199                        SIZE_T nLeftIndex = 0, nRightIndex = GetCount();
200                        if(!nRightIndex)
201                                return FALSE;
202                        if(nAddress < GetAt(0).m_nStartAddress || nAddress > GetAt(GetCount() - 1).m_nEndAddress)
203                                return FALSE;
204                        for(; nLeftIndex + 1 < nRightIndex; )
205                        {
206                                SIZE_T nIndex = (nLeftIndex + nRightIndex) / 2;
207                                const CBlock& Block = GetAt(nIndex);
208                                if(nAddress < Block.m_nStartAddress)
209                                {
210                                        nRightIndex = nIndex;
211                                } else
212                                if(nAddress > Block.m_nEndAddress)
213                                {
214                                        nLeftIndex = nIndex + 1;
215                                } else
216                                {
217                                        nLeftIndex = nIndex;
218                                        break;
219                                }
220                        }
221                        const CBlock& Block = GetAt(nLeftIndex);
222                        if(!Block.Contains(nAddress))
223                                return FALSE;
224                        if(ppBlock)
225                                *ppBlock = &Block;
226                        return TRUE;
227                }
228        };
229}
230
231////////////////////////////////////////////////////////////
232// CLocations
233
234class ATL_NO_VTABLE CLocations : 
235        public CComObjectRootEx<CComMultiThreadModelNoCS>,
236        public CComCoClass<CLocations, &__uuidof(Locations)>,
237        public CBasePersistT<CLocations>,
238        //public IRoPersistStreamInitT<CLocations>,
239        //public IRoPersistStorageT<CLocations>,
240        //public IRoPersistPropertyBagT<CLocations>,
241        //public IRoSpecifyPropertyPagesT<CLocations>,
242        public IDispatchImpl<ILocations>
243{
244public:
245        enum { IDR = IDR_LOCATIONS };
246
247//DECLARE_REGISTRY_RESOURCEID(IDR)
248
249DECLARE_PROTECT_FINAL_CONSTRUCT()
250
251BEGIN_COM_MAP(CLocations)
252        //COM_INTERFACE_ENTRY_IID(__uuidof(IPersist), IPersistStreamInit)
253        //COM_INTERFACE_ENTRY_IID(__uuidof(IPersistStream), IPersistStreamInit)
254        //COM_INTERFACE_ENTRY(IPersistStreamInit)
255        //COM_INTERFACE_ENTRY(IPersistStorage)
256        //COM_INTERFACE_ENTRY(IPersistPropertyBag)
257        //COM_INTERFACE_ENTRY(ISpecifyPropertyPages)
258        COM_INTERFACE_ENTRY(ILocations)
259        COM_INTERFACE_ENTRY(IDispatch)
260END_COM_MAP()
261
262BEGIN_PROP_MAP(CLocations)
263END_PROP_MAP()
264
265public:
266
267        ////////////////////////////////////////////////////////
268        // CLocation
269
270        class ATL_NO_VTABLE CLocation : 
271                public CComObjectRootEx<CComMultiThreadModelNoCS>,
272                public CComCoClass<CLocation, &__uuidof(Location)>,
273                public IDispatchImpl<ILocation>
274        {
275        public:
276
277        DECLARE_NO_REGISTRY()
278
279        //DECLARE_PROTECT_FINAL_CONSTRUCT()
280
281        BEGIN_COM_MAP(CLocation)
282                COM_INTERFACE_ENTRY(ILocation)
283                COM_INTERFACE_ENTRY(IDispatch)
284        END_COM_MAP()
285
286        private:
287                GeoLiteCity::CLocation m_Location;
288
289        public:
290        // CLocation
291                CLocation() throw()
292                {
293                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
294                }
295                ~CLocation() throw()
296                {
297                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
298                }
299                VOID Initialize(const GeoLiteCity::CLocation& Location)
300                {
301                        m_Location = Location;
302                }
303
304        // ILocation
305                STDMETHOD(get_Country)(BSTR* psCountry) throw()
306                {
307                        _Z4(atlTraceCOM, 4, _T("...\n"));
308                        _ATLTRY
309                        {
310                                __D(psCountry, E_POINTER);
311                                ObjectLock Lock(this);
312                                *psCountry = CComBSTR(m_Location.m_sCountryCode).Detach();
313                        }
314                        _ATLCATCH(Exception)
315                        {
316                                _C(Exception);
317                        }
318                        return S_OK;
319                }
320                STDMETHOD(get_Region)(BSTR* psRegion) throw()
321                {
322                        _Z4(atlTraceCOM, 4, _T("...\n"));
323                        _ATLTRY
324                        {
325                                __D(psRegion, E_POINTER);
326                                ObjectLock Lock(this);
327                                *psRegion = CComBSTR(m_Location.m_sRegion).Detach();
328                        }
329                        _ATLCATCH(Exception)
330                        {
331                                _C(Exception);
332                        }
333                        return S_OK;
334                }
335                STDMETHOD(get_City)(BSTR* psCity) throw()
336                {
337                        _Z4(atlTraceCOM, 4, _T("...\n"));
338                        _ATLTRY
339                        {
340                                __D(psCity, E_POINTER);
341                                ObjectLock Lock(this);
342                                *psCity = CComBSTR(m_Location.m_sCity).Detach();
343                        }
344                        _ATLCATCH(Exception)
345                        {
346                                _C(Exception);
347                        }
348                        return S_OK;
349                }
350                STDMETHOD(get_PostalCode)(BSTR* psPostalCode) throw()
351                {
352                        _Z4(atlTraceCOM, 4, _T("...\n"));
353                        _ATLTRY
354                        {
355                                __D(psPostalCode, E_POINTER);
356                                ObjectLock Lock(this);
357                                *psPostalCode = CComBSTR(m_Location.m_sPostalCode).Detach();
358                        }
359                        _ATLCATCH(Exception)
360                        {
361                                _C(Exception);
362                        }
363                        return S_OK;
364                }
365                STDMETHOD(get_Latitude)(DOUBLE* pfLatitude) throw()
366                {
367                        _Z4(atlTraceCOM, 4, _T("...\n"));
368                        _ATLTRY
369                        {
370                                __D(pfLatitude, E_POINTER);
371                                ObjectLock Lock(this);
372                                *pfLatitude = m_Location.m_fLatitude;
373                        }
374                        _ATLCATCH(Exception)
375                        {
376                                _C(Exception);
377                        }
378                        return S_OK;
379                }
380                STDMETHOD(get_Longitude)(DOUBLE* pfLongitude) throw()
381                {
382                        _Z4(atlTraceCOM, 4, _T("...\n"));
383                        _ATLTRY
384                        {
385                                __D(pfLongitude, E_POINTER);
386                                ObjectLock Lock(this);
387                                *pfLongitude = m_Location.m_fLongitude;
388                        }
389                        _ATLCATCH(Exception)
390                        {
391                                _C(Exception);
392                        }
393                        return S_OK;
394                }
395                STDMETHOD(get_MetroCode)(BSTR* psMetroCode) throw()
396                {
397                        _Z4(atlTraceCOM, 4, _T("...\n"));
398                        _ATLTRY
399                        {
400                                __D(psMetroCode, E_POINTER);
401                                ObjectLock Lock(this);
402                                *psMetroCode = CComBSTR(m_Location.m_sMetroCode).Detach();
403                        }
404                        _ATLCATCH(Exception)
405                        {
406                                _C(Exception);
407                        }
408                        return S_OK;
409                }
410                STDMETHOD(get_AreaCode)(BSTR* psAreaCode) throw()
411                {
412                        _Z4(atlTraceCOM, 4, _T("...\n"));
413                        _ATLTRY
414                        {
415                                __D(psAreaCode, E_POINTER);
416                                ObjectLock Lock(this);
417                                *psAreaCode = CComBSTR(m_Location.m_sAreaCode).Detach();
418                        }
419                        _ATLCATCH(Exception)
420                        {
421                                _C(Exception);
422                        }
423                        return S_OK;
424                }
425        };
426
427private:
428        CWindowsSockets2 m_Sockets;
429        CRequiresSave m_bRequiresSave;
430        mutable CRoCriticalSection m_DataCriticalSection;
431        GeoLiteCity::CLocationArray m_LocationArray;
432        GeoLiteCity::CBlockArray m_BlockArray;
433
434public:
435// CLocations
436        static CString GetObjectFriendlyName()
437        {
438                return _StringHelper::GetLine(IDR, 2);
439        }
440        static HRESULT WINAPI UpdateRegistry(BOOL bRegister) throw()
441        {
442                _Z2(atlTraceRegistrar, 2, _T("bRegister %d\n"), bRegister);
443                _ATLTRY
444                {
445                        UpdateRegistryFromResource<CLocations>(bRegister);
446                }
447                _ATLCATCH(Exception)
448                {
449                        _C(Exception);
450                }
451                return S_OK;
452        }
453        CLocations() throw() :
454                CBasePersistT<CLocations>(m_DataCriticalSection),
455                m_bRequiresSave(m_DataCriticalSection)
456        {
457                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
458        }
459        ~CLocations() throw()
460        {
461                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
462        }
463        HRESULT FinalConstruct() throw()
464        {
465                _ATLTRY
466                {
467                        __C(m_Sockets.GetStartupResult());
468                        Initialize();
469                }
470                _ATLCATCH(Exception)
471                {
472                        _C(Exception);
473                }
474                return S_OK;
475        }
476        VOID FinalRelease() throw()
477        {
478        }
479        VOID Initialize()
480        {
481                TCHAR pszDirectory[MAX_PATH] = { 0 };
482                _W(GetModuleFileName(_AtlBaseModule.GetModuleInstance(), pszDirectory, DIM(pszDirectory)));
483                _W(RemoveFileSpec(pszDirectory));
484                CPath sLocationPath, sBlockPath;
485                sLocationPath.Combine(pszDirectory, _T("GeoLiteCity-Location.csv"));
486                sBlockPath.Combine(pszDirectory, _T("GeoLiteCity-Blocks.csv"));
487                //CRoCriticalSectionLock DataLock(m_DataCriticalSection);
488                m_LocationArray.Initialize(sLocationPath);
489                m_BlockArray.Initialize(sBlockPath);
490        }
491
492// ILocation
493        STDMETHOD(get_Item)(VARIANT vIndex, ILocation** ppLocation) throw()
494        {
495                _Z4(atlTraceCOM, 4, _T("vIndex.vt 0x%x\n"), vIndex.vt);
496                _ATLTRY
497                {
498                        __D(ppLocation, E_POINTER);
499                        __D(vIndex.vt == VT_BSTR, E_INVALIDARG);
500                        ULONG nAddress;
501                        nAddress = ntohl(inet_addr(CW2A(vIndex.bstrVal)));
502                        if(nAddress == INADDR_NONE)
503                        {
504                                SOCKADDR_IN Address;
505                                __E(CSocket::AddressFromHost(CW2CT(vIndex.bstrVal), 0, Address));
506                                nAddress = ntohl(Address.sin_addr.S_un.S_addr);
507                        }
508                        //ObjectLock Lock(this);
509                        //CRoCriticalSectionLock DataLock(m_DataCriticalSection);
510                        CObjectPtr<CLocation> pLocation;
511                        const GeoLiteCity::CBlock* pBlock;
512                        if(m_BlockArray.Lookup(nAddress, &pBlock))
513                        {
514                                const GeoLiteCity::CLocation* pInternalLocation;
515                                if(m_LocationArray.Lookup(pBlock->m_nLocationIdentifier, &pInternalLocation))
516                                        pLocation.Construct()->Initialize(*pInternalLocation);
517                                else
518                                        _A(FALSE);
519                        }
520                        *ppLocation = pLocation.Detach();
521                }
522                _ATLCATCH(Exception)
523                {
524                        _C(Exception);
525                }
526                return S_OK;
527        }
528};
529
530OBJECT_ENTRY_AUTO(__uuidof(Locations), CLocations)
Note: See TracBrowser for help on using the repository browser.