137 lines
3.9 KiB
Python
137 lines
3.9 KiB
Python
import enum
|
|
from dataclasses import dataclass
|
|
from typing import Iterable, Optional
|
|
|
|
from pyhanko.pdf_utils import generic
|
|
from pyhanko.pdf_utils.generic import pdf_name
|
|
|
|
__all__ = ['DevExtensionMultivalued', 'DeveloperExtension']
|
|
|
|
|
|
class DevExtensionMultivalued(enum.Enum):
|
|
"""
|
|
Setting indicating how an extension is expected to behave well w.r.t.
|
|
the new mechanism for multivalued extensions in ISO 32000-2:2020.
|
|
"""
|
|
|
|
ALWAYS = enum.auto()
|
|
"""
|
|
Always serialise this extension as a multivalued extension.
|
|
"""
|
|
|
|
NEVER = enum.auto()
|
|
"""
|
|
Never serialise this extension as a multivalued extension.
|
|
"""
|
|
|
|
MAYBE = enum.auto()
|
|
"""
|
|
Make this extension single-valued whenever possible, but allow multiple
|
|
values as well, e.g. when a different but non-comparable extension with
|
|
the same prefix is already present in the file.
|
|
"""
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DeveloperExtension:
|
|
"""
|
|
PDF developer extension designation.
|
|
"""
|
|
|
|
prefix_name: generic.NameObject
|
|
"""
|
|
Registered developer prefix.
|
|
"""
|
|
|
|
base_version: generic.NameObject
|
|
"""
|
|
Base version on to which the extension applies.
|
|
"""
|
|
|
|
extension_level: int
|
|
"""
|
|
Extension level.
|
|
"""
|
|
|
|
url: Optional[str] = None
|
|
"""
|
|
Optional URL linking to the extension's documentation.
|
|
"""
|
|
|
|
extension_revision: Optional[str] = None
|
|
"""
|
|
Optional extra revision information. Not comparable.
|
|
"""
|
|
|
|
compare_by_level: bool = False
|
|
"""
|
|
Compare developer extensions by level number.
|
|
If this value is ``True`` and a copy of this extension already exists in the
|
|
target file with a higher level number, do not override it.
|
|
If one exists with a lower level number, override it.
|
|
|
|
If this value is ``False``, the decision is based on :attr:`subsumed_by`
|
|
and :attr:`subsumes`.
|
|
|
|
.. warning::
|
|
It is generally not safe to assume that extension levels are used as a
|
|
versioning system (i.e. that higher extension levels supersede lower
|
|
ones), hence why the default is ``False``.
|
|
"""
|
|
|
|
subsumed_by: Iterable[int] = ()
|
|
"""
|
|
List of extension levels that would subsume this one. If one of these is
|
|
present in the extensions dictionary, attempting to register this extension
|
|
will not override it.
|
|
|
|
Default value: empty.
|
|
|
|
.. warning::
|
|
This parameter is ignored if :attr:`compare_by_level` is ``True``.
|
|
"""
|
|
|
|
subsumes: Iterable[int] = ()
|
|
"""
|
|
List of extensions explicitly subsumed by this one. If one of these is
|
|
present in the extensions dictionary, attempting to register this extension
|
|
will override it.
|
|
|
|
Default value: empty.
|
|
|
|
.. warning::
|
|
This parameter is ignored if :attr:`compare_by_level` is ``True``.
|
|
"""
|
|
|
|
multivalued: DevExtensionMultivalued = DevExtensionMultivalued.MAYBE
|
|
"""
|
|
Setting indicating whether this extension is expected to behave well w.r.t.
|
|
the new mechanism for multivalued extensions in ISO 32000-2:2020.
|
|
"""
|
|
|
|
def as_pdf_object(self) -> generic.DictionaryObject:
|
|
"""
|
|
Format the data in this object into a PDF dictionary for registration
|
|
into the `/Extensions` dictionary.
|
|
|
|
:return:
|
|
A :class:`.generic.DictionaryObject`.
|
|
"""
|
|
|
|
result = generic.DictionaryObject(
|
|
{
|
|
pdf_name('/Type'): pdf_name('/DeveloperExtensions'),
|
|
pdf_name('/BaseVersion'): self.base_version,
|
|
pdf_name('/ExtensionLevel'): generic.NumberObject(
|
|
self.extension_level
|
|
),
|
|
}
|
|
)
|
|
if self.url is not None:
|
|
result['/URL'] = generic.TextStringObject(self.url)
|
|
if self.extension_revision is not None:
|
|
result['/ExtensionRevision'] = generic.TextStringObject(
|
|
self.extension_revision
|
|
)
|
|
return result
|