|
31 | 31 |
|
32 | 32 | import logging
|
33 | 33 | import re
|
| 34 | +import sys |
34 | 35 | from io import BytesIO
|
35 | 36 | from typing import (
|
36 | 37 | Any,
|
|
70 | 71 | from ..errors import STREAM_TRUNCATED_PREMATURELY, PdfReadError, PdfStreamError
|
71 | 72 | from ._base import (
|
72 | 73 | BooleanObject,
|
| 74 | + ByteStringObject, |
73 | 75 | FloatObject,
|
74 | 76 | IndirectObject,
|
75 | 77 | NameObject,
|
|
81 | 83 | from ._fit import Fit
|
82 | 84 | from ._utils import read_hex_string_from_stream, read_string_from_stream
|
83 | 85 |
|
| 86 | +if sys.version_info >= (3, 11): |
| 87 | + from typing import Self |
| 88 | +else: |
| 89 | + from typing_extensions import Self |
| 90 | + |
84 | 91 | logger = logging.getLogger(__name__)
|
85 | 92 | NumberSigns = b"+-"
|
86 | 93 | IndirectPattern = re.compile(rb"[+-]?(\d+)\s+(\d+)\s+R[^a-zA-Z]")
|
@@ -121,6 +128,65 @@ def items(self) -> Iterable[Any]:
|
121 | 128 | """Emulate DictionaryObject.items for a list (index, object)."""
|
122 | 129 | return enumerate(self)
|
123 | 130 |
|
| 131 | + def _to_lst(self, lst: Any) -> List[Any]: |
| 132 | + # Convert to list, internal |
| 133 | + if isinstance(lst, (list, tuple, set)): |
| 134 | + pass |
| 135 | + elif isinstance(lst, PdfObject): |
| 136 | + lst = [lst] |
| 137 | + elif isinstance(lst, str): |
| 138 | + if lst[0] == "/": |
| 139 | + lst = [NameObject(lst)] |
| 140 | + else: |
| 141 | + lst = [TextStringObject(lst)] |
| 142 | + elif isinstance(lst, bytes): |
| 143 | + lst = [ByteStringObject(lst)] |
| 144 | + else: # for numbers,... |
| 145 | + lst = [lst] |
| 146 | + return lst |
| 147 | + |
| 148 | + def __add__(self, lst: Any) -> "ArrayObject": |
| 149 | + """ |
| 150 | + Allow extension by adding list or add one element only |
| 151 | +
|
| 152 | + Args: |
| 153 | + lst: any list, tuples are extended the list. |
| 154 | + other types(numbers,...) will be appended. |
| 155 | + if str is passed it will be converted into TextStringObject |
| 156 | + or NameObject (if starting with "/") |
| 157 | + if bytes is passed it will be converted into ByteStringObject |
| 158 | +
|
| 159 | + Returns: |
| 160 | + ArrayObject with all elements |
| 161 | + """ |
| 162 | + temp = ArrayObject(self) |
| 163 | + temp.extend(self._to_lst(lst)) |
| 164 | + return temp |
| 165 | + |
| 166 | + def __iadd__(self, lst: Any) -> Self: |
| 167 | + """ |
| 168 | + Allow extension by adding list or add one element only |
| 169 | +
|
| 170 | + Args: |
| 171 | + lst: any list, tuples are extended the list. |
| 172 | + other types(numbers,...) will be appended. |
| 173 | + if str is passed it will be converted into TextStringObject |
| 174 | + or NameObject (if starting with "/") |
| 175 | + if bytes is passed it will be converted into ByteStringObject |
| 176 | + """ |
| 177 | + self.extend(self._to_lst(lst)) |
| 178 | + return self |
| 179 | + |
| 180 | + def __isub__(self, lst: Any) -> Self: |
| 181 | + """Allow to remove items""" |
| 182 | + for x in self._to_lst(lst): |
| 183 | + try: |
| 184 | + x = self.index(x) |
| 185 | + del self[x] |
| 186 | + except ValueError: |
| 187 | + pass |
| 188 | + return self |
| 189 | + |
124 | 190 | def write_to_stream(
|
125 | 191 | self, stream: StreamType, encryption_key: Union[None, str, bytes] = None
|
126 | 192 | ) -> None:
|
|
0 commit comments