Skip to content

Commit

Permalink
Don't allow unescaped characters
Browse files Browse the repository at this point in the history
  • Loading branch information
arisktfx committed Feb 15, 2024
1 parent 8894322 commit f46bc9f
Show file tree
Hide file tree
Showing 3 changed files with 412 additions and 285 deletions.
84 changes: 45 additions & 39 deletions openformats/formats/android_unescaped.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,25 @@
class AndroidUnescapedHandler(AndroidHandler):
def _create_string(self, name, text, comment, product, child, pluralized=False):
"""Creates a string and returns it. If empty string it returns None.
Also checks if the provided text contains unescaped characters which are
invalid for the Android XML format.
:param text: The strings text.
:param name: The name of the string.
:param comment: The developer's comment the string might have.
:param product: Extra context for the string.
:param child: The child tag that the string is created from. Used to find
line numbers when errors occur.
:returns: Returns an OpenString object if the text is not empty else None.
:param child: The child tag that the string is created from.
Used to find line numbers when errors occur.
:returns: Returns an OpenString object if the text is not empty
else None.
"""
AndroidUnescapedHandler._check_unescaped_characters(text)
if XMLUtils.validate_not_empty_string(
self.transcriber,
text,
child,
error_context={"main_tag": "plural", "child_tag": "item"},
):
text = self._escape_quotes(text)
if (name, product) in self.existing_hashes:
if child.tag in self.existing_hashes[(name, product)]:
format_dict = {"name": name, "child_tag": child.tag}
Expand Down Expand Up @@ -60,58 +63,64 @@ def _create_string(self, name, text, comment, product, child, pluralized=False):
return string
return None

def _escape_quotes(self, text):
"""Allow single and double quotes to be uploaded unescaped but they must be
returned escaped
@staticmethod
def _check_unescaped_characters(text):
"""Checks if the provided text contains unescaped characters which are
invalid for the Android XML format.
"""
if type(text) == dict:
text = AndroidUnescapedHandler._escape_quotes_plural_string(text)
text = AndroidUnescapedHandler._check_unescaped_characters_in_plural_string(
text
)
else:
text = AndroidUnescapedHandler._escape_quotes_simple_string(text)
text = AndroidUnescapedHandler._check_unescaped_characters_in_simple_string(
text
)

return text

@staticmethod
def _escape_quotes_simple_string(text):
text, protected_tags = AndroidUnescapedHandler._protect_inline_tags(text)
def _check_unescaped_characters_in_simple_string(text):
try:
protected_string, _ = AndroidUnescapedHandler._protect_inline_tags(text)
except Exception as e:
raise ParseError(
"Error escaping the string. Please check for any open tags or any "
"dangling < characters"
) from e

text = re.sub(
not_allowed_unescaped = [
r"(?<!\\)'",
"".join([DumbXml.BACKSLASH, DumbXml.SINGLE_QUOTE]),
text,
)
text = re.sub(
r'(?<!\\)"',
"".join([DumbXml.BACKSLASH, DumbXml.DOUBLE_QUOTES]),
text,
)

text = AndroidUnescapedHandler._unprotect_inline_tags(text, protected_tags)

return text
r"(?<!\\)@",
r"(?<!\\)\?",
r"(?<!\\)\n",
r"(?<!\\)\t",
]

for pattern in not_allowed_unescaped:
if re.search(pattern, protected_string):
raise ParseError(
"You have one or more unescaped characters from the following "
f"list ', \", @, ?, \\n, \\t in the string : {text}"
)

@staticmethod
def _escape_quotes_plural_string(text):
escaped_dict = {}
for key, string in text.items():
escaped_string = AndroidUnescapedHandler._escape_quotes_simple_string(
string
)
escaped_dict[key] = escaped_string

return escaped_dict
def _check_unescaped_characters_in_plural_string(text):
for _, string in text.items():
AndroidUnescapedHandler._check_unescaped_characters_in_simple_string(string)

@staticmethod
def _protect_inline_tags(text):
"""Protect INLINE_TAGS from escaping single and double quotes"""
"""Protect INLINE_TAGS from escaping special characters"""
protected_tags = {}
wrapped_text = f"<x>{text}</x>"
parsed = DumbXml(wrapped_text)
children_iterator = parsed.find_children()

for child in children_iterator:
if child.tag in AndroidHandler.INLINE_TAGS:
child_content = child.source[child.start : child.end]
child_content = child.source[child.position : child.tail_position]
string_hash = md5(child_content.encode("utf-8")).hexdigest()
text = text.replace(child_content, string_hash)
protected_tags[string_hash] = child_content
Expand All @@ -131,11 +140,8 @@ def escape(string):
string, protected_tags = AndroidUnescapedHandler._protect_inline_tags(
string
)
except Exception as e:
raise ParseError(
"Error escaping the string. Please check for any open tags or any "
"dangling < characters"
)
except Exception as _:
return AndroidHandler.escape(string)

string = AndroidHandler.escape(string)
string = (
Expand Down
Loading

0 comments on commit f46bc9f

Please sign in to comment.