##// END OF EJS Templates
rhg: reduce verbosity in path_encode by using a trait for writing...
Arseniy Alekseyev -
r51439:96d31efd default
parent child Browse files
Show More
@@ -1,651 +1,630 b''
1 use sha1::{Digest, Sha1};
1 use sha1::{Digest, Sha1};
2
2
3 #[derive(PartialEq, Debug)]
3 #[derive(PartialEq, Debug)]
4 #[allow(non_camel_case_types)]
4 #[allow(non_camel_case_types)]
5 #[allow(clippy::upper_case_acronyms)]
5 #[allow(clippy::upper_case_acronyms)]
6 enum path_state {
6 enum path_state {
7 START, /* first byte of a path component */
7 START, /* first byte of a path component */
8 A, /* "AUX" */
8 A, /* "AUX" */
9 AU,
9 AU,
10 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
10 THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
11 C, /* "CON" or "COMn" */
11 C, /* "CON" or "COMn" */
12 CO,
12 CO,
13 COMLPT, /* "COM" or "LPT" */
13 COMLPT, /* "COM" or "LPT" */
14 COMLPTn,
14 COMLPTn,
15 L,
15 L,
16 LP,
16 LP,
17 N,
17 N,
18 NU,
18 NU,
19 P, /* "PRN" */
19 P, /* "PRN" */
20 PR,
20 PR,
21 LDOT, /* leading '.' */
21 LDOT, /* leading '.' */
22 DOT, /* '.' in a non-leading position */
22 DOT, /* '.' in a non-leading position */
23 H, /* ".h" */
23 H, /* ".h" */
24 HGDI, /* ".hg", ".d", or ".i" */
24 HGDI, /* ".hg", ".d", or ".i" */
25 SPACE,
25 SPACE,
26 DEFAULT, /* byte of a path component after the first */
26 DEFAULT, /* byte of a path component after the first */
27 }
27 }
28
28
29 /* state machine for dir-encoding */
29 /* state machine for dir-encoding */
30 #[allow(non_camel_case_types)]
30 #[allow(non_camel_case_types)]
31 #[allow(clippy::upper_case_acronyms)]
31 #[allow(clippy::upper_case_acronyms)]
32 enum dir_state {
32 enum dir_state {
33 DDOT,
33 DDOT,
34 DH,
34 DH,
35 DHGDI,
35 DHGDI,
36 DDEFAULT,
36 DDEFAULT,
37 }
37 }
38
38
39 trait Sink {
40 fn write_byte(&mut self, c: u8);
41 fn write_bytes(&mut self, c: &[u8]);
42 }
43
39 fn inset(bitset: &[u32; 8], c: u8) -> bool {
44 fn inset(bitset: &[u32; 8], c: u8) -> bool {
40 bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
45 bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
41 }
46 }
42
47
43 fn charcopy(dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
48 struct Dest<'a> {
44 if let Some(slice) = dest {
49 dest: Option<&'a mut [u8]>,
45 slice[*destlen] = c
50 pub len: usize,
46 }
47 *destlen += 1
48 }
51 }
49
52
50 fn memcopy(dest: Option<&mut [u8]>, destlen: &mut usize, src: &[u8]) {
53 impl<'a> Dest<'a> {
51 if let Some(slice) = dest {
54 pub fn create(buf: &'a mut [u8]) -> Dest<'a> {
52 slice[*destlen..*destlen + src.len()].copy_from_slice(src)
55 Dest {
56 dest: Some(buf),
57 len: 0,
53 }
58 }
54 *destlen += src.len();
59 }
60
61 pub fn create_measure() -> Dest<'a> {
62 Dest { dest: None, len: 0 }
63 }
55 }
64 }
56
65
57 fn rewrap_option<'a, 'b: 'a>(
66 fn rewrap_option<'a, 'b: 'a>(
58 x: &'a mut Option<&'b mut [u8]>,
67 x: &'a mut Option<&'b mut [u8]>,
59 ) -> Option<&'a mut [u8]> {
68 ) -> Option<&'a mut [u8]> {
60 match x {
69 match x {
61 None => None,
70 None => None,
62 Some(y) => Some(y),
71 Some(y) => Some(y),
63 }
72 }
64 }
73 }
65
74
66 fn hexencode(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
75 impl<'a> Sink for Dest<'a> {
76 fn write_byte(&mut self, c: u8) {
77 if let Some(slice) = rewrap_option(&mut self.dest) {
78 slice[self.len] = c
79 }
80 self.len += 1
81 }
82
83 fn write_bytes(&mut self, src: &[u8]) {
84 if let Some(slice) = rewrap_option(&mut self.dest) {
85 slice[self.len..self.len + src.len()].copy_from_slice(src)
86 }
87 self.len += src.len();
88 }
89 }
90
91 fn hexencode(dest: &mut impl Sink, c: u8) {
67 let hexdigit = b"0123456789abcdef";
92 let hexdigit = b"0123456789abcdef";
68 charcopy(
93 dest.write_byte(hexdigit[(c as usize) >> 4]);
69 rewrap_option(&mut dest),
94 dest.write_byte(hexdigit[(c as usize) & 15]);
70 destlen,
71 hexdigit[(c as usize) >> 4],
72 );
73 charcopy(dest, destlen, hexdigit[(c as usize) & 15]);
74 }
95 }
75
96
76 /* 3-byte escape: tilde followed by two hex digits */
97 /* 3-byte escape: tilde followed by two hex digits */
77 fn escape3(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) {
98 fn escape3(dest: &mut impl Sink, c: u8) {
78 charcopy(rewrap_option(&mut dest), destlen, b'~');
99 dest.write_byte(b'~');
79 hexencode(dest, destlen, c);
100 hexencode(dest, c);
80 }
101 }
81
102
82 fn encode_dir(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize {
103 fn encode_dir(dest: &mut impl Sink, src: &[u8]) {
83 let mut state = dir_state::DDEFAULT;
104 let mut state = dir_state::DDEFAULT;
84 let mut i = 0;
105 let mut i = 0;
85 let mut destlen = 0;
86
106
87 while i < src.len() {
107 while i < src.len() {
88 match state {
108 match state {
89 dir_state::DDOT => match src[i] {
109 dir_state::DDOT => match src[i] {
90 b'd' | b'i' => {
110 b'd' | b'i' => {
91 state = dir_state::DHGDI;
111 state = dir_state::DHGDI;
92 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
112 dest.write_byte(src[i]);
93 i += 1;
113 i += 1;
94 }
114 }
95 b'h' => {
115 b'h' => {
96 state = dir_state::DH;
116 state = dir_state::DH;
97 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
117 dest.write_byte(src[i]);
98 i += 1;
118 i += 1;
99 }
119 }
100 _ => {
120 _ => {
101 state = dir_state::DDEFAULT;
121 state = dir_state::DDEFAULT;
102 }
122 }
103 },
123 },
104 dir_state::DH => {
124 dir_state::DH => {
105 if src[i] == b'g' {
125 if src[i] == b'g' {
106 state = dir_state::DHGDI;
126 state = dir_state::DHGDI;
107 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
127 dest.write_byte(src[i]);
108 i += 1;
128 i += 1;
109 } else {
129 } else {
110 state = dir_state::DDEFAULT;
130 state = dir_state::DDEFAULT;
111 }
131 }
112 }
132 }
113 dir_state::DHGDI => {
133 dir_state::DHGDI => {
114 if src[i] == b'/' {
134 if src[i] == b'/' {
115 memcopy(rewrap_option(&mut dest), &mut destlen, b".hg");
135 dest.write_bytes(b".hg");
116 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
136 dest.write_byte(src[i]);
117 i += 1;
137 i += 1;
118 }
138 }
119 state = dir_state::DDEFAULT;
139 state = dir_state::DDEFAULT;
120 }
140 }
121 dir_state::DDEFAULT => {
141 dir_state::DDEFAULT => {
122 if src[i] == b'.' {
142 if src[i] == b'.' {
123 state = dir_state::DDOT
143 state = dir_state::DDOT
124 }
144 }
125 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
145 dest.write_byte(src[i]);
126 i += 1;
146 i += 1;
127 }
147 }
128 }
148 }
129 }
149 }
130 destlen
131 }
150 }
132
151
133 fn _encode(
152 fn _encode(
134 twobytes: &[u32; 8],
153 twobytes: &[u32; 8],
135 onebyte: &[u32; 8],
154 onebyte: &[u32; 8],
136 mut dest: Option<&mut [u8]>,
155 dest: &mut impl Sink,
137 src: &[u8],
156 src: &[u8],
138 encodedir: bool,
157 encodedir: bool,
139 ) -> usize {
158 ) {
140 let mut state = path_state::START;
159 let mut state = path_state::START;
141 let mut i = 0;
160 let mut i = 0;
142 let mut destlen = 0;
143 let len = src.len();
161 let len = src.len();
144
162
145 while i < len {
163 while i < len {
146 match state {
164 match state {
147 path_state::START => match src[i] {
165 path_state::START => match src[i] {
148 b'/' => {
166 b'/' => {
149 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
167 dest.write_byte(src[i]);
150 i += 1;
168 i += 1;
151 }
169 }
152 b'.' => {
170 b'.' => {
153 state = path_state::LDOT;
171 state = path_state::LDOT;
154 escape3(rewrap_option(&mut dest), &mut destlen, src[i]);
172 escape3(dest, src[i]);
155 i += 1;
173 i += 1;
156 }
174 }
157 b' ' => {
175 b' ' => {
158 state = path_state::DEFAULT;
176 state = path_state::DEFAULT;
159 escape3(rewrap_option(&mut dest), &mut destlen, src[i]);
177 escape3(dest, src[i]);
160 i += 1;
178 i += 1;
161 }
179 }
162 b'a' => {
180 b'a' => {
163 state = path_state::A;
181 state = path_state::A;
164 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
182 dest.write_byte(src[i]);
165 i += 1;
183 i += 1;
166 }
184 }
167 b'c' => {
185 b'c' => {
168 state = path_state::C;
186 state = path_state::C;
169 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
187 dest.write_byte(src[i]);
170 i += 1;
188 i += 1;
171 }
189 }
172 b'l' => {
190 b'l' => {
173 state = path_state::L;
191 state = path_state::L;
174 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
192 dest.write_byte(src[i]);
175 i += 1;
193 i += 1;
176 }
194 }
177 b'n' => {
195 b'n' => {
178 state = path_state::N;
196 state = path_state::N;
179 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
197 dest.write_byte(src[i]);
180 i += 1;
198 i += 1;
181 }
199 }
182 b'p' => {
200 b'p' => {
183 state = path_state::P;
201 state = path_state::P;
184 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
202 dest.write_byte(src[i]);
185 i += 1;
203 i += 1;
186 }
204 }
187 _ => {
205 _ => {
188 state = path_state::DEFAULT;
206 state = path_state::DEFAULT;
189 }
207 }
190 },
208 },
191 path_state::A => {
209 path_state::A => {
192 if src[i] == b'u' {
210 if src[i] == b'u' {
193 state = path_state::AU;
211 state = path_state::AU;
194 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
212 dest.write_byte(src[i]);
195 i += 1;
213 i += 1;
196 } else {
214 } else {
197 state = path_state::DEFAULT;
215 state = path_state::DEFAULT;
198 }
216 }
199 }
217 }
200 path_state::AU => {
218 path_state::AU => {
201 if src[i] == b'x' {
219 if src[i] == b'x' {
202 state = path_state::THIRD;
220 state = path_state::THIRD;
203 i += 1;
221 i += 1;
204 } else {
222 } else {
205 state = path_state::DEFAULT;
223 state = path_state::DEFAULT;
206 }
224 }
207 }
225 }
208 path_state::THIRD => {
226 path_state::THIRD => {
209 state = path_state::DEFAULT;
227 state = path_state::DEFAULT;
210 match src[i] {
228 match src[i] {
211 b'.' | b'/' | b'\0' => escape3(
229 b'.' | b'/' | b'\0' => escape3(dest, src[i - 1]),
212 rewrap_option(&mut dest),
213 &mut destlen,
214 src[i - 1],
215 ),
216 _ => i -= 1,
230 _ => i -= 1,
217 }
231 }
218 }
232 }
219 path_state::C => {
233 path_state::C => {
220 if src[i] == b'o' {
234 if src[i] == b'o' {
221 state = path_state::CO;
235 state = path_state::CO;
222 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
236 dest.write_byte(src[i]);
223 i += 1;
237 i += 1;
224 } else {
238 } else {
225 state = path_state::DEFAULT;
239 state = path_state::DEFAULT;
226 }
240 }
227 }
241 }
228 path_state::CO => {
242 path_state::CO => {
229 if src[i] == b'm' {
243 if src[i] == b'm' {
230 state = path_state::COMLPT;
244 state = path_state::COMLPT;
231 i += 1;
245 i += 1;
232 } else if src[i] == b'n' {
246 } else if src[i] == b'n' {
233 state = path_state::THIRD;
247 state = path_state::THIRD;
234 i += 1;
248 i += 1;
235 } else {
249 } else {
236 state = path_state::DEFAULT;
250 state = path_state::DEFAULT;
237 }
251 }
238 }
252 }
239 path_state::COMLPT => {
253 path_state::COMLPT => {
240 if src[i] >= b'1' && src[i] <= b'9' {
254 if src[i] >= b'1' && src[i] <= b'9' {
241 state = path_state::COMLPTn;
255 state = path_state::COMLPTn;
242 i += 1;
256 i += 1;
243 } else {
257 } else {
244 state = path_state::DEFAULT;
258 state = path_state::DEFAULT;
245 charcopy(
259 dest.write_byte(src[i - 1]);
246 rewrap_option(&mut dest),
247 &mut destlen,
248 src[i - 1],
249 );
250 }
260 }
251 }
261 }
252 path_state::COMLPTn => {
262 path_state::COMLPTn => {
253 state = path_state::DEFAULT;
263 state = path_state::DEFAULT;
254 match src[i] {
264 match src[i] {
255 b'.' | b'/' | b'\0' => {
265 b'.' | b'/' | b'\0' => {
256 escape3(
266 escape3(dest, src[i - 2]);
257 rewrap_option(&mut dest),
267 dest.write_byte(src[i - 1]);
258 &mut destlen,
259 src[i - 2],
260 );
261 charcopy(
262 rewrap_option(&mut dest),
263 &mut destlen,
264 src[i - 1],
265 );
266 }
268 }
267 _ => {
269 _ => {
268 memcopy(
270 dest.write_bytes(&src[i - 2..i]);
269 rewrap_option(&mut dest),
270 &mut destlen,
271 &src[i - 2..i],
272 );
273 }
271 }
274 }
272 }
275 }
273 }
276 path_state::L => {
274 path_state::L => {
277 if src[i] == b'p' {
275 if src[i] == b'p' {
278 state = path_state::LP;
276 state = path_state::LP;
279 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
277 dest.write_byte(src[i]);
280 i += 1;
278 i += 1;
281 } else {
279 } else {
282 state = path_state::DEFAULT;
280 state = path_state::DEFAULT;
283 }
281 }
284 }
282 }
285 path_state::LP => {
283 path_state::LP => {
286 if src[i] == b't' {
284 if src[i] == b't' {
287 state = path_state::COMLPT;
285 state = path_state::COMLPT;
288 i += 1;
286 i += 1;
289 } else {
287 } else {
290 state = path_state::DEFAULT;
288 state = path_state::DEFAULT;
291 }
289 }
292 }
290 }
293 path_state::N => {
291 path_state::N => {
294 if src[i] == b'u' {
292 if src[i] == b'u' {
295 state = path_state::NU;
293 state = path_state::NU;
296 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
294 dest.write_byte(src[i]);
297 i += 1;
295 i += 1;
298 } else {
296 } else {
299 state = path_state::DEFAULT;
297 state = path_state::DEFAULT;
300 }
298 }
301 }
299 }
302 path_state::NU => {
300 path_state::NU => {
303 if src[i] == b'l' {
301 if src[i] == b'l' {
304 state = path_state::THIRD;
302 state = path_state::THIRD;
305 i += 1;
303 i += 1;
306 } else {
304 } else {
307 state = path_state::DEFAULT;
305 state = path_state::DEFAULT;
308 }
306 }
309 }
307 }
310 path_state::P => {
308 path_state::P => {
311 if src[i] == b'r' {
309 if src[i] == b'r' {
312 state = path_state::PR;
310 state = path_state::PR;
313 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
311 dest.write_byte(src[i]);
314 i += 1;
312 i += 1;
315 } else {
313 } else {
316 state = path_state::DEFAULT;
314 state = path_state::DEFAULT;
317 }
315 }
318 }
316 }
319 path_state::PR => {
317 path_state::PR => {
320 if src[i] == b'n' {
318 if src[i] == b'n' {
321 state = path_state::THIRD;
319 state = path_state::THIRD;
322 i += 1;
320 i += 1;
323 } else {
321 } else {
324 state = path_state::DEFAULT;
322 state = path_state::DEFAULT;
325 }
323 }
326 }
324 }
327 path_state::LDOT => match src[i] {
325 path_state::LDOT => match src[i] {
328 b'd' | b'i' => {
326 b'd' | b'i' => {
329 state = path_state::HGDI;
327 state = path_state::HGDI;
330 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
328 dest.write_byte(src[i]);
331 i += 1;
329 i += 1;
332 }
330 }
333 b'h' => {
331 b'h' => {
334 state = path_state::H;
332 state = path_state::H;
335 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
333 dest.write_byte(src[i]);
336 i += 1;
334 i += 1;
337 }
335 }
338 _ => {
336 _ => {
339 state = path_state::DEFAULT;
337 state = path_state::DEFAULT;
340 }
338 }
341 },
339 },
342 path_state::DOT => match src[i] {
340 path_state::DOT => match src[i] {
343 b'/' | b'\0' => {
341 b'/' | b'\0' => {
344 state = path_state::START;
342 state = path_state::START;
345 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e");
343 dest.write_bytes(b"~2e");
346 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
344 dest.write_byte(src[i]);
347 i += 1;
345 i += 1;
348 }
346 }
349 b'd' | b'i' => {
347 b'd' | b'i' => {
350 state = path_state::HGDI;
348 state = path_state::HGDI;
351 charcopy(rewrap_option(&mut dest), &mut destlen, b'.');
349 dest.write_byte(b'.');
352 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
350 dest.write_byte(src[i]);
353 i += 1;
351 i += 1;
354 }
352 }
355 b'h' => {
353 b'h' => {
356 state = path_state::H;
354 state = path_state::H;
357 memcopy(rewrap_option(&mut dest), &mut destlen, b".h");
355 dest.write_bytes(b".h");
358 i += 1;
356 i += 1;
359 }
357 }
360 _ => {
358 _ => {
361 state = path_state::DEFAULT;
359 state = path_state::DEFAULT;
362 charcopy(rewrap_option(&mut dest), &mut destlen, b'.');
360 dest.write_byte(b'.');
363 }
361 }
364 },
362 },
365 path_state::H => {
363 path_state::H => {
366 if src[i] == b'g' {
364 if src[i] == b'g' {
367 state = path_state::HGDI;
365 state = path_state::HGDI;
368 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
366 dest.write_byte(src[i]);
369 i += 1;
367 i += 1;
370 } else {
368 } else {
371 state = path_state::DEFAULT;
369 state = path_state::DEFAULT;
372 }
370 }
373 }
371 }
374 path_state::HGDI => {
372 path_state::HGDI => {
375 if src[i] == b'/' {
373 if src[i] == b'/' {
376 state = path_state::START;
374 state = path_state::START;
377 if encodedir {
375 if encodedir {
378 memcopy(
376 dest.write_bytes(b".hg");
379 rewrap_option(&mut dest),
380 &mut destlen,
381 b".hg",
382 );
383 }
377 }
384 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
378 dest.write_byte(src[i]);
385 i += 1
379 i += 1
386 } else {
380 } else {
387 state = path_state::DEFAULT;
381 state = path_state::DEFAULT;
388 }
382 }
389 }
383 }
390 path_state::SPACE => match src[i] {
384 path_state::SPACE => match src[i] {
391 b'/' | b'\0' => {
385 b'/' | b'\0' => {
392 state = path_state::START;
386 state = path_state::START;
393 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20");
387 dest.write_bytes(b"~20");
394 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
388 dest.write_byte(src[i]);
395 i += 1;
389 i += 1;
396 }
390 }
397 _ => {
391 _ => {
398 state = path_state::DEFAULT;
392 state = path_state::DEFAULT;
399 charcopy(rewrap_option(&mut dest), &mut destlen, b' ');
393 dest.write_byte(b' ');
400 }
394 }
401 },
395 },
402 path_state::DEFAULT => {
396 path_state::DEFAULT => {
403 while i != len && inset(onebyte, src[i]) {
397 while i != len && inset(onebyte, src[i]) {
404 charcopy(rewrap_option(&mut dest), &mut destlen, src[i]);
398 dest.write_byte(src[i]);
405 i += 1;
399 i += 1;
406 }
400 }
407 if i == len {
401 if i == len {
408 break;
402 break;
409 }
403 }
410 match src[i] {
404 match src[i] {
411 b'.' => {
405 b'.' => {
412 state = path_state::DOT;
406 state = path_state::DOT;
413 i += 1
407 i += 1
414 }
408 }
415 b' ' => {
409 b' ' => {
416 state = path_state::SPACE;
410 state = path_state::SPACE;
417 i += 1
411 i += 1
418 }
412 }
419 b'/' => {
413 b'/' => {
420 state = path_state::START;
414 state = path_state::START;
421 charcopy(rewrap_option(&mut dest), &mut destlen, b'/');
415 dest.write_byte(b'/');
422 i += 1;
416 i += 1;
423 }
417 }
424 _ => {
418 _ => {
425 if inset(onebyte, src[i]) {
419 if inset(onebyte, src[i]) {
426 loop {
420 loop {
427 charcopy(
421 dest.write_byte(src[i]);
428 rewrap_option(&mut dest),
429 &mut destlen,
430 src[i],
431 );
432 i += 1;
422 i += 1;
433 if !(i < len && inset(onebyte, src[i])) {
423 if !(i < len && inset(onebyte, src[i])) {
434 break;
424 break;
435 }
425 }
436 }
426 }
437 } else if inset(twobytes, src[i]) {
427 } else if inset(twobytes, src[i]) {
438 let c = src[i];
428 let c = src[i];
439 i += 1;
429 i += 1;
440 charcopy(
430 dest.write_byte(b'_');
441 rewrap_option(&mut dest),
431 dest.write_byte(if c == b'_' {
442 &mut destlen,
432 b'_'
443 b'_',
444 );
445 charcopy(
446 rewrap_option(&mut dest),
447 &mut destlen,
448 if c == b'_' { b'_' } else { c + 32 },
449 );
450 } else {
433 } else {
451 escape3(
434 c + 32
452 rewrap_option(&mut dest),
435 });
453 &mut destlen,
436 } else {
454 src[i],
437 escape3(dest, src[i]);
455 );
456 i += 1;
438 i += 1;
457 }
439 }
458 }
440 }
459 }
441 }
460 }
442 }
461 }
443 }
462 }
444 }
463 match state {
445 match state {
464 path_state::START => (),
446 path_state::START => (),
465 path_state::A => (),
447 path_state::A => (),
466 path_state::AU => (),
448 path_state::AU => (),
467 path_state::THIRD => {
449 path_state::THIRD => escape3(dest, src[i - 1]),
468 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 1])
469 }
470 path_state::C => (),
450 path_state::C => (),
471 path_state::CO => (),
451 path_state::CO => (),
472 path_state::COMLPT => {
452 path_state::COMLPT => dest.write_byte(src[i - 1]),
473 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1])
474 }
475 path_state::COMLPTn => {
453 path_state::COMLPTn => {
476 escape3(rewrap_option(&mut dest), &mut destlen, src[i - 2]);
454 escape3(dest, src[i - 2]);
477 charcopy(rewrap_option(&mut dest), &mut destlen, src[i - 1]);
455 dest.write_byte(src[i - 1]);
478 }
456 }
479 path_state::L => (),
457 path_state::L => (),
480 path_state::LP => (),
458 path_state::LP => (),
481 path_state::N => (),
459 path_state::N => (),
482 path_state::NU => (),
460 path_state::NU => (),
483 path_state::P => (),
461 path_state::P => (),
484 path_state::PR => (),
462 path_state::PR => (),
485 path_state::LDOT => (),
463 path_state::LDOT => (),
486 path_state::DOT => {
464 path_state::DOT => {
487 memcopy(rewrap_option(&mut dest), &mut destlen, b"~2e");
465 dest.write_bytes(b"~2e");
488 }
466 }
489 path_state::H => (),
467 path_state::H => (),
490 path_state::HGDI => (),
468 path_state::HGDI => (),
491 path_state::SPACE => {
469 path_state::SPACE => {
492 memcopy(rewrap_option(&mut dest), &mut destlen, b"~20");
470 dest.write_bytes(b"~20");
493 }
471 }
494 path_state::DEFAULT => (),
472 path_state::DEFAULT => (),
495 };
473 }
496 destlen
497 }
474 }
498
475
499 fn basic_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
476 fn basic_encode(dest: &mut impl Sink, src: &[u8]) {
500 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
477 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
501 let onebyte: [u32; 8] =
478 let onebyte: [u32; 8] =
502 [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
479 [1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
503 _encode(&twobytes, &onebyte, dest, src, true)
480 _encode(&twobytes, &onebyte, dest, src, true)
504 }
481 }
505
482
506 const MAXSTOREPATHLEN: usize = 120;
483 const MAXSTOREPATHLEN: usize = 120;
507
484
508 fn lower_encode(mut dest: Option<&mut [u8]>, src: &[u8]) -> usize {
485 fn lower_encode(dest: &mut impl Sink, src: &[u8]) {
509 let onebyte: [u32; 8] =
486 let onebyte: [u32; 8] =
510 [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
487 [1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
511 let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
488 let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
512 let mut destlen = 0;
513 for c in src {
489 for c in src {
514 if inset(&onebyte, *c) {
490 if inset(&onebyte, *c) {
515 charcopy(rewrap_option(&mut dest), &mut destlen, *c)
491 dest.write_byte(*c)
516 } else if inset(&lower, *c) {
492 } else if inset(&lower, *c) {
517 charcopy(rewrap_option(&mut dest), &mut destlen, *c + 32)
493 dest.write_byte(*c + 32)
518 } else {
494 } else {
519 escape3(rewrap_option(&mut dest), &mut destlen, *c)
495 escape3(dest, *c)
520 }
496 }
521 }
497 }
522 destlen
523 }
498 }
524
499
525 fn aux_encode(dest: Option<&mut [u8]>, src: &[u8]) -> usize {
500 fn aux_encode(dest: &mut impl Sink, src: &[u8]) {
526 let twobytes = [0; 8];
501 let twobytes = [0; 8];
527 let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
502 let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
528 _encode(&twobytes, &onebyte, dest, src, false)
503 _encode(&twobytes, &onebyte, dest, src, false)
529 }
504 }
530
505
531 fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
506 fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
532 let dirprefixlen = 8;
507 let dirprefixlen = 8;
533 let maxshortdirslen = 68;
508 let maxshortdirslen = 68;
534 let mut destlen = 0;
535
509
536 let last_slash = src.iter().rposition(|b| *b == b'/');
510 let last_slash = src.iter().rposition(|b| *b == b'/');
537 let last_dot: Option<usize> = {
511 let last_dot: Option<usize> = {
538 let s = last_slash.unwrap_or(0);
512 let s = last_slash.unwrap_or(0);
539 src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s)
513 src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s)
540 };
514 };
541
515
542 let mut dest = vec![0; MAXSTOREPATHLEN];
516 let mut dest_vec = vec![0; MAXSTOREPATHLEN];
543 memcopy(Some(&mut dest), &mut destlen, b"dh/");
517 let mut dest = Dest::create(&mut dest_vec);
518 dest.write_bytes(b"dh/");
544
519
545 if let Some(last_slash) = last_slash {
520 if let Some(last_slash) = last_slash {
546 for slice in src[..last_slash].split(|b| *b == b'/') {
521 for slice in src[..last_slash].split(|b| *b == b'/') {
547 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
522 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
548 if destlen + slice.len() > maxshortdirslen + 3 {
523 if dest.len + slice.len() > maxshortdirslen + 3 {
549 break;
524 break;
550 } else {
525 } else {
551 memcopy(Some(&mut dest), &mut destlen, slice);
526 dest.write_bytes(slice);
552 if dest[destlen - 1] == b'.' || dest[destlen - 1] == b' ' {
553 dest[destlen - 1] = b'_'
554 }
527 }
555 }
528 dest.write_byte(b'/');
556 charcopy(Some(&mut dest), &mut destlen, b'/');
557 }
529 }
558 }
530 }
559
531
560 let used = destlen + 40 + {
532 let used = dest.len + 40 + {
561 if let Some(l) = last_dot {
533 if let Some(l) = last_dot {
562 src.len() - l
534 src.len() - l
563 } else {
535 } else {
564 0
536 0
565 }
537 }
566 };
538 };
567
539
568 if MAXSTOREPATHLEN > used {
540 if MAXSTOREPATHLEN > used {
569 let slop = MAXSTOREPATHLEN - used;
541 let slop = MAXSTOREPATHLEN - used;
570 let basenamelen = match last_slash {
542 let basenamelen = match last_slash {
571 Some(l) => src.len() - l - 1,
543 Some(l) => src.len() - l - 1,
572 None => src.len(),
544 None => src.len(),
573 };
545 };
574 let basenamelen = std::cmp::min(basenamelen, slop);
546 let basenamelen = std::cmp::min(basenamelen, slop);
575 if basenamelen > 0 {
547 if basenamelen > 0 {
576 let start = match last_slash {
548 let start = match last_slash {
577 Some(l) => l + 1,
549 Some(l) => l + 1,
578 None => 0,
550 None => 0,
579 };
551 };
580 memcopy(
552 dest.write_bytes(&src[start..][..basenamelen])
581 Some(&mut dest),
582 &mut destlen,
583 &src[start..][..basenamelen],
584 )
585 }
553 }
586 }
554 }
587 for c in sha {
555 for c in sha {
588 hexencode(Some(&mut dest), &mut destlen, *c);
556 hexencode(&mut dest, *c);
589 }
557 }
590 if let Some(l) = last_dot {
558 if let Some(l) = last_dot {
591 memcopy(Some(&mut dest), &mut destlen, &src[l..]);
559 dest.write_bytes(&src[l..]);
592 }
560 }
593 if destlen == dest.len() {
561 let destlen = dest.len;
594 dest
562 if destlen == dest_vec.len() {
563 dest_vec
595 } else {
564 } else {
596 // sometimes the path are shorter than MAXSTOREPATHLEN
565 // sometimes the path are shorter than MAXSTOREPATHLEN
597 dest[..destlen].to_vec()
566 dest_vec[..destlen].to_vec()
598 }
567 }
599 }
568 }
600
569
601 const MAXENCODE: usize = 4096 * 4;
570 const MAXENCODE: usize = 4096 * 4;
602 fn hash_encode(src: &[u8]) -> Vec<u8> {
571 fn hash_encode(src: &[u8]) -> Vec<u8> {
603 let dired = &mut [0; MAXENCODE];
572 let dired = &mut [0; MAXENCODE];
573 let mut dired_dest = Dest::create(dired);
604 let lowered = &mut [0; MAXENCODE];
574 let lowered = &mut [0; MAXENCODE];
575 let mut lowered_dest = Dest::create(lowered);
605 let auxed = &mut [0; MAXENCODE];
576 let auxed = &mut [0; MAXENCODE];
577 let mut auxed_dest = Dest::create(auxed);
606 let baselen = (src.len() - 5) * 3;
578 let baselen = (src.len() - 5) * 3;
607 if baselen >= MAXENCODE {
579 if baselen >= MAXENCODE {
608 panic!("path_encode::hash_encore: string too long: {}", baselen)
580 panic!("path_encode::hash_encore: string too long: {}", baselen)
609 };
581 };
610 let dirlen = encode_dir(Some(&mut dired[..]), src);
582 encode_dir(&mut dired_dest, src);
583 let dirlen = dired_dest.len;
611 let sha = Sha1::digest(&dired[..dirlen]);
584 let sha = Sha1::digest(&dired[..dirlen]);
612 let lowerlen = lower_encode(Some(&mut lowered[..]), &dired[..dirlen][5..]);
585 lower_encode(&mut lowered_dest, &dired[..dirlen][5..]);
613 let auxlen = aux_encode(Some(&mut auxed[..]), &lowered[..lowerlen]);
586 let lowerlen = lowered_dest.len;
587 aux_encode(&mut auxed_dest, &lowered[..lowerlen]);
588 let auxlen = auxed_dest.len;
614 hash_mangle(&auxed[..auxlen], &sha)
589 hash_mangle(&auxed[..auxlen], &sha)
615 }
590 }
616
591
617 pub fn path_encode(path: &[u8]) -> Vec<u8> {
592 pub fn path_encode(path: &[u8]) -> Vec<u8> {
618 let newlen = if path.len() <= MAXSTOREPATHLEN {
593 let newlen = if path.len() <= MAXSTOREPATHLEN {
619 basic_encode(None, path)
594 let mut measure = Dest::create_measure();
595 basic_encode(&mut measure, path);
596 measure.len
620 } else {
597 } else {
621 MAXSTOREPATHLEN + 1
598 MAXSTOREPATHLEN + 1
622 };
599 };
623 if newlen <= MAXSTOREPATHLEN {
600 if newlen <= MAXSTOREPATHLEN {
624 if newlen == path.len() {
601 if newlen == path.len() {
625 path.to_vec()
602 path.to_vec()
626 } else {
603 } else {
627 let mut res = vec![0; newlen];
604 let mut res = vec![0; newlen];
628 basic_encode(Some(&mut res), path);
605 let mut dest = Dest::create(&mut res);
606 basic_encode(&mut dest, path);
607 assert!(dest.len == newlen);
629 res
608 res
630 }
609 }
631 } else {
610 } else {
632 hash_encode(path)
611 hash_encode(path)
633 }
612 }
634 }
613 }
635
614
636 #[cfg(test)]
615 #[cfg(test)]
637 mod tests {
616 mod tests {
638 use super::*;
617 use super::*;
639 use crate::utils::hg_path::HgPathBuf;
618 use crate::utils::hg_path::HgPathBuf;
640
619
641 #[test]
620 #[test]
642 fn test_long_filename_at_root() {
621 fn test_long_filename_at_root() {
643 let input = b"data/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
622 let input = b"data/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
644 let expected = b"dh/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.i708243a2237a7afae259ea3545a72a2ef11c247b.i";
623 let expected = b"dh/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.i708243a2237a7afae259ea3545a72a2ef11c247b.i";
645 let res = path_encode(input);
624 let res = path_encode(input);
646 assert_eq!(
625 assert_eq!(
647 HgPathBuf::from_bytes(&res),
626 HgPathBuf::from_bytes(&res),
648 HgPathBuf::from_bytes(expected)
627 HgPathBuf::from_bytes(expected)
649 );
628 );
650 }
629 }
651 }
630 }
General Comments 0
You need to be logged in to leave comments. Login now