PYTHON   36

prototypes.py

Guest on 3rd June 2021 05:59:54 AM

  1. from ctypes import POINTER, Structure, c_char_p, c_float, c_int, string_at
  2.  
  3. from django.contrib.gis.geoip.libgeoip import free, lgeoip
  4.  
  5.  
  6. # #### GeoIP C Structure definitions ####
  7.  
  8. class GeoIPRecord(Structure):
  9.     _fields_ = [('country_code', c_char_p),
  10.                 ('country_code3', c_char_p),
  11.                 ('country_name', c_char_p),
  12.                 ('region', c_char_p),
  13.                 ('city', c_char_p),
  14.                 ('postal_code', c_char_p),
  15.                 ('latitude', c_float),
  16.                 ('longitude', c_float),
  17.                 # TODO: In 1.4.6 this changed from `int dma_code;` to
  18.                 # `union {int metro_code; int dma_code;};`.  Change
  19.                 # to a `ctypes.Union` in to accommodate in future when
  20.                 # pre-1.4.6 versions are no longer distributed.
  21.                 ('dma_code', c_int),
  22.                 ('area_code', c_int),
  23.                 ('charset', c_int),
  24.                 ('continent_code', c_char_p),
  25.                 ]
  26. geoip_char_fields = [name for name, ctype in GeoIPRecord._fields_ if ctype is c_char_p]
  27. GEOIP_DEFAULT_ENCODING = 'iso-8859-1'
  28. geoip_encodings = {
  29.     0: 'iso-8859-1',
  30.     1: 'utf8',
  31. }
  32.  
  33.  
  34. class GeoIPTag(Structure):
  35.     pass
  36.  
  37. RECTYPE = POINTER(GeoIPRecord)
  38. DBTYPE = POINTER(GeoIPTag)
  39.  
  40. # #### ctypes function prototypes ####
  41.  
  42. # GeoIP_lib_version appeared in version 1.4.7.
  43. if hasattr(lgeoip, 'GeoIP_lib_version'):
  44.     GeoIP_lib_version = lgeoip.GeoIP_lib_version
  45.     GeoIP_lib_version.argtypes = None
  46.     GeoIP_lib_version.restype = c_char_p
  47. else:
  48.     GeoIP_lib_version = None
  49.  
  50. # For freeing memory allocated within a record
  51. GeoIPRecord_delete = lgeoip.GeoIPRecord_delete
  52. GeoIPRecord_delete.argtypes = [RECTYPE]
  53. GeoIPRecord_delete.restype = None
  54.  
  55.  
  56. # For retrieving records by name or address.
  57. def check_record(result, func, cargs):
  58.     if result:
  59.         # Checking the pointer to the C structure, if valid pull out elements
  60.         # into a dictionary.
  61.         rec = result.contents
  62.         record = {fld: getattr(rec, fld) for fld, ctype in rec._fields_}
  63.  
  64.         # Now converting the strings to unicode using the proper encoding.
  65.         encoding = geoip_encodings[record['charset']]
  66.         for char_field in geoip_char_fields:
  67.             if record[char_field]:
  68.                 record[char_field] = record[char_field].decode(encoding)
  69.  
  70.         # Free the memory allocated for the struct & return.
  71.         GeoIPRecord_delete(result)
  72.         return record
  73.     else:
  74.         return None
  75.  
  76.  
  77. def record_output(func):
  78.     func.argtypes = [DBTYPE, c_char_p]
  79.     func.restype = RECTYPE
  80.     func.errcheck = check_record
  81.     return func
  82. GeoIP_record_by_addr = record_output(lgeoip.GeoIP_record_by_addr)
  83. GeoIP_record_by_name = record_output(lgeoip.GeoIP_record_by_name)
  84.  
  85.  
  86. # For opening & closing GeoIP database files.
  87. GeoIP_open = lgeoip.GeoIP_open
  88. GeoIP_open.restype = DBTYPE
  89. GeoIP_delete = lgeoip.GeoIP_delete
  90. GeoIP_delete.argtypes = [DBTYPE]
  91. GeoIP_delete.restype = None
  92.  
  93.  
  94. # This is so the string pointer can be freed within Python.
  95. class geoip_char_p(c_char_p):
  96.     pass
  97.  
  98.  
  99. def check_string(result, func, cargs):
  100.     if result:
  101.         s = string_at(result)
  102.         free(result)
  103.     else:
  104.         s = ''
  105.     return s.decode(GEOIP_DEFAULT_ENCODING)
  106.  
  107. GeoIP_database_info = lgeoip.GeoIP_database_info
  108. GeoIP_database_info.restype = geoip_char_p
  109. GeoIP_database_info.errcheck = check_string
  110.  
  111.  
  112. # String output routines.
  113. def string_output(func):
  114.     def _err_check(result, func, cargs):
  115.         if result:
  116.             return result.decode(GEOIP_DEFAULT_ENCODING)
  117.         return result
  118.     func.restype = c_char_p
  119.     func.errcheck = _err_check
  120.     return func
  121.  
  122. GeoIP_country_code_by_addr = string_output(lgeoip.GeoIP_country_code_by_addr)
  123. GeoIP_country_code_by_name = string_output(lgeoip.GeoIP_country_code_by_name)
  124. GeoIP_country_name_by_addr = string_output(lgeoip.GeoIP_country_name_by_addr)
  125. GeoIP_country_name_by_name = string_output(lgeoip.GeoIP_country_name_by_name)

Raw Paste


Login or Register to edit or fork this paste. It's free.