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