1
2 """Utility functions for handling XRIs.
3
4 @see: XRI Syntax v2.0 at the U{OASIS XRI Technical Committee<http://www.oasis-open.org/committees/tc_home.php?wg_abbrev=xri>}
5 """
6
7 import re
8
9 XRI_AUTHORITIES = ['!', '=', '@', '+', '$', '(']
10
11 try:
12 unichr(0x10000)
13 except ValueError:
14
15 UCSCHAR = [
16 (0xA0, 0xD7FF),
17 (0xF900, 0xFDCF),
18 (0xFDF0, 0xFFEF),
19 ]
20
21 IPRIVATE = [
22 (0xE000, 0xF8FF),
23 ]
24 else:
25 UCSCHAR = [
26 (0xA0, 0xD7FF),
27 (0xF900, 0xFDCF),
28 (0xFDF0, 0xFFEF),
29 (0x10000, 0x1FFFD),
30 (0x20000, 0x2FFFD),
31 (0x30000, 0x3FFFD),
32 (0x40000, 0x4FFFD),
33 (0x50000, 0x5FFFD),
34 (0x60000, 0x6FFFD),
35 (0x70000, 0x7FFFD),
36 (0x80000, 0x8FFFD),
37 (0x90000, 0x9FFFD),
38 (0xA0000, 0xAFFFD),
39 (0xB0000, 0xBFFFD),
40 (0xC0000, 0xCFFFD),
41 (0xD0000, 0xDFFFD),
42 (0xE1000, 0xEFFFD),
43 ]
44
45 IPRIVATE = [
46 (0xE000, 0xF8FF),
47 (0xF0000, 0xFFFFD),
48 (0x100000, 0x10FFFD),
49 ]
50
51
52 _escapeme_re = re.compile('[%s]' % (''.join(
53 map(lambda (m, n): u'%s-%s' % (unichr(m), unichr(n)),
54 UCSCHAR + IPRIVATE)),))
55
56
58 """Determine if this identifier is an XRI or URI.
59
60 @returns: C{"XRI"} or C{"URI"}
61 """
62 if identifier.startswith('xri://') or identifier[0] in XRI_AUTHORITIES:
63 return "XRI"
64 else:
65 return "URI"
66
67
69 """Transform an XRI to IRI-normal form."""
70 if not xri.startswith('xri://'):
71 xri = 'xri://' + xri
72 return escapeForIRI(xri)
73
74
75 _xref_re = re.compile('\((.*?)\)')
76
77
79 """Escape things that need to be escaped if they're in a cross-reference.
80 """
81 xref = xref_match.group()
82 xref = xref.replace('/', '%2F')
83 xref = xref.replace('?', '%3F')
84 xref = xref.replace('#', '%23')
85 return xref
86
87
93
94
98
99
101 c = char_match.group()
102 return ''.join(['%%%X' % (ord(octet),) for octet in c.encode('utf-8')])
103
104
109
110
112 """Is this provider ID authoritative for this XRI?
113
114 @returntype: bool
115 """
116
117 lastbang = canonicalID.rindex('!')
118 parent = canonicalID[:lastbang]
119 return parent == providerID
120
121
123 """Return the root authority for an XRI.
124
125 Example::
126
127 rootAuthority("xri://@example") == "xri://@"
128
129 @type xri: unicode
130 @returntype: unicode
131 """
132 if xri.startswith('xri://'):
133 xri = xri[6:]
134 authority = xri.split('/', 1)[0]
135 if authority[0] == '(':
136
137
138
139
140
141 root = authority[:authority.index(')') + 1]
142 elif authority[0] in XRI_AUTHORITIES:
143
144 root = authority[0]
145 else:
146
147 segments = authority.split('!')
148 segments = reduce(list.__add__,
149 map(lambda s: s.split('*'), segments))
150 root = segments[0]
151
152 return XRI(root)
153
154
156 """An XRI object allowing comparison of XRI.
157
158 Ideally, this would do full normalization and provide comparsion
159 operators as per XRI Syntax. Right now, it just does a bit of
160 canonicalization by ensuring the xri scheme is present.
161
162 @param xri: an xri string
163 @type xri: unicode
164 """
165 if not xri.startswith('xri://'):
166 xri = 'xri://' + xri
167 return xri
168