-
-
Notifications
You must be signed in to change notification settings - Fork 176
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
169eedc
commit 2e8430a
Showing
1 changed file
with
47 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -259,25 +259,6 @@ def from_ical(cls, st, strict=False): | |
% (param, exc)) | ||
return result | ||
|
||
|
||
def escape_string(val): | ||
# '%{:02X}'.format(i) | ||
return val.replace(r'\,', '%2C').replace(r'\:', '%3A')\ | ||
.replace(r'\;', '%3B').replace(r'\\', '%5C') | ||
|
||
|
||
def unescape_string(val): | ||
return val.replace('%2C', ',').replace('%3A', ':')\ | ||
.replace('%3B', ';').replace('%5C', '\\') | ||
|
||
|
||
def unescape_list_or_string(val): | ||
if isinstance(val, list): | ||
return [unescape_string(s) for s in val] | ||
else: | ||
return unescape_string(val) | ||
|
||
|
||
######################################### | ||
# parsing and generation of content lines | ||
|
||
|
@@ -315,34 +296,68 @@ def from_parts(cls, name, params, values, sorted=True): | |
return cls(f'{name}:{values}') | ||
|
||
def parts(self): | ||
"""Split the content line up into (name, parameters, values) parts. | ||
""" | ||
Split the content line up into (name, parameters, values) parts. | ||
Example with parameter: | ||
DESCRIPTION;ALTREP="cid:[email protected]":The Fall'98 Wild | ||
Example without parameters: | ||
DESCRIPTION:The Fall'98 Wild | ||
https://icalendar.org/iCalendar-RFC-5545/3-2-property-parameters.html | ||
""" | ||
try: | ||
st = escape_string(self) | ||
st = self | ||
name_split = None | ||
value_split = None | ||
in_quotes = False | ||
# Any character can be escaped using a backslash, e.g.: "test\:test" | ||
quote_character = False | ||
for i, ch in enumerate(st): | ||
if not in_quotes: | ||
if ch in ':;' and not name_split: | ||
name_split = i | ||
if ch == ':' and not value_split: | ||
value_split = i | ||
# We can also quote using quotation marks. This ignores any output, until another quote appears. | ||
if ch == '"': | ||
in_quotes = not in_quotes | ||
name = unescape_string(st[:name_split]) | ||
continue | ||
|
||
# Ignore input, as we are currently in quotation mark quotes | ||
if in_quotes: | ||
continue | ||
|
||
# Skip quoted character | ||
if quote_character: | ||
quote_character = False | ||
continue | ||
|
||
# The next character should be ignored | ||
if ch == '\\': | ||
quote_character = True | ||
continue | ||
|
||
# The name ends either after the parameter or value delimiter | ||
if ch in ':;' and not name_split: | ||
name_split = i | ||
|
||
# The value starts after the value delimiter | ||
if ch == ':' and not value_split: | ||
value_split = i | ||
|
||
# Get name | ||
name = st[:name_split] | ||
if not name: | ||
raise ValueError('Key name is required') | ||
validate_token(name) | ||
|
||
# Check if parameters are empty | ||
if not name_split or name_split + 1 == value_split: | ||
raise ValueError('Invalid content line') | ||
|
||
# Get parameters (text between ; and :) | ||
params = Parameters.from_ical(st[name_split + 1: value_split], | ||
strict=self.strict) | ||
params = Parameters( | ||
(unescape_string(key), unescape_list_or_string(value)) | ||
for key, value in iter(params.items()) | ||
) | ||
values = unescape_string(st[value_split + 1:]) | ||
|
||
# Get the value after the : | ||
values = st[value_split + 1:] | ||
return (name, params, values) | ||
except ValueError as exc: | ||
raise ValueError( | ||
|