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