##// END OF EJS Templates
pathencode: allow clang-format oversight...
Augie Fackler -
r36073:44cb058b default
parent child Browse files
Show More
@@ -1,60 +1,59
1 # Files that just need to be migrated to the formatter.
1 # Files that just need to be migrated to the formatter.
2 # Do not add new files here!
2 # Do not add new files here!
3 mercurial/cext/base85.c
3 mercurial/cext/base85.c
4 mercurial/cext/charencode.c
4 mercurial/cext/charencode.c
5 mercurial/cext/charencode.h
5 mercurial/cext/charencode.h
6 mercurial/cext/diffhelpers.c
6 mercurial/cext/diffhelpers.c
7 mercurial/cext/dirs.c
7 mercurial/cext/dirs.c
8 mercurial/cext/manifest.c
8 mercurial/cext/manifest.c
9 mercurial/cext/mpatch.c
9 mercurial/cext/mpatch.c
10 mercurial/cext/osutil.c
10 mercurial/cext/osutil.c
11 mercurial/cext/pathencode.c
12 mercurial/cext/revlog.c
11 mercurial/cext/revlog.c
13 # Vendored code that we should never format:
12 # Vendored code that we should never format:
14 contrib/python-zstandard/c-ext/bufferutil.c
13 contrib/python-zstandard/c-ext/bufferutil.c
15 contrib/python-zstandard/c-ext/compressiondict.c
14 contrib/python-zstandard/c-ext/compressiondict.c
16 contrib/python-zstandard/c-ext/compressionparams.c
15 contrib/python-zstandard/c-ext/compressionparams.c
17 contrib/python-zstandard/c-ext/compressionwriter.c
16 contrib/python-zstandard/c-ext/compressionwriter.c
18 contrib/python-zstandard/c-ext/compressobj.c
17 contrib/python-zstandard/c-ext/compressobj.c
19 contrib/python-zstandard/c-ext/compressor.c
18 contrib/python-zstandard/c-ext/compressor.c
20 contrib/python-zstandard/c-ext/compressoriterator.c
19 contrib/python-zstandard/c-ext/compressoriterator.c
21 contrib/python-zstandard/c-ext/constants.c
20 contrib/python-zstandard/c-ext/constants.c
22 contrib/python-zstandard/c-ext/decompressionwriter.c
21 contrib/python-zstandard/c-ext/decompressionwriter.c
23 contrib/python-zstandard/c-ext/decompressobj.c
22 contrib/python-zstandard/c-ext/decompressobj.c
24 contrib/python-zstandard/c-ext/decompressor.c
23 contrib/python-zstandard/c-ext/decompressor.c
25 contrib/python-zstandard/c-ext/decompressoriterator.c
24 contrib/python-zstandard/c-ext/decompressoriterator.c
26 contrib/python-zstandard/c-ext/frameparams.c
25 contrib/python-zstandard/c-ext/frameparams.c
27 contrib/python-zstandard/c-ext/python-zstandard.h
26 contrib/python-zstandard/c-ext/python-zstandard.h
28 contrib/python-zstandard/zstd.c
27 contrib/python-zstandard/zstd.c
29 contrib/python-zstandard/zstd/common/bitstream.h
28 contrib/python-zstandard/zstd/common/bitstream.h
30 contrib/python-zstandard/zstd/common/entropy_common.c
29 contrib/python-zstandard/zstd/common/entropy_common.c
31 contrib/python-zstandard/zstd/common/error_private.c
30 contrib/python-zstandard/zstd/common/error_private.c
32 contrib/python-zstandard/zstd/common/error_private.h
31 contrib/python-zstandard/zstd/common/error_private.h
33 contrib/python-zstandard/zstd/common/fse.h
32 contrib/python-zstandard/zstd/common/fse.h
34 contrib/python-zstandard/zstd/common/fse_decompress.c
33 contrib/python-zstandard/zstd/common/fse_decompress.c
35 contrib/python-zstandard/zstd/common/huf.h
34 contrib/python-zstandard/zstd/common/huf.h
36 contrib/python-zstandard/zstd/common/mem.h
35 contrib/python-zstandard/zstd/common/mem.h
37 contrib/python-zstandard/zstd/common/pool.c
36 contrib/python-zstandard/zstd/common/pool.c
38 contrib/python-zstandard/zstd/common/pool.h
37 contrib/python-zstandard/zstd/common/pool.h
39 contrib/python-zstandard/zstd/common/threading.c
38 contrib/python-zstandard/zstd/common/threading.c
40 contrib/python-zstandard/zstd/common/threading.h
39 contrib/python-zstandard/zstd/common/threading.h
41 contrib/python-zstandard/zstd/common/xxhash.c
40 contrib/python-zstandard/zstd/common/xxhash.c
42 contrib/python-zstandard/zstd/common/xxhash.h
41 contrib/python-zstandard/zstd/common/xxhash.h
43 contrib/python-zstandard/zstd/common/zstd_common.c
42 contrib/python-zstandard/zstd/common/zstd_common.c
44 contrib/python-zstandard/zstd/common/zstd_errors.h
43 contrib/python-zstandard/zstd/common/zstd_errors.h
45 contrib/python-zstandard/zstd/common/zstd_internal.h
44 contrib/python-zstandard/zstd/common/zstd_internal.h
46 contrib/python-zstandard/zstd/compress/fse_compress.c
45 contrib/python-zstandard/zstd/compress/fse_compress.c
47 contrib/python-zstandard/zstd/compress/huf_compress.c
46 contrib/python-zstandard/zstd/compress/huf_compress.c
48 contrib/python-zstandard/zstd/compress/zstd_compress.c
47 contrib/python-zstandard/zstd/compress/zstd_compress.c
49 contrib/python-zstandard/zstd/compress/zstd_opt.h
48 contrib/python-zstandard/zstd/compress/zstd_opt.h
50 contrib/python-zstandard/zstd/compress/zstdmt_compress.c
49 contrib/python-zstandard/zstd/compress/zstdmt_compress.c
51 contrib/python-zstandard/zstd/compress/zstdmt_compress.h
50 contrib/python-zstandard/zstd/compress/zstdmt_compress.h
52 contrib/python-zstandard/zstd/decompress/huf_decompress.c
51 contrib/python-zstandard/zstd/decompress/huf_decompress.c
53 contrib/python-zstandard/zstd/decompress/zstd_decompress.c
52 contrib/python-zstandard/zstd/decompress/zstd_decompress.c
54 contrib/python-zstandard/zstd/dictBuilder/cover.c
53 contrib/python-zstandard/zstd/dictBuilder/cover.c
55 contrib/python-zstandard/zstd/dictBuilder/divsufsort.c
54 contrib/python-zstandard/zstd/dictBuilder/divsufsort.c
56 contrib/python-zstandard/zstd/dictBuilder/divsufsort.h
55 contrib/python-zstandard/zstd/dictBuilder/divsufsort.h
57 contrib/python-zstandard/zstd/dictBuilder/zdict.c
56 contrib/python-zstandard/zstd/dictBuilder/zdict.c
58 contrib/python-zstandard/zstd/dictBuilder/zdict.h
57 contrib/python-zstandard/zstd/dictBuilder/zdict.h
59 contrib/python-zstandard/zstd/zstd.h
58 contrib/python-zstandard/zstd/zstd.h
60 hgext/fsmonitor/pywatchman/bser.c
59 hgext/fsmonitor/pywatchman/bser.c
@@ -1,765 +1,763
1 /*
1 /*
2 pathencode.c - efficient path name encoding
2 pathencode.c - efficient path name encoding
3
3
4 Copyright 2012 Facebook
4 Copyright 2012 Facebook
5
5
6 This software may be used and distributed according to the terms of
6 This software may be used and distributed according to the terms of
7 the GNU General Public License, incorporated herein by reference.
7 the GNU General Public License, incorporated herein by reference.
8 */
8 */
9
9
10 /*
10 /*
11 * An implementation of the name encoding scheme used by the fncache
11 * An implementation of the name encoding scheme used by the fncache
12 * store. The common case is of a path < 120 bytes long, which is
12 * store. The common case is of a path < 120 bytes long, which is
13 * handled either in a single pass with no allocations or two passes
13 * handled either in a single pass with no allocations or two passes
14 * with a single allocation. For longer paths, multiple passes are
14 * with a single allocation. For longer paths, multiple passes are
15 * required.
15 * required.
16 */
16 */
17
17
18 #define PY_SSIZE_T_CLEAN
18 #define PY_SSIZE_T_CLEAN
19 #include <Python.h>
19 #include <Python.h>
20 #include <assert.h>
20 #include <assert.h>
21 #include <ctype.h>
21 #include <ctype.h>
22 #include <stdlib.h>
22 #include <stdlib.h>
23 #include <string.h>
23 #include <string.h>
24
24
25 #include "util.h"
25 #include "util.h"
26
26
27 /* state machine for the fast path */
27 /* state machine for the fast path */
28 enum path_state {
28 enum path_state {
29 START, /* first byte of a path component */
29 START, /* first byte of a path component */
30 A, /* "AUX" */
30 A, /* "AUX" */
31 AU,
31 AU,
32 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
32 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
33 C, /* "CON" or "COMn" */
33 C, /* "CON" or "COMn" */
34 CO,
34 CO,
35 COMLPT, /* "COM" or "LPT" */
35 COMLPT, /* "COM" or "LPT" */
36 COMLPTn,
36 COMLPTn,
37 L,
37 L,
38 LP,
38 LP,
39 N,
39 N,
40 NU,
40 NU,
41 P, /* "PRN" */
41 P, /* "PRN" */
42 PR,
42 PR,
43 LDOT, /* leading '.' */
43 LDOT, /* leading '.' */
44 DOT, /* '.' in a non-leading position */
44 DOT, /* '.' in a non-leading position */
45 H, /* ".h" */
45 H, /* ".h" */
46 HGDI, /* ".hg", ".d", or ".i" */
46 HGDI, /* ".hg", ".d", or ".i" */
47 SPACE,
47 SPACE,
48 DEFAULT /* byte of a path component after the first */
48 DEFAULT, /* byte of a path component after the first */
49 };
49 };
50
50
51 /* state machine for dir-encoding */
51 /* state machine for dir-encoding */
52 enum dir_state {
52 enum dir_state {
53 DDOT,
53 DDOT,
54 DH,
54 DH,
55 DHGDI,
55 DHGDI,
56 DDEFAULT
56 DDEFAULT,
57 };
57 };
58
58
59 static inline int inset(const uint32_t bitset[], char c)
59 static inline int inset(const uint32_t bitset[], char c)
60 {
60 {
61 return bitset[((uint8_t)c) >> 5] & (1 << (((uint8_t)c) & 31));
61 return bitset[((uint8_t)c) >> 5] & (1 << (((uint8_t)c) & 31));
62 }
62 }
63
63
64 static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
64 static inline void charcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
65 char c)
65 char c)
66 {
66 {
67 if (dest) {
67 if (dest) {
68 assert(*destlen < destsize);
68 assert(*destlen < destsize);
69 dest[*destlen] = c;
69 dest[*destlen] = c;
70 }
70 }
71 (*destlen)++;
71 (*destlen)++;
72 }
72 }
73
73
74 static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
74 static inline void memcopy(char *dest, Py_ssize_t *destlen, size_t destsize,
75 const void *src, Py_ssize_t len)
75 const void *src, Py_ssize_t len)
76 {
76 {
77 if (dest) {
77 if (dest) {
78 assert(*destlen + len < destsize);
78 assert(*destlen + len < destsize);
79 memcpy((void *)&dest[*destlen], src, len);
79 memcpy((void *)&dest[*destlen], src, len);
80 }
80 }
81 *destlen += len;
81 *destlen += len;
82 }
82 }
83
83
84 static inline void hexencode(char *dest, Py_ssize_t *destlen, size_t destsize,
84 static inline void hexencode(char *dest, Py_ssize_t *destlen, size_t destsize,
85 uint8_t c)
85 uint8_t c)
86 {
86 {
87 static const char hexdigit[] = "0123456789abcdef";
87 static const char hexdigit[] = "0123456789abcdef";
88
88
89 charcopy(dest, destlen, destsize, hexdigit[c >> 4]);
89 charcopy(dest, destlen, destsize, hexdigit[c >> 4]);
90 charcopy(dest, destlen, destsize, hexdigit[c & 15]);
90 charcopy(dest, destlen, destsize, hexdigit[c & 15]);
91 }
91 }
92
92
93 /* 3-byte escape: tilde followed by two hex digits */
93 /* 3-byte escape: tilde followed by two hex digits */
94 static inline void escape3(char *dest, Py_ssize_t *destlen, size_t destsize,
94 static inline void escape3(char *dest, Py_ssize_t *destlen, size_t destsize,
95 char c)
95 char c)
96 {
96 {
97 charcopy(dest, destlen, destsize, '~');
97 charcopy(dest, destlen, destsize, '~');
98 hexencode(dest, destlen, destsize, c);
98 hexencode(dest, destlen, destsize, c);
99 }
99 }
100
100
101 static Py_ssize_t _encodedir(char *dest, size_t destsize,
101 static Py_ssize_t _encodedir(char *dest, size_t destsize, const char *src,
102 const char *src, Py_ssize_t len)
102 Py_ssize_t len)
103 {
103 {
104 enum dir_state state = DDEFAULT;
104 enum dir_state state = DDEFAULT;
105 Py_ssize_t i = 0, destlen = 0;
105 Py_ssize_t i = 0, destlen = 0;
106
106
107 while (i < len) {
107 while (i < len) {
108 switch (state) {
108 switch (state) {
109 case DDOT:
109 case DDOT:
110 switch (src[i]) {
110 switch (src[i]) {
111 case 'd':
111 case 'd':
112 case 'i':
112 case 'i':
113 state = DHGDI;
113 state = DHGDI;
114 charcopy(dest, &destlen, destsize, src[i++]);
114 charcopy(dest, &destlen, destsize, src[i++]);
115 break;
115 break;
116 case 'h':
116 case 'h':
117 state = DH;
117 state = DH;
118 charcopy(dest, &destlen, destsize, src[i++]);
118 charcopy(dest, &destlen, destsize, src[i++]);
119 break;
119 break;
120 default:
120 default:
121 state = DDEFAULT;
121 state = DDEFAULT;
122 break;
122 break;
123 }
123 }
124 break;
124 break;
125 case DH:
125 case DH:
126 if (src[i] == 'g') {
126 if (src[i] == 'g') {
127 state = DHGDI;
127 state = DHGDI;
128 charcopy(dest, &destlen, destsize, src[i++]);
128 charcopy(dest, &destlen, destsize, src[i++]);
129 }
129 } else
130 else state = DDEFAULT;
130 state = DDEFAULT;
131 break;
131 break;
132 case DHGDI:
132 case DHGDI:
133 if (src[i] == '/') {
133 if (src[i] == '/') {
134 memcopy(dest, &destlen, destsize, ".hg", 3);
134 memcopy(dest, &destlen, destsize, ".hg", 3);
135 charcopy(dest, &destlen, destsize, src[i++]);
135 charcopy(dest, &destlen, destsize, src[i++]);
136 }
136 }
137 state = DDEFAULT;
137 state = DDEFAULT;
138 break;
138 break;
139 case DDEFAULT:
139 case DDEFAULT:
140 if (src[i] == '.')
140 if (src[i] == '.')
141 state = DDOT;
141 state = DDOT;
142 charcopy(dest, &destlen, destsize, src[i++]);
142 charcopy(dest, &destlen, destsize, src[i++]);
143 break;
143 break;
144 }
144 }
145 }
145 }
146
146
147 return destlen;
147 return destlen;
148 }
148 }
149
149
150 PyObject *encodedir(PyObject *self, PyObject *args)
150 PyObject *encodedir(PyObject *self, PyObject *args)
151 {
151 {
152 Py_ssize_t len, newlen;
152 Py_ssize_t len, newlen;
153 PyObject *pathobj, *newobj;
153 PyObject *pathobj, *newobj;
154 char *path;
154 char *path;
155
155
156 if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj))
156 if (!PyArg_ParseTuple(args, "O:encodedir", &pathobj))
157 return NULL;
157 return NULL;
158
158
159 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
159 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
160 PyErr_SetString(PyExc_TypeError, "expected a string");
160 PyErr_SetString(PyExc_TypeError, "expected a string");
161 return NULL;
161 return NULL;
162 }
162 }
163
163
164 newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1;
164 newlen = len ? _encodedir(NULL, 0, path, len + 1) : 1;
165
165
166 if (newlen == len + 1) {
166 if (newlen == len + 1) {
167 Py_INCREF(pathobj);
167 Py_INCREF(pathobj);
168 return pathobj;
168 return pathobj;
169 }
169 }
170
170
171 newobj = PyBytes_FromStringAndSize(NULL, newlen);
171 newobj = PyBytes_FromStringAndSize(NULL, newlen);
172
172
173 if (newobj) {
173 if (newobj) {
174 assert(PyBytes_Check(newobj));
174 assert(PyBytes_Check(newobj));
175 Py_SIZE(newobj)--;
175 Py_SIZE(newobj)--;
176 _encodedir(PyBytes_AS_STRING(newobj), newlen, path,
176 _encodedir(PyBytes_AS_STRING(newobj), newlen, path, len + 1);
177 len + 1);
178 }
177 }
179
178
180 return newobj;
179 return newobj;
181 }
180 }
182
181
183 static Py_ssize_t _encode(const uint32_t twobytes[8], const uint32_t onebyte[8],
182 static Py_ssize_t _encode(const uint32_t twobytes[8], const uint32_t onebyte[8],
184 char *dest, Py_ssize_t destlen, size_t destsize,
183 char *dest, Py_ssize_t destlen, size_t destsize,
185 const char *src, Py_ssize_t len,
184 const char *src, Py_ssize_t len, int encodedir)
186 int encodedir)
187 {
185 {
188 enum path_state state = START;
186 enum path_state state = START;
189 Py_ssize_t i = 0;
187 Py_ssize_t i = 0;
190
188
191 /*
189 /*
192 * Python strings end with a zero byte, which we use as a
190 * Python strings end with a zero byte, which we use as a
193 * terminal token as they are not valid inside path names.
191 * terminal token as they are not valid inside path names.
194 */
192 */
195
193
196 while (i < len) {
194 while (i < len) {
197 switch (state) {
195 switch (state) {
198 case START:
196 case START:
199 switch (src[i]) {
197 switch (src[i]) {
200 case '/':
198 case '/':
201 charcopy(dest, &destlen, destsize, src[i++]);
199 charcopy(dest, &destlen, destsize, src[i++]);
202 break;
200 break;
203 case '.':
201 case '.':
204 state = LDOT;
202 state = LDOT;
205 escape3(dest, &destlen, destsize, src[i++]);
203 escape3(dest, &destlen, destsize, src[i++]);
206 break;
204 break;
207 case ' ':
205 case ' ':
208 state = DEFAULT;
206 state = DEFAULT;
209 escape3(dest, &destlen, destsize, src[i++]);
207 escape3(dest, &destlen, destsize, src[i++]);
210 break;
208 break;
211 case 'a':
209 case 'a':
212 state = A;
210 state = A;
213 charcopy(dest, &destlen, destsize, src[i++]);
211 charcopy(dest, &destlen, destsize, src[i++]);
214 break;
212 break;
215 case 'c':
213 case 'c':
216 state = C;
214 state = C;
217 charcopy(dest, &destlen, destsize, src[i++]);
215 charcopy(dest, &destlen, destsize, src[i++]);
218 break;
216 break;
219 case 'l':
217 case 'l':
220 state = L;
218 state = L;
221 charcopy(dest, &destlen, destsize, src[i++]);
219 charcopy(dest, &destlen, destsize, src[i++]);
222 break;
220 break;
223 case 'n':
221 case 'n':
224 state = N;
222 state = N;
225 charcopy(dest, &destlen, destsize, src[i++]);
223 charcopy(dest, &destlen, destsize, src[i++]);
226 break;
224 break;
227 case 'p':
225 case 'p':
228 state = P;
226 state = P;
229 charcopy(dest, &destlen, destsize, src[i++]);
227 charcopy(dest, &destlen, destsize, src[i++]);
230 break;
228 break;
231 default:
229 default:
232 state = DEFAULT;
230 state = DEFAULT;
233 break;
231 break;
234 }
232 }
235 break;
233 break;
236 case A:
234 case A:
237 if (src[i] == 'u') {
235 if (src[i] == 'u') {
238 state = AU;
236 state = AU;
239 charcopy(dest, &destlen, destsize, src[i++]);
237 charcopy(dest, &destlen, destsize, src[i++]);
240 }
238 } else
241 else state = DEFAULT;
239 state = DEFAULT;
242 break;
240 break;
243 case AU:
241 case AU:
244 if (src[i] == 'x') {
242 if (src[i] == 'x') {
245 state = THIRD;
243 state = THIRD;
246 i++;
244 i++;
247 }
245 } else
248 else state = DEFAULT;
246 state = DEFAULT;
249 break;
247 break;
250 case THIRD:
248 case THIRD:
251 state = DEFAULT;
249 state = DEFAULT;
252 switch (src[i]) {
250 switch (src[i]) {
253 case '.':
251 case '.':
254 case '/':
252 case '/':
255 case '\0':
253 case '\0':
256 escape3(dest, &destlen, destsize, src[i - 1]);
254 escape3(dest, &destlen, destsize, src[i - 1]);
257 break;
255 break;
258 default:
256 default:
259 i--;
257 i--;
260 break;
258 break;
261 }
259 }
262 break;
260 break;
263 case C:
261 case C:
264 if (src[i] == 'o') {
262 if (src[i] == 'o') {
265 state = CO;
263 state = CO;
266 charcopy(dest, &destlen, destsize, src[i++]);
264 charcopy(dest, &destlen, destsize, src[i++]);
267 }
265 } else
268 else state = DEFAULT;
266 state = DEFAULT;
269 break;
267 break;
270 case CO:
268 case CO:
271 if (src[i] == 'm') {
269 if (src[i] == 'm') {
272 state = COMLPT;
270 state = COMLPT;
273 i++;
271 i++;
274 }
272 } else if (src[i] == 'n') {
275 else if (src[i] == 'n') {
276 state = THIRD;
273 state = THIRD;
277 i++;
274 i++;
278 }
275 } else
279 else state = DEFAULT;
276 state = DEFAULT;
280 break;
277 break;
281 case COMLPT:
278 case COMLPT:
282 switch (src[i]) {
279 switch (src[i]) {
283 case '1': case '2': case '3': case '4': case '5':
280 case '1':
284 case '6': case '7': case '8': case '9':
281 case '2':
282 case '3':
283 case '4':
284 case '5':
285 case '6':
286 case '7':
287 case '8':
288 case '9':
285 state = COMLPTn;
289 state = COMLPTn;
286 i++;
290 i++;
287 break;
291 break;
288 default:
292 default:
289 state = DEFAULT;
293 state = DEFAULT;
290 charcopy(dest, &destlen, destsize, src[i - 1]);
294 charcopy(dest, &destlen, destsize, src[i - 1]);
291 break;
295 break;
292 }
296 }
293 break;
297 break;
294 case COMLPTn:
298 case COMLPTn:
295 state = DEFAULT;
299 state = DEFAULT;
296 switch (src[i]) {
300 switch (src[i]) {
297 case '.':
301 case '.':
298 case '/':
302 case '/':
299 case '\0':
303 case '\0':
300 escape3(dest, &destlen, destsize, src[i - 2]);
304 escape3(dest, &destlen, destsize, src[i - 2]);
301 charcopy(dest, &destlen, destsize, src[i - 1]);
305 charcopy(dest, &destlen, destsize, src[i - 1]);
302 break;
306 break;
303 default:
307 default:
304 memcopy(dest, &destlen, destsize,
308 memcopy(dest, &destlen, destsize, &src[i - 2],
305 &src[i - 2], 2);
309 2);
306 break;
310 break;
307 }
311 }
308 break;
312 break;
309 case L:
313 case L:
310 if (src[i] == 'p') {
314 if (src[i] == 'p') {
311 state = LP;
315 state = LP;
312 charcopy(dest, &destlen, destsize, src[i++]);
316 charcopy(dest, &destlen, destsize, src[i++]);
313 }
317 } else
314 else state = DEFAULT;
318 state = DEFAULT;
315 break;
319 break;
316 case LP:
320 case LP:
317 if (src[i] == 't') {
321 if (src[i] == 't') {
318 state = COMLPT;
322 state = COMLPT;
319 i++;
323 i++;
320 }
324 } else
321 else state = DEFAULT;
325 state = DEFAULT;
322 break;
326 break;
323 case N:
327 case N:
324 if (src[i] == 'u') {
328 if (src[i] == 'u') {
325 state = NU;
329 state = NU;
326 charcopy(dest, &destlen, destsize, src[i++]);
330 charcopy(dest, &destlen, destsize, src[i++]);
327 }
331 } else
328 else state = DEFAULT;
332 state = DEFAULT;
329 break;
333 break;
330 case NU:
334 case NU:
331 if (src[i] == 'l') {
335 if (src[i] == 'l') {
332 state = THIRD;
336 state = THIRD;
333 i++;
337 i++;
334 }
338 } else
335 else state = DEFAULT;
339 state = DEFAULT;
336 break;
340 break;
337 case P:
341 case P:
338 if (src[i] == 'r') {
342 if (src[i] == 'r') {
339 state = PR;
343 state = PR;
340 charcopy(dest, &destlen, destsize, src[i++]);
344 charcopy(dest, &destlen, destsize, src[i++]);
341 }
345 } else
342 else state = DEFAULT;
346 state = DEFAULT;
343 break;
347 break;
344 case PR:
348 case PR:
345 if (src[i] == 'n') {
349 if (src[i] == 'n') {
346 state = THIRD;
350 state = THIRD;
347 i++;
351 i++;
348 }
352 } else
349 else state = DEFAULT;
353 state = DEFAULT;
350 break;
354 break;
351 case LDOT:
355 case LDOT:
352 switch (src[i]) {
356 switch (src[i]) {
353 case 'd':
357 case 'd':
354 case 'i':
358 case 'i':
355 state = HGDI;
359 state = HGDI;
356 charcopy(dest, &destlen, destsize, src[i++]);
360 charcopy(dest, &destlen, destsize, src[i++]);
357 break;
361 break;
358 case 'h':
362 case 'h':
359 state = H;
363 state = H;
360 charcopy(dest, &destlen, destsize, src[i++]);
364 charcopy(dest, &destlen, destsize, src[i++]);
361 break;
365 break;
362 default:
366 default:
363 state = DEFAULT;
367 state = DEFAULT;
364 break;
368 break;
365 }
369 }
366 break;
370 break;
367 case DOT:
371 case DOT:
368 switch (src[i]) {
372 switch (src[i]) {
369 case '/':
373 case '/':
370 case '\0':
374 case '\0':
371 state = START;
375 state = START;
372 memcopy(dest, &destlen, destsize, "~2e", 3);
376 memcopy(dest, &destlen, destsize, "~2e", 3);
373 charcopy(dest, &destlen, destsize, src[i++]);
377 charcopy(dest, &destlen, destsize, src[i++]);
374 break;
378 break;
375 case 'd':
379 case 'd':
376 case 'i':
380 case 'i':
377 state = HGDI;
381 state = HGDI;
378 charcopy(dest, &destlen, destsize, '.');
382 charcopy(dest, &destlen, destsize, '.');
379 charcopy(dest, &destlen, destsize, src[i++]);
383 charcopy(dest, &destlen, destsize, src[i++]);
380 break;
384 break;
381 case 'h':
385 case 'h':
382 state = H;
386 state = H;
383 memcopy(dest, &destlen, destsize, ".h", 2);
387 memcopy(dest, &destlen, destsize, ".h", 2);
384 i++;
388 i++;
385 break;
389 break;
386 default:
390 default:
387 state = DEFAULT;
391 state = DEFAULT;
388 charcopy(dest, &destlen, destsize, '.');
392 charcopy(dest, &destlen, destsize, '.');
389 break;
393 break;
390 }
394 }
391 break;
395 break;
392 case H:
396 case H:
393 if (src[i] == 'g') {
397 if (src[i] == 'g') {
394 state = HGDI;
398 state = HGDI;
395 charcopy(dest, &destlen, destsize, src[i++]);
399 charcopy(dest, &destlen, destsize, src[i++]);
396 }
400 } else
397 else state = DEFAULT;
401 state = DEFAULT;
398 break;
402 break;
399 case HGDI:
403 case HGDI:
400 if (src[i] == '/') {
404 if (src[i] == '/') {
401 state = START;
405 state = START;
402 if (encodedir)
406 if (encodedir)
403 memcopy(dest, &destlen, destsize, ".hg",
407 memcopy(dest, &destlen, destsize, ".hg",
404 3);
408 3);
405 charcopy(dest, &destlen, destsize, src[i++]);
409 charcopy(dest, &destlen, destsize, src[i++]);
406 }
410 } else
407 else state = DEFAULT;
411 state = DEFAULT;
408 break;
412 break;
409 case SPACE:
413 case SPACE:
410 switch (src[i]) {
414 switch (src[i]) {
411 case '/':
415 case '/':
412 case '\0':
416 case '\0':
413 state = START;
417 state = START;
414 memcopy(dest, &destlen, destsize, "~20", 3);
418 memcopy(dest, &destlen, destsize, "~20", 3);
415 charcopy(dest, &destlen, destsize, src[i++]);
419 charcopy(dest, &destlen, destsize, src[i++]);
416 break;
420 break;
417 default:
421 default:
418 state = DEFAULT;
422 state = DEFAULT;
419 charcopy(dest, &destlen, destsize, ' ');
423 charcopy(dest, &destlen, destsize, ' ');
420 break;
424 break;
421 }
425 }
422 break;
426 break;
423 case DEFAULT:
427 case DEFAULT:
424 while (inset(onebyte, src[i])) {
428 while (inset(onebyte, src[i])) {
425 charcopy(dest, &destlen, destsize, src[i++]);
429 charcopy(dest, &destlen, destsize, src[i++]);
426 if (i == len)
430 if (i == len)
427 goto done;
431 goto done;
428 }
432 }
429 switch (src[i]) {
433 switch (src[i]) {
430 case '.':
434 case '.':
431 state = DOT;
435 state = DOT;
432 i++;
436 i++;
433 break;
437 break;
434 case ' ':
438 case ' ':
435 state = SPACE;
439 state = SPACE;
436 i++;
440 i++;
437 break;
441 break;
438 case '/':
442 case '/':
439 state = START;
443 state = START;
440 charcopy(dest, &destlen, destsize, '/');
444 charcopy(dest, &destlen, destsize, '/');
441 i++;
445 i++;
442 break;
446 break;
443 default:
447 default:
444 if (inset(onebyte, src[i])) {
448 if (inset(onebyte, src[i])) {
445 do {
449 do {
446 charcopy(dest, &destlen,
450 charcopy(dest, &destlen,
447 destsize, src[i++]);
451 destsize, src[i++]);
448 } while (i < len &&
452 } while (i < len &&
449 inset(onebyte, src[i]));
453 inset(onebyte, src[i]));
450 }
454 } else if (inset(twobytes, src[i])) {
451 else if (inset(twobytes, src[i])) {
452 char c = src[i++];
455 char c = src[i++];
453 charcopy(dest, &destlen, destsize, '_');
456 charcopy(dest, &destlen, destsize, '_');
454 charcopy(dest, &destlen, destsize,
457 charcopy(dest, &destlen, destsize,
455 c == '_' ? '_' : c + 32);
458 c == '_' ? '_' : c + 32);
456 }
459 } else
457 else
458 escape3(dest, &destlen, destsize,
460 escape3(dest, &destlen, destsize,
459 src[i++]);
461 src[i++]);
460 break;
462 break;
461 }
463 }
462 break;
464 break;
463 }
465 }
464 }
466 }
465 done:
467 done:
466 return destlen;
468 return destlen;
467 }
469 }
468
470
469 static Py_ssize_t basicencode(char *dest, size_t destsize,
471 static Py_ssize_t basicencode(char *dest, size_t destsize, const char *src,
470 const char *src, Py_ssize_t len)
472 Py_ssize_t len)
471 {
473 {
472 static const uint32_t twobytes[8] = { 0, 0, 0x87fffffe };
474 static const uint32_t twobytes[8] = {0, 0, 0x87fffffe};
473
475
474 static const uint32_t onebyte[8] = {
476 static const uint32_t onebyte[8] = {
475 1, 0x2bff3bfa, 0x68000001, 0x2fffffff,
477 1, 0x2bff3bfa, 0x68000001, 0x2fffffff,
476 };
478 };
477
479
478 Py_ssize_t destlen = 0;
480 Py_ssize_t destlen = 0;
479
481
480 return _encode(twobytes, onebyte, dest, destlen, destsize,
482 return _encode(twobytes, onebyte, dest, destlen, destsize, src, len, 1);
481 src, len, 1);
482 }
483 }
483
484
484 static const Py_ssize_t maxstorepathlen = 120;
485 static const Py_ssize_t maxstorepathlen = 120;
485
486
486 static Py_ssize_t _lowerencode(char *dest, size_t destsize,
487 static Py_ssize_t _lowerencode(char *dest, size_t destsize, const char *src,
487 const char *src, Py_ssize_t len)
488 Py_ssize_t len)
488 {
489 {
489 static const uint32_t onebyte[8] = {
490 static const uint32_t onebyte[8] = {1, 0x2bfffbfb, 0xe8000001,
490 1, 0x2bfffbfb, 0xe8000001, 0x2fffffff
491 0x2fffffff};
491 };
492
492
493 static const uint32_t lower[8] = { 0, 0, 0x7fffffe };
493 static const uint32_t lower[8] = {0, 0, 0x7fffffe};
494
494
495 Py_ssize_t i, destlen = 0;
495 Py_ssize_t i, destlen = 0;
496
496
497 for (i = 0; i < len; i++) {
497 for (i = 0; i < len; i++) {
498 if (inset(onebyte, src[i]))
498 if (inset(onebyte, src[i]))
499 charcopy(dest, &destlen, destsize, src[i]);
499 charcopy(dest, &destlen, destsize, src[i]);
500 else if (inset(lower, src[i]))
500 else if (inset(lower, src[i]))
501 charcopy(dest, &destlen, destsize, src[i] + 32);
501 charcopy(dest, &destlen, destsize, src[i] + 32);
502 else
502 else
503 escape3(dest, &destlen, destsize, src[i]);
503 escape3(dest, &destlen, destsize, src[i]);
504 }
504 }
505
505
506 return destlen;
506 return destlen;
507 }
507 }
508
508
509 PyObject *lowerencode(PyObject *self, PyObject *args)
509 PyObject *lowerencode(PyObject *self, PyObject *args)
510 {
510 {
511 char *path;
511 char *path;
512 Py_ssize_t len, newlen;
512 Py_ssize_t len, newlen;
513 PyObject *ret;
513 PyObject *ret;
514
514
515 if (!PyArg_ParseTuple(args, "s#:lowerencode", &path, &len))
515 if (!PyArg_ParseTuple(args, "s#:lowerencode", &path, &len))
516 return NULL;
516 return NULL;
517
517
518 newlen = _lowerencode(NULL, 0, path, len);
518 newlen = _lowerencode(NULL, 0, path, len);
519 ret = PyBytes_FromStringAndSize(NULL, newlen);
519 ret = PyBytes_FromStringAndSize(NULL, newlen);
520 if (ret)
520 if (ret)
521 _lowerencode(PyBytes_AS_STRING(ret), newlen, path, len);
521 _lowerencode(PyBytes_AS_STRING(ret), newlen, path, len);
522
522
523 return ret;
523 return ret;
524 }
524 }
525
525
526 /* See store.py:_auxencode for a description. */
526 /* See store.py:_auxencode for a description. */
527 static Py_ssize_t auxencode(char *dest, size_t destsize,
527 static Py_ssize_t auxencode(char *dest, size_t destsize, const char *src,
528 const char *src, Py_ssize_t len)
528 Py_ssize_t len)
529 {
529 {
530 static const uint32_t twobytes[8];
530 static const uint32_t twobytes[8];
531
531
532 static const uint32_t onebyte[8] = {
532 static const uint32_t onebyte[8] = {
533 ~0U, 0xffff3ffe, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
533 ~0U, 0xffff3ffe, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
534 };
534 };
535
535
536 return _encode(twobytes, onebyte, dest, 0, destsize, src, len, 0);
536 return _encode(twobytes, onebyte, dest, 0, destsize, src, len, 0);
537 }
537 }
538
538
539 static PyObject *hashmangle(const char *src, Py_ssize_t len, const char sha[20])
539 static PyObject *hashmangle(const char *src, Py_ssize_t len, const char sha[20])
540 {
540 {
541 static const Py_ssize_t dirprefixlen = 8;
541 static const Py_ssize_t dirprefixlen = 8;
542 static const Py_ssize_t maxshortdirslen = 68;
542 static const Py_ssize_t maxshortdirslen = 68;
543 char *dest;
543 char *dest;
544 PyObject *ret;
544 PyObject *ret;
545
545
546 Py_ssize_t i, d, p, lastslash = len - 1, lastdot = -1;
546 Py_ssize_t i, d, p, lastslash = len - 1, lastdot = -1;
547 Py_ssize_t destsize, destlen = 0, slop, used;
547 Py_ssize_t destsize, destlen = 0, slop, used;
548
548
549 while (lastslash >= 0 && src[lastslash] != '/') {
549 while (lastslash >= 0 && src[lastslash] != '/') {
550 if (src[lastslash] == '.' && lastdot == -1)
550 if (src[lastslash] == '.' && lastdot == -1)
551 lastdot = lastslash;
551 lastdot = lastslash;
552 lastslash--;
552 lastslash--;
553 }
553 }
554
554
555 #if 0
555 #if 0
556 /* All paths should end in a suffix of ".i" or ".d".
556 /* All paths should end in a suffix of ".i" or ".d".
557 Unfortunately, the file names in test-hybridencode.py
557 Unfortunately, the file names in test-hybridencode.py
558 violate this rule. */
558 violate this rule. */
559 if (lastdot != len - 3) {
559 if (lastdot != len - 3) {
560 PyErr_SetString(PyExc_ValueError,
560 PyErr_SetString(PyExc_ValueError,
561 "suffix missing or wrong length");
561 "suffix missing or wrong length");
562 return NULL;
562 return NULL;
563 }
563 }
564 #endif
564 #endif
565
565
566 /* If src contains a suffix, we will append it to the end of
566 /* If src contains a suffix, we will append it to the end of
567 the new string, so make room. */
567 the new string, so make room. */
568 destsize = 120;
568 destsize = 120;
569 if (lastdot >= 0)
569 if (lastdot >= 0)
570 destsize += len - lastdot - 1;
570 destsize += len - lastdot - 1;
571
571
572 ret = PyBytes_FromStringAndSize(NULL, destsize);
572 ret = PyBytes_FromStringAndSize(NULL, destsize);
573 if (ret == NULL)
573 if (ret == NULL)
574 return NULL;
574 return NULL;
575
575
576 dest = PyBytes_AS_STRING(ret);
576 dest = PyBytes_AS_STRING(ret);
577 memcopy(dest, &destlen, destsize, "dh/", 3);
577 memcopy(dest, &destlen, destsize, "dh/", 3);
578
578
579 /* Copy up to dirprefixlen bytes of each path component, up to
579 /* Copy up to dirprefixlen bytes of each path component, up to
580 a limit of maxshortdirslen bytes. */
580 a limit of maxshortdirslen bytes. */
581 for (i = d = p = 0; i < lastslash; i++, p++) {
581 for (i = d = p = 0; i < lastslash; i++, p++) {
582 if (src[i] == '/') {
582 if (src[i] == '/') {
583 char d = dest[destlen - 1];
583 char d = dest[destlen - 1];
584 /* After truncation, a directory name may end
584 /* After truncation, a directory name may end
585 in a space or dot, which are unportable. */
585 in a space or dot, which are unportable. */
586 if (d == '.' || d == ' ')
586 if (d == '.' || d == ' ')
587 dest[destlen - 1] = '_';
587 dest[destlen - 1] = '_';
588 /* The + 3 is to account for "dh/" in the beginning */
588 /* The + 3 is to account for "dh/" in the beginning */
589 if (destlen > maxshortdirslen + 3)
589 if (destlen > maxshortdirslen + 3)
590 break;
590 break;
591 charcopy(dest, &destlen, destsize, src[i]);
591 charcopy(dest, &destlen, destsize, src[i]);
592 p = -1;
592 p = -1;
593 }
593 } else if (p < dirprefixlen)
594 else if (p < dirprefixlen)
595 charcopy(dest, &destlen, destsize, src[i]);
594 charcopy(dest, &destlen, destsize, src[i]);
596 }
595 }
597
596
598 /* Rewind to just before the last slash copied. */
597 /* Rewind to just before the last slash copied. */
599 if (destlen > maxshortdirslen + 3)
598 if (destlen > maxshortdirslen + 3)
600 do {
599 do {
601 destlen--;
600 destlen--;
602 } while (destlen > 0 && dest[destlen] != '/');
601 } while (destlen > 0 && dest[destlen] != '/');
603
602
604 if (destlen > 3) {
603 if (destlen > 3) {
605 if (lastslash > 0) {
604 if (lastslash > 0) {
606 char d = dest[destlen - 1];
605 char d = dest[destlen - 1];
607 /* The last directory component may be
606 /* The last directory component may be
608 truncated, so make it safe. */
607 truncated, so make it safe. */
609 if (d == '.' || d == ' ')
608 if (d == '.' || d == ' ')
610 dest[destlen - 1] = '_';
609 dest[destlen - 1] = '_';
611 }
610 }
612
611
613 charcopy(dest, &destlen, destsize, '/');
612 charcopy(dest, &destlen, destsize, '/');
614 }
613 }
615
614
616 /* Add a prefix of the original file's name. Its length
615 /* Add a prefix of the original file's name. Its length
617 depends on the number of bytes left after accounting for
616 depends on the number of bytes left after accounting for
618 hash and suffix. */
617 hash and suffix. */
619 used = destlen + 40;
618 used = destlen + 40;
620 if (lastdot >= 0)
619 if (lastdot >= 0)
621 used += len - lastdot - 1;
620 used += len - lastdot - 1;
622 slop = maxstorepathlen - used;
621 slop = maxstorepathlen - used;
623 if (slop > 0) {
622 if (slop > 0) {
624 Py_ssize_t basenamelen =
623 Py_ssize_t basenamelen =
625 lastslash >= 0 ? len - lastslash - 2 : len - 1;
624 lastslash >= 0 ? len - lastslash - 2 : len - 1;
626
625
627 if (basenamelen > slop)
626 if (basenamelen > slop)
628 basenamelen = slop;
627 basenamelen = slop;
629 if (basenamelen > 0)
628 if (basenamelen > 0)
630 memcopy(dest, &destlen, destsize, &src[lastslash + 1],
629 memcopy(dest, &destlen, destsize, &src[lastslash + 1],
631 basenamelen);
630 basenamelen);
632 }
631 }
633
632
634 /* Add hash and suffix. */
633 /* Add hash and suffix. */
635 for (i = 0; i < 20; i++)
634 for (i = 0; i < 20; i++)
636 hexencode(dest, &destlen, destsize, sha[i]);
635 hexencode(dest, &destlen, destsize, sha[i]);
637
636
638 if (lastdot >= 0)
637 if (lastdot >= 0)
639 memcopy(dest, &destlen, destsize, &src[lastdot],
638 memcopy(dest, &destlen, destsize, &src[lastdot],
640 len - lastdot - 1);
639 len - lastdot - 1);
641
640
642 assert(PyBytes_Check(ret));
641 assert(PyBytes_Check(ret));
643 Py_SIZE(ret) = destlen;
642 Py_SIZE(ret) = destlen;
644
643
645 return ret;
644 return ret;
646 }
645 }
647
646
648 /*
647 /*
649 * Avoiding a trip through Python would improve performance by 50%,
648 * Avoiding a trip through Python would improve performance by 50%,
650 * but we don't encounter enough long names to be worth the code.
649 * but we don't encounter enough long names to be worth the code.
651 */
650 */
652 static int sha1hash(char hash[20], const char *str, Py_ssize_t len)
651 static int sha1hash(char hash[20], const char *str, Py_ssize_t len)
653 {
652 {
654 static PyObject *shafunc;
653 static PyObject *shafunc;
655 PyObject *shaobj, *hashobj;
654 PyObject *shaobj, *hashobj;
656
655
657 if (shafunc == NULL) {
656 if (shafunc == NULL) {
658 PyObject *hashlib, *name = PyBytes_FromString("hashlib");
657 PyObject *hashlib, *name = PyBytes_FromString("hashlib");
659
658
660 if (name == NULL)
659 if (name == NULL)
661 return -1;
660 return -1;
662
661
663 hashlib = PyImport_Import(name);
662 hashlib = PyImport_Import(name);
664 Py_DECREF(name);
663 Py_DECREF(name);
665
664
666 if (hashlib == NULL) {
665 if (hashlib == NULL) {
667 PyErr_SetString(PyExc_ImportError, "hashlib");
666 PyErr_SetString(PyExc_ImportError, "hashlib");
668 return -1;
667 return -1;
669 }
668 }
670 shafunc = PyObject_GetAttrString(hashlib, "sha1");
669 shafunc = PyObject_GetAttrString(hashlib, "sha1");
671 Py_DECREF(hashlib);
670 Py_DECREF(hashlib);
672
671
673 if (shafunc == NULL) {
672 if (shafunc == NULL) {
674 PyErr_SetString(PyExc_AttributeError,
673 PyErr_SetString(PyExc_AttributeError,
675 "module 'hashlib' has no "
674 "module 'hashlib' has no "
676 "attribute 'sha1'");
675 "attribute 'sha1'");
677 return -1;
676 return -1;
678 }
677 }
679 }
678 }
680
679
681 shaobj = PyObject_CallFunction(shafunc, "s#", str, len);
680 shaobj = PyObject_CallFunction(shafunc, "s#", str, len);
682
681
683 if (shaobj == NULL)
682 if (shaobj == NULL)
684 return -1;
683 return -1;
685
684
686 hashobj = PyObject_CallMethod(shaobj, "digest", "");
685 hashobj = PyObject_CallMethod(shaobj, "digest", "");
687 Py_DECREF(shaobj);
686 Py_DECREF(shaobj);
688 if (hashobj == NULL)
687 if (hashobj == NULL)
689 return -1;
688 return -1;
690
689
691 if (!PyBytes_Check(hashobj) || PyBytes_GET_SIZE(hashobj) != 20) {
690 if (!PyBytes_Check(hashobj) || PyBytes_GET_SIZE(hashobj) != 20) {
692 PyErr_SetString(PyExc_TypeError,
691 PyErr_SetString(PyExc_TypeError,
693 "result of digest is not a 20-byte hash");
692 "result of digest is not a 20-byte hash");
694 Py_DECREF(hashobj);
693 Py_DECREF(hashobj);
695 return -1;
694 return -1;
696 }
695 }
697
696
698 memcpy(hash, PyBytes_AS_STRING(hashobj), 20);
697 memcpy(hash, PyBytes_AS_STRING(hashobj), 20);
699 Py_DECREF(hashobj);
698 Py_DECREF(hashobj);
700 return 0;
699 return 0;
701 }
700 }
702
701
703 #define MAXENCODE 4096 * 4
702 #define MAXENCODE 4096 * 4
704
703
705 static PyObject *hashencode(const char *src, Py_ssize_t len)
704 static PyObject *hashencode(const char *src, Py_ssize_t len)
706 {
705 {
707 char dired[MAXENCODE];
706 char dired[MAXENCODE];
708 char lowered[MAXENCODE];
707 char lowered[MAXENCODE];
709 char auxed[MAXENCODE];
708 char auxed[MAXENCODE];
710 Py_ssize_t dirlen, lowerlen, auxlen, baselen;
709 Py_ssize_t dirlen, lowerlen, auxlen, baselen;
711 char sha[20];
710 char sha[20];
712
711
713 baselen = (len - 5) * 3;
712 baselen = (len - 5) * 3;
714 if (baselen >= MAXENCODE) {
713 if (baselen >= MAXENCODE) {
715 PyErr_SetString(PyExc_ValueError, "string too long");
714 PyErr_SetString(PyExc_ValueError, "string too long");
716 return NULL;
715 return NULL;
717 }
716 }
718
717
719 dirlen = _encodedir(dired, baselen, src, len);
718 dirlen = _encodedir(dired, baselen, src, len);
720 if (sha1hash(sha, dired, dirlen - 1) == -1)
719 if (sha1hash(sha, dired, dirlen - 1) == -1)
721 return NULL;
720 return NULL;
722 lowerlen = _lowerencode(lowered, baselen, dired + 5, dirlen - 5);
721 lowerlen = _lowerencode(lowered, baselen, dired + 5, dirlen - 5);
723 auxlen = auxencode(auxed, baselen, lowered, lowerlen);
722 auxlen = auxencode(auxed, baselen, lowered, lowerlen);
724 return hashmangle(auxed, auxlen, sha);
723 return hashmangle(auxed, auxlen, sha);
725 }
724 }
726
725
727 PyObject *pathencode(PyObject *self, PyObject *args)
726 PyObject *pathencode(PyObject *self, PyObject *args)
728 {
727 {
729 Py_ssize_t len, newlen;
728 Py_ssize_t len, newlen;
730 PyObject *pathobj, *newobj;
729 PyObject *pathobj, *newobj;
731 char *path;
730 char *path;
732
731
733 if (!PyArg_ParseTuple(args, "O:pathencode", &pathobj))
732 if (!PyArg_ParseTuple(args, "O:pathencode", &pathobj))
734 return NULL;
733 return NULL;
735
734
736 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
735 if (PyBytes_AsStringAndSize(pathobj, &path, &len) == -1) {
737 PyErr_SetString(PyExc_TypeError, "expected a string");
736 PyErr_SetString(PyExc_TypeError, "expected a string");
738 return NULL;
737 return NULL;
739 }
738 }
740
739
741 if (len > maxstorepathlen)
740 if (len > maxstorepathlen)
742 newlen = maxstorepathlen + 2;
741 newlen = maxstorepathlen + 2;
743 else
742 else
744 newlen = len ? basicencode(NULL, 0, path, len + 1) : 1;
743 newlen = len ? basicencode(NULL, 0, path, len + 1) : 1;
745
744
746 if (newlen <= maxstorepathlen + 1) {
745 if (newlen <= maxstorepathlen + 1) {
747 if (newlen == len + 1) {
746 if (newlen == len + 1) {
748 Py_INCREF(pathobj);
747 Py_INCREF(pathobj);
749 return pathobj;
748 return pathobj;
750 }
749 }
751
750
752 newobj = PyBytes_FromStringAndSize(NULL, newlen);
751 newobj = PyBytes_FromStringAndSize(NULL, newlen);
753
752
754 if (newobj) {
753 if (newobj) {
755 assert(PyBytes_Check(newobj));
754 assert(PyBytes_Check(newobj));
756 Py_SIZE(newobj)--;
755 Py_SIZE(newobj)--;
757 basicencode(PyBytes_AS_STRING(newobj), newlen, path,
756 basicencode(PyBytes_AS_STRING(newobj), newlen, path,
758 len + 1);
757 len + 1);
759 }
758 }
760 }
759 } else
761 else
762 newobj = hashencode(path, len + 1);
760 newobj = hashencode(path, len + 1);
763
761
764 return newobj;
762 return newobj;
765 }
763 }
General Comments 0
You need to be logged in to leave comments. Login now