Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 52 additions & 11 deletions src/cosmetic_filter_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,67 @@ impl SpecificFilterType {
}
}

/// Encodes permission bits in the last byte of a script string
/// Returns the script with permission byte prepended
/// Encodes permission bits in the last 2 ascii chars of a script string
/// Returns the script with permission appended
pub(crate) fn encode_script_with_permission(
mut script: String,
permission: PermissionMask,
) -> String {
script.push(permission.to_bits() as char);
const HEX_CHARS: &[u8; 16] = b"0123456789abcdef";
let high = (permission.to_bits() >> 4) as usize;
let low = (permission.to_bits() & 0x0f) as usize;

script.push(HEX_CHARS[high] as char);
script.push(HEX_CHARS[low] as char);
script
}

/// Decodes permission bits from the last byte of a script string
/// Decodes permission bits from the last 2 ascii chars of a script string
/// Returns (permission, script) tuple
pub(crate) fn decode_script_with_permission(encoded_script: &str) -> (PermissionMask, &str) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. Can we change encoded script + permissions to be &[u8] in all instances? Should make it harder to misuse, especially considering that Rust APIs widely assume a &str is valid Unicode data.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, that's problematic: it hits the flatbuffer format limitations. It doesn't support arrays of arrays, so we have to wrap it in a new table. That will consume extra memory and makes the code less clear.

if encoded_script.is_empty() {
return (PermissionMask::default(), encoded_script);
if encoded_script.len() < 2 {
return (PermissionMask::default(), "");
}
let mut last_chars = encoded_script.char_indices().rev();
// unwrap: length >= 2 asserted above
let (digit2, digit1) = (last_chars.next().unwrap(), last_chars.next().unwrap());
fn parse_hex(c: char) -> Option<u8> {
match c {
'0'..='9' => Some(c as u8 - b'0'),
'a'..='f' => Some(c as u8 - b'a' + 10),
_ => None,
}
}
if let (Some(d1), Some(d2)) = (parse_hex(digit1.1), parse_hex(digit2.1)) {
let permission = PermissionMask::from_bits(d1 << 4 | d2);
(permission, &encoded_script[..digit1.0])
} else {
(PermissionMask::default(), "")
}
}

#[cfg(test)]
mod tests {
use super::*;

let last_char = encoded_script.chars().last().unwrap();
let permission_bits = last_char as u8;
let permission = PermissionMask::from_bits(permission_bits);
let script = &encoded_script[..encoded_script.len() - 1];
(permission, script)
#[test]
fn test_encode_decode_script_with_permission() {
for permission in 0u8..=255u8 {
let script = "console.log('测试 🚀 emoji')".to_string();
let permission = PermissionMask::from_bits(permission);

let encoded = encode_script_with_permission(script.clone(), permission);
let (decoded_permission, decoded_script) = decode_script_with_permission(&encoded);

assert_eq!(decoded_permission.to_bits(), permission.to_bits());
assert_eq!(decoded_script, script);
}
}

#[test]
fn test_encode_decode_script_with_permission_empty() {
let (permission, script) = decode_script_with_permission("");
assert_eq!(permission.to_bits(), 0);
assert_eq!(script, "");
}
}
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ pub mod cosmetic_filter_cache;
mod cosmetic_filter_cache_builder;
mod cosmetic_filter_utils;
mod data_format;
mod engine;
pub mod engine;
pub mod filters;
mod flatbuffers;
pub mod lists;
Expand Down
4 changes: 2 additions & 2 deletions src/resources/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ mod resource_storage;
pub(crate) use resource_storage::parse_scriptlet_args;
#[doc(inline)]
pub use resource_storage::{
AddResourceError, InMemoryResourceStorage, ResourceStorage, ResourceStorageBackend,
ScriptletResourceError,
AddResourceError, InMemoryResourceStorage, ResourceImpl, ResourceStorage,
ResourceStorageBackend, ScriptletResourceError,
};

use memchr::memrchr as find_char_reverse;
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -237,9 +237,9 @@ mod tests {
);
}
let expected_hash: u64 = if cfg!(feature = "css-validation") {
1870862363610703254
6149900431907845995
} else {
17169786507112655088
4163862738495854511
};

assert_eq!(hash(&data), expected_hash, "{}", HASH_MISMATCH_MSG);
Expand Down