##// END OF EJS Templates
tests: use sha256line.py instead of /dev/random in test-censor.t (issue6858)...
tests: use sha256line.py instead of /dev/random in test-censor.t (issue6858) Sometimes the systems that run our test suite don't have enough entropy and they cannot produce target file of the expected size using /dev/random, which results in test failures. Switching to /dev/urandom would give us way more available data at the cost of it being less "random", but we don't really need to use entropy for this task at all, since we only care if the file size after compression is big enough to not be stored inline in the revlog. So let's use something that we already have used to generate this kind of data in other tests.

File last commit:

r51264:3f513754 stable
r52255:e7be2ddf stable
Show More
path_encode.rs
639 lines | 18.5 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: Use a maintained crate for SHA-1 hashing...
r48171 use sha1::{Digest, Sha1};
Antoine Cezar
hg-core: add path_encode...
r46110
#[derive(PartialEq, Debug)]
#[allow(non_camel_case_types)]
Raphaël Gomès
rust-clippy: fix most warnings in `hg-core`...
r50825 #[allow(clippy::upper_case_acronyms)]
Antoine Cezar
hg-core: add path_encode...
r46110 enum path_state {
START, /* first byte of a path component */
A, /* "AUX" */
AU,
THIRD, /* third of a 3-byte sequence, e.g. "AUX", "NUL" */
C, /* "CON" or "COMn" */
CO,
COMLPT, /* "COM" or "LPT" */
COMLPTn,
L,
LP,
N,
NU,
P, /* "PRN" */
PR,
LDOT, /* leading '.' */
DOT, /* '.' in a non-leading position */
H, /* ".h" */
HGDI, /* ".hg", ".d", or ".i" */
SPACE,
DEFAULT, /* byte of a path component after the first */
}
/* state machine for dir-encoding */
#[allow(non_camel_case_types)]
Raphaël Gomès
rust-clippy: fix most warnings in `hg-core`...
r50825 #[allow(clippy::upper_case_acronyms)]
Antoine Cezar
hg-core: add path_encode...
r46110 enum dir_state {
DDOT,
DH,
DHGDI,
DDEFAULT,
}
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 trait Sink {
fn write_byte(&mut self, c: u8);
fn write_bytes(&mut self, c: &[u8]);
}
Antoine Cezar
hg-core: add path_encode...
r46110 fn inset(bitset: &[u32; 8], c: u8) -> bool {
bitset[(c as usize) >> 5] & (1 << (c & 31)) != 0
}
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 const MAXENCODE: usize = 4096 * 4;
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 struct DestArr<const N: usize> {
buf: [u8; N],
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 pub len: usize,
}
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 impl<const N: usize> DestArr<N> {
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 pub fn create() -> Self {
DestArr {
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 buf: [0; N],
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 len: 0,
}
}
pub fn contents(&self) -> &[u8] {
&self.buf[..self.len]
}
}
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 impl<const N: usize> Sink for DestArr<N> {
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 fn write_byte(&mut self, c: u8) {
self.buf[self.len] = c;
self.len += 1;
}
fn write_bytes(&mut self, src: &[u8]) {
self.buf[self.len..self.len + src.len()].copy_from_slice(src);
self.len += src.len();
}
}
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 struct MeasureDest {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 pub len: usize,
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 impl Sink for Vec<u8> {
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 fn write_byte(&mut self, c: u8) {
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 self.push(c)
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 }
fn write_bytes(&mut self, src: &[u8]) {
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 self.extend_from_slice(src)
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 impl MeasureDest {
fn create() -> Self {
Self { len: 0 }
}
}
impl Sink for MeasureDest {
fn write_byte(&mut self, _c: u8) {
self.len += 1;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 }
fn write_bytes(&mut self, src: &[u8]) {
self.len += src.len();
}
}
fn hexencode(dest: &mut impl Sink, c: u8) {
Antoine Cezar
hg-core: add path_encode...
r46110 let hexdigit = b"0123456789abcdef";
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(hexdigit[(c as usize) >> 4]);
dest.write_byte(hexdigit[(c as usize) & 15]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
/* 3-byte escape: tilde followed by two hex digits */
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn escape3(dest: &mut impl Sink, c: u8) {
dest.write_byte(b'~');
hexencode(dest, c);
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn encode_dir(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let mut state = dir_state::DDEFAULT;
let mut i = 0;
while i < src.len() {
match state {
dir_state::DDOT => match src[i] {
b'd' | b'i' => {
state = dir_state::DHGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'h' => {
state = dir_state::DH;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = dir_state::DDEFAULT;
}
},
dir_state::DH => {
if src[i] == b'g' {
state = dir_state::DHGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = dir_state::DDEFAULT;
}
}
dir_state::DHGDI => {
if src[i] == b'/' {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b".hg");
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
state = dir_state::DDEFAULT;
}
dir_state::DDEFAULT => {
if src[i] == b'.' {
state = dir_state::DDOT
}
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
}
}
}
fn _encode(
twobytes: &[u32; 8],
onebyte: &[u32; 8],
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest: &mut impl Sink,
Antoine Cezar
hg-core: add path_encode...
r46110 src: &[u8],
encodedir: bool,
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 ) {
Antoine Cezar
hg-core: add path_encode...
r46110 let mut state = path_state::START;
let mut i = 0;
let len = src.len();
while i < len {
match state {
path_state::START => match src[i] {
b'/' => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'.' => {
state = path_state::LDOT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b' ' => {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'a' => {
state = path_state::A;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'c' => {
state = path_state::C;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'l' => {
state = path_state::L;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'n' => {
state = path_state::N;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'p' => {
state = path_state::P;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
}
},
path_state::A => {
if src[i] == b'u' {
state = path_state::AU;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::AU => {
if src[i] == b'x' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::THIRD => {
state = path_state::DEFAULT;
match src[i] {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 b'.' | b'/' | b'\0' => escape3(dest, src[i - 1]),
Antoine Cezar
hg-core: add path_encode...
r46110 _ => i -= 1,
}
}
path_state::C => {
if src[i] == b'o' {
state = path_state::CO;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::CO => {
if src[i] == b'm' {
state = path_state::COMLPT;
i += 1;
} else if src[i] == b'n' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::COMLPT => {
if src[i] >= b'1' && src[i] <= b'9' {
state = path_state::COMLPTn;
i += 1;
} else {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i - 1]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
path_state::COMLPTn => {
state = path_state::DEFAULT;
match src[i] {
b'.' | b'/' | b'\0' => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i - 2]);
dest.write_byte(src[i - 1]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
_ => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(&src[i - 2..i]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
}
path_state::L => {
if src[i] == b'p' {
state = path_state::LP;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::LP => {
if src[i] == b't' {
state = path_state::COMLPT;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::N => {
if src[i] == b'u' {
state = path_state::NU;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::NU => {
if src[i] == b'l' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::P => {
if src[i] == b'r' {
state = path_state::PR;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::PR => {
if src[i] == b'n' {
state = path_state::THIRD;
i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::LDOT => match src[i] {
b'd' | b'i' => {
state = path_state::HGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'h' => {
state = path_state::H;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
}
},
path_state::DOT => match src[i] {
b'/' | b'\0' => {
state = path_state::START;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~2e");
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'd' | b'i' => {
state = path_state::HGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'.');
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
b'h' => {
state = path_state::H;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b".h");
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'.');
Antoine Cezar
hg-core: add path_encode...
r46110 }
},
path_state::H => {
if src[i] == b'g' {
state = path_state::HGDI;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
} else {
state = path_state::DEFAULT;
}
}
path_state::HGDI => {
if src[i] == b'/' {
state = path_state::START;
if encodedir {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b".hg");
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1
} else {
state = path_state::DEFAULT;
}
}
path_state::SPACE => match src[i] {
b'/' | b'\0' => {
state = path_state::START;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~20");
dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
state = path_state::DEFAULT;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b' ');
Antoine Cezar
hg-core: add path_encode...
r46110 }
},
path_state::DEFAULT => {
while i != len && inset(onebyte, src[i]) {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
if i == len {
break;
}
match src[i] {
b'.' => {
state = path_state::DOT;
i += 1
}
b' ' => {
state = path_state::SPACE;
i += 1
}
b'/' => {
state = path_state::START;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'/');
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
_ => {
if inset(onebyte, src[i]) {
loop {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
if !(i < len && inset(onebyte, src[i])) {
break;
}
}
} else if inset(twobytes, src[i]) {
let c = src[i];
i += 1;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'_');
dest.write_byte(if c == b'_' {
b'_'
} else {
c + 32
});
Antoine Cezar
hg-core: add path_encode...
r46110 } else {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i]);
Antoine Cezar
hg-core: add path_encode...
r46110 i += 1;
}
}
}
}
}
}
match state {
path_state::START => (),
path_state::A => (),
path_state::AU => (),
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 path_state::THIRD => escape3(dest, src[i - 1]),
Antoine Cezar
hg-core: add path_encode...
r46110 path_state::C => (),
path_state::CO => (),
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 path_state::COMLPT => dest.write_byte(src[i - 1]),
Antoine Cezar
hg-core: add path_encode...
r46110 path_state::COMLPTn => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, src[i - 2]);
dest.write_byte(src[i - 1]);
Antoine Cezar
hg-core: add path_encode...
r46110 }
path_state::L => (),
path_state::LP => (),
path_state::N => (),
path_state::NU => (),
path_state::P => (),
path_state::PR => (),
path_state::LDOT => (),
path_state::DOT => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~2e");
Antoine Cezar
hg-core: add path_encode...
r46110 }
path_state::H => (),
path_state::HGDI => (),
path_state::SPACE => {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"~20");
Antoine Cezar
hg-core: add path_encode...
r46110 }
path_state::DEFAULT => (),
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 }
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn basic_encode(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let twobytes: [u32; 8] = [0, 0, 0x87ff_fffe, 0, 0, 0, 0, 0];
let onebyte: [u32; 8] =
[1, 0x2bff_3bfa, 0x6800_0001, 0x2fff_ffff, 0, 0, 0, 0];
_encode(&twobytes, &onebyte, dest, src, true)
}
const MAXSTOREPATHLEN: usize = 120;
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn lower_encode(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let onebyte: [u32; 8] =
[1, 0x2bff_fbfb, 0xe800_0001, 0x2fff_ffff, 0, 0, 0, 0];
let lower: [u32; 8] = [0, 0, 0x07ff_fffe, 0, 0, 0, 0, 0];
for c in src {
if inset(&onebyte, *c) {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(*c)
Antoine Cezar
hg-core: add path_encode...
r46110 } else if inset(&lower, *c) {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(*c + 32)
Antoine Cezar
hg-core: add path_encode...
r46110 } else {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 escape3(dest, *c)
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
}
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 fn aux_encode(dest: &mut impl Sink, src: &[u8]) {
Antoine Cezar
hg-core: add path_encode...
r46110 let twobytes = [0; 8];
let onebyte: [u32; 8] = [!0, 0xffff_3ffe, !0, !0, !0, !0, !0, !0];
_encode(&twobytes, &onebyte, dest, src, false)
}
fn hash_mangle(src: &[u8], sha: &[u8]) -> Vec<u8> {
let dirprefixlen = 8;
let maxshortdirslen = 68;
let last_slash = src.iter().rposition(|b| *b == b'/');
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 let basename_start = match last_slash {
Some(slash) => slash + 1,
None => 0,
};
let basename = &src[basename_start..];
let ext = match basename.iter().rposition(|b| *b == b'.') {
None => &[],
Some(dot) => &basename[dot..],
Antoine Cezar
hg-core: add path_encode...
r46110 };
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 let mut dest = Vec::with_capacity(MAXSTOREPATHLEN);
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_bytes(b"dh/");
Antoine Cezar
hg-core: add path_encode...
r46110
Arseniy Alekseyev
rhg: fix a bug in path_encode...
r50991 if let Some(last_slash) = last_slash {
for slice in src[..last_slash].split(|b| *b == b'/') {
Antoine Cezar
hg-core: add path_encode...
r46110 let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)];
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 if dest.len() + slice.len() > maxshortdirslen + 3 {
Antoine Cezar
hg-core: add path_encode...
r46110 break;
Arseniy Alekseyev
rhg: don't crash on empty directory names in path_encode, just in case...
r51264 }
if let Some(last_char) = slice.last() {
if *last_char == b'.' || *last_char == b' ' {
Arseniy Alekseyev
rhg: fix a bug in path encoding, demonstrated in the parent commit
r51263 dest.write_bytes(&slice[0..slice.len() - 1]);
dest.write_byte(b'_');
} else {
dest.write_bytes(slice);
}
Arseniy Alekseyev
rhg: don't crash on empty directory names in path_encode, just in case...
r51264 };
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 dest.write_byte(b'/');
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 let used = dest.len() + 40 + ext.len();
Antoine Cezar
hg-core: add path_encode...
r46110
if MAXSTOREPATHLEN > used {
let slop = MAXSTOREPATHLEN - used;
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 let len = std::cmp::min(basename.len(), slop);
dest.write_bytes(&basename[..len])
Antoine Cezar
hg-core: add path_encode...
r46110 }
for c in sha {
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 hexencode(&mut dest, *c);
Antoine Cezar
hg-core: add path_encode...
r46110 }
Arseniy Alekseyev
rhg: in path_encode, simplify a bit more...
r51062 dest.write_bytes(ext);
Arseniy Alekseyev
rhg: in path_encode, be a bit more conservative about memory usage...
r51061 dest.shrink_to_fit();
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 dest
Antoine Cezar
hg-core: add path_encode...
r46110 }
fn hash_encode(src: &[u8]) -> Vec<u8> {
Arseniy Alekseyev
rhg: in path_encode, make DestArr generic over its size
r51056 let mut dired: DestArr<MAXENCODE> = DestArr::create();
let mut lowered: DestArr<MAXENCODE> = DestArr::create();
let mut auxed: DestArr<MAXENCODE> = DestArr::create();
Antoine Cezar
hg-core: add path_encode...
r46110 let baselen = (src.len() - 5) * 3;
if baselen >= MAXENCODE {
panic!("path_encode::hash_encore: string too long: {}", baselen)
};
Arseniy Alekseyev
rhg: in path_encode add a DestArr type...
r51055 encode_dir(&mut dired, src);
let sha = Sha1::digest(dired.contents());
lower_encode(&mut lowered, &dired.contents()[5..]);
aux_encode(&mut auxed, lowered.contents());
hash_mangle(auxed.contents(), &sha)
Antoine Cezar
hg-core: add path_encode...
r46110 }
pub fn path_encode(path: &[u8]) -> Vec<u8> {
let newlen = if path.len() <= MAXSTOREPATHLEN {
Arseniy Alekseyev
rhg: in path_encode, split Dest into VecDest and MeasureDest...
r51058 let mut measure = MeasureDest::create();
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 basic_encode(&mut measure, path);
measure.len
Antoine Cezar
hg-core: add path_encode...
r46110 } else {
Arseniy Alekseyev
rhg: small refactor: stop using a magical constant "+ 1"...
r51060 return hash_encode(path);
Antoine Cezar
hg-core: add path_encode...
r46110 };
if newlen <= MAXSTOREPATHLEN {
if newlen == path.len() {
path.to_vec()
} else {
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 let mut dest = Vec::with_capacity(newlen);
Arseniy Alekseyev
rhg: reduce verbosity in path_encode by using a trait for writing...
r51054 basic_encode(&mut dest, path);
Arseniy Alekseyev
rhg: in path_encode, use Vec directly instead of VecDest...
r51059 assert!(dest.len() == newlen);
dest
Antoine Cezar
hg-core: add path_encode...
r46110 }
} else {
Raphaël Gomès
rust-clippy: fix most warnings in `hg-core`...
r50825 hash_encode(path)
Antoine Cezar
hg-core: add path_encode...
r46110 }
}
Arseniy Alekseyev
rhg: demonstrate a bug in path_encode...
r50990
#[cfg(test)]
mod tests {
use super::*;
use crate::utils::hg_path::HgPathBuf;
#[test]
Arseniy Alekseyev
rhg: show a bug in the rust implementation of path_encode introduced recently...
r51262 fn test_dirname_ends_with_underscore() {
let input = b"data/dir1234.foo/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
Arseniy Alekseyev
rhg: fix a bug in path encoding, demonstrated in the parent commit
r51263 let expected = b"dh/dir1234_/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.if2e9ce59e095eff5f8f334dc809e65606a0aa50b.i";
Arseniy Alekseyev
rhg: show a bug in the rust implementation of path_encode introduced recently...
r51262 let res = path_encode(input);
assert_eq!(
HgPathBuf::from_bytes(&res),
HgPathBuf::from_bytes(expected)
);
}
#[test]
Arseniy Alekseyev
rhg: demonstrate a bug in path_encode...
r50990 fn test_long_filename_at_root() {
let input = b"data/ABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJABCDEFGHIJ.i";
let expected = b"dh/abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij.i708243a2237a7afae259ea3545a72a2ef11c247b.i";
let res = path_encode(input);
assert_eq!(
HgPathBuf::from_bytes(&res),
HgPathBuf::from_bytes(expected)
);
}
}