vis.py 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. """
  2. vis.py
  3. ======
  4. Ctypes based module to access libbsd's strvis & strunvis functions.
  5. The `vis` function is the equivalent of strvis.
  6. The `unvis` function is the equivalent of strunvis.
  7. All functions accept unicode string as input and return a unicode string.
  8. Constants:
  9. ----------
  10. * to select alternate encoding format
  11. `VIS_OCTAL`: use octal \ddd format
  12. `VIS_CSTYLE`: use \[nrft0..] where appropiate
  13. * to alter set of characters encoded
  14. (default is to encode all non-graphic except space, tab, and newline).
  15. `VIS_SP`: also encode space
  16. `VIS_TAB`: also encode tab
  17. `VIS_NL`: also encode newline
  18. `VIS_WHITE`: same as (VIS_SP | VIS_TAB | VIS_NL)
  19. `VIS_SAFE`: only encode "unsafe" characters
  20. * other
  21. `VIS_NOSLASH`: inhibit printing '\'
  22. `VIS_HTTP1808`: http-style escape % hex hex
  23. `VIS_HTTPSTYLE`: http-style escape % hex hex
  24. `VIS_MIMESTYLE`: mime-style escape = HEX HEX
  25. `VIS_HTTP1866`: http-style &#num; or &string;
  26. `VIS_NOESCAPE`: don't decode `\'
  27. `VIS_GLOB`: encode glob(3) magic characters
  28. :Authors:
  29. - ju1ius (http://github.com/ju1ius)
  30. :Version: 1
  31. :Date: 2014-01-05
  32. """
  33. from ctypes import CDLL, c_char_p, c_int
  34. from ctypes.util import find_library
  35. __all__ = [
  36. 'vis', 'unvis',
  37. 'VIS_OCTAL', 'VIS_CSTYLE',
  38. 'VIS_SP', 'VIS_TAB', 'VIS_NL', 'VIS_WHITE', 'VIS_SAFE',
  39. 'VIS_NOSLASH', 'VIS_HTTP1808', 'VIS_HTTPSTYLE', 'VIS_MIMESTYLE',
  40. 'VIS_HTTP1866', 'VIS_NOESCAPE', 'VIS_GLOB'
  41. ]
  42. #############################################################
  43. # Constants from bsd/vis.h
  44. #############################################################
  45. #to select alternate encoding format
  46. VIS_OCTAL = 0x0001
  47. VIS_CSTYLE = 0x0002
  48. # to alter set of characters encoded
  49. # (default is to encode all non-graphic except space, tab, and newline).
  50. VIS_SP = 0x0004
  51. VIS_TAB = 0x0008
  52. VIS_NL = 0x0010
  53. VIS_WHITE = VIS_SP | VIS_TAB | VIS_NL
  54. VIS_SAFE = 0x0020
  55. # other
  56. VIS_NOSLASH = 0x0040
  57. VIS_HTTP1808 = 0x0080
  58. VIS_HTTPSTYLE = 0x0080
  59. VIS_MIMESTYLE = 0x0100
  60. VIS_HTTP1866 = 0x0200
  61. VIS_NOESCAPE = 0x0400
  62. VIS_GLOB = 0x1000
  63. #############################################################
  64. # Import libbsd/vis functions
  65. #############################################################
  66. _libbsd = CDLL(find_library('bsd'))
  67. _strvis = _libbsd.strvis
  68. _strvis.argtypes = [c_char_p, c_char_p, c_int]
  69. _strvis.restype = c_int
  70. _strunvis = _libbsd.strunvis
  71. _strvis.argtypes = [c_char_p, c_char_p]
  72. _strvis.restype = c_int
  73. def vis(src, flags=VIS_WHITE):
  74. """
  75. Encodes the string `src` into libbsd's vis encoding.
  76. `flags` must be one of the VIS_* constants
  77. C definition:
  78. int strvis(char *dst, char *src, int flags);
  79. """
  80. src = bytes(src, 'utf-8')
  81. dst_p = c_char_p(bytes(len(src) * 4))
  82. src_p = c_char_p(src)
  83. flags = c_int(flags)
  84. bytes_written = _strvis(dst_p, src_p, flags)
  85. if -1 == bytes_written:
  86. raise RuntimeError('vis failed to encode string "{}"'.format(src))
  87. return dst_p.value.decode('utf-8')
  88. def unvis(src):
  89. """
  90. Decodes a string encoded by vis.
  91. C definition:
  92. int strunvis(char *dst, char *src);
  93. """
  94. src = bytes(src, 'utf-8')
  95. dst_p = c_char_p(bytes(len(src)))
  96. src_p = c_char_p(src)
  97. bytes_written = _strunvis(dst_p, src_p)
  98. if -1 == bytes_written:
  99. raise RuntimeError('unvis failed to decode string "{}"'.format(src))
  100. return dst_p.value.decode('utf-8')