File: prototypes.py

package info (click to toggle)
python-django 1.7.1-1~bpo70%2B1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy-backports
  • size: 44,904 kB
  • sloc: python: 168,907; xml: 713; makefile: 195; sh: 170; sql: 11
file content (124 lines) | stat: -rw-r--r-- 3,944 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
from ctypes import c_char_p, c_float, c_int, string_at, Structure, POINTER
from django.contrib.gis.geoip.libgeoip import lgeoip, free


#### GeoIP C Structure definitions ####

class GeoIPRecord(Structure):
    _fields_ = [('country_code', c_char_p),
                ('country_code3', c_char_p),
                ('country_name', c_char_p),
                ('region', c_char_p),
                ('city', c_char_p),
                ('postal_code', c_char_p),
                ('latitude', c_float),
                ('longitude', c_float),
                # TODO: In 1.4.6 this changed from `int dma_code;` to
                # `union {int metro_code; int dma_code;};`.  Change
                # to a `ctypes.Union` in to accommodate in future when
                # pre-1.4.6 versions are no longer distributed.
                ('dma_code', c_int),
                ('area_code', c_int),
                ('charset', c_int),
                ('continent_code', c_char_p),
                ]
geoip_char_fields = [name for name, ctype in GeoIPRecord._fields_ if ctype is c_char_p]
GEOIP_DEFAULT_ENCODING = 'iso-8859-1'
geoip_encodings = {
    0: 'iso-8859-1',
    1: 'utf8',
}


class GeoIPTag(Structure):
    pass

RECTYPE = POINTER(GeoIPRecord)
DBTYPE = POINTER(GeoIPTag)

#### ctypes function prototypes ####

# GeoIP_lib_version appeared in version 1.4.7.
if hasattr(lgeoip, 'GeoIP_lib_version'):
    GeoIP_lib_version = lgeoip.GeoIP_lib_version
    GeoIP_lib_version.argtypes = None
    GeoIP_lib_version.restype = c_char_p
else:
    GeoIP_lib_version = None

# For freeing memory allocated within a record
GeoIPRecord_delete = lgeoip.GeoIPRecord_delete
GeoIPRecord_delete.argtypes = [RECTYPE]
GeoIPRecord_delete.restype = None


# For retrieving records by name or address.
def check_record(result, func, cargs):
    if result:
        # Checking the pointer to the C structure, if valid pull out elements
        # into a dictionary.
        rec = result.contents
        record = dict((fld, getattr(rec, fld)) for fld, ctype in rec._fields_)

        # Now converting the strings to unicode using the proper encoding.
        encoding = geoip_encodings[record['charset']]
        for char_field in geoip_char_fields:
            if record[char_field]:
                record[char_field] = record[char_field].decode(encoding)

        # Free the memory allocated for the struct & return.
        GeoIPRecord_delete(result)
        return record
    else:
        return None


def record_output(func):
    func.argtypes = [DBTYPE, c_char_p]
    func.restype = RECTYPE
    func.errcheck = check_record
    return func
GeoIP_record_by_addr = record_output(lgeoip.GeoIP_record_by_addr)
GeoIP_record_by_name = record_output(lgeoip.GeoIP_record_by_name)


# For opening & closing GeoIP database files.
GeoIP_open = lgeoip.GeoIP_open
GeoIP_open.restype = DBTYPE
GeoIP_delete = lgeoip.GeoIP_delete
GeoIP_delete.argtypes = [DBTYPE]
GeoIP_delete.restype = None


# This is so the string pointer can be freed within Python.
class geoip_char_p(c_char_p):
    pass


def check_string(result, func, cargs):
    if result:
        s = string_at(result)
        free(result)
    else:
        s = ''
    return s.decode(GEOIP_DEFAULT_ENCODING)

GeoIP_database_info = lgeoip.GeoIP_database_info
GeoIP_database_info.restype = geoip_char_p
GeoIP_database_info.errcheck = check_string


# String output routines.
def string_output(func):
    def _err_check(result, func, cargs):
        if result:
            return result.decode(GEOIP_DEFAULT_ENCODING)
        return result
    func.restype = c_char_p
    func.errcheck = _err_check
    return func

GeoIP_country_code_by_addr = string_output(lgeoip.GeoIP_country_code_by_addr)
GeoIP_country_code_by_name = string_output(lgeoip.GeoIP_country_code_by_name)
GeoIP_country_name_by_addr = string_output(lgeoip.GeoIP_country_name_by_addr)
GeoIP_country_name_by_name = string_output(lgeoip.GeoIP_country_name_by_name)