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