mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-15 15:22:54 +00:00
A language tag longer than 35 characters is still a tag
BCP 47 sets no maximum length; 35 characters is only the least a protocol must hold. A well formed tag such as en-US-u-ca-gregory-nu-latn-co-phonebk was left out of both exports. The bound is now 255, kept only so a PDF's /Lang can't put an unbounded string in the file.
This commit is contained in:
1 parent
a699e13305
commit
0cae1c518b
2 files changed
+12
-3
No files matched your search
@@ -8,14 +8,18 @@ pub(crate) fn allowed(c: char) -> bool {
|
||||
matches!(c, '\t' | '\n' | '\r') || !(c.is_ascii_control() || c == '\u{FFFE}' || c == '\u{FFFF}')
|
||||
}
|
||||
|
||||
/// The longest language tag the exports write. BCP 47 sets no maximum (35 characters is only
|
||||
/// the least a protocol must hold), so this bounds only what a PDF's `/Lang` can put in a file.
|
||||
const LONGEST_TAG: usize = 255;
|
||||
|
||||
/// `lang` when it is a well formed language tag (BCP 47, as a PDF's `/Lang` holds one): a primary
|
||||
/// language of two or three letters, then subtags of one to eight letters or digits, joined by
|
||||
/// hyphens, 35 characters at most. Anything else names no language.
|
||||
/// hyphens, [`LONGEST_TAG`] characters at most. Anything else names no language.
|
||||
pub(crate) fn language_tag(lang: Option<&str>) -> Option<&str> {
|
||||
let tag = lang?.trim();
|
||||
let mut subtags = tag.split('-');
|
||||
let primary = subtags.next()?;
|
||||
let well_formed = tag.len() <= 35
|
||||
let well_formed = tag.len() <= LONGEST_TAG
|
||||
&& (2..=3).contains(&primary.len())
|
||||
&& primary.bytes().all(|b| b.is_ascii_alphabetic())
|
||||
&& subtags.all(|s| (1..=8).contains(&s.len()) && s.bytes().all(|b| b.is_ascii_alphanumeric()));
|
||||
|
||||
@@ -260,6 +260,11 @@ fn word_and_html_take_the_documents_language() {
|
||||
assert!(styles(Some("ar-EG")).contains(&defaults("<w:lang w:bidi=\"ar-EG\"/>")), "right-to-left text");
|
||||
assert!(styles(Some("HE")).contains("<w:lang w:bidi=\"HE\"/>"), "right-to-left text");
|
||||
assert!(html_with_language(&pages, "Report", Some("bg-BG")).starts_with("<!DOCTYPE html>\n<html lang=\"bg-BG\">\n"));
|
||||
// A tag longer than 35 characters is still a tag.
|
||||
let long = "en-US-u-ca-gregory-nu-latn-co-phonebk";
|
||||
assert!(styles(Some(long)).contains(&format!("<w:lang w:val=\"{long}\"/>")), "{long}");
|
||||
assert!(html_with_language(&pages, "Report", Some(long)).contains(&format!("<html lang=\"{long}\">")), "{long}");
|
||||
let too_long = format!("en{}", "-abcdefgh".repeat(29));
|
||||
for lang in [
|
||||
None,
|
||||
Some(""),
|
||||
@@ -270,7 +275,7 @@ fn word_and_html_take_the_documents_language() {
|
||||
Some("bg--BG"),
|
||||
Some("bg-"),
|
||||
Some("en-US-abcdefghi"),
|
||||
Some("en-abcdefgh-abcdefgh-abcdefgh-abcdefgh"),
|
||||
Some(too_long.as_str()),
|
||||
Some("en-\"x\""),
|
||||
Some("1a-BG"),
|
||||
Some("\u{431}\u{433}-BG"),
|
||||
|
||||
Reference in new issue
Block a user