diff options
Diffstat (limited to 'pdfrw/objects/pdfdict.py')
-rw-r--r-- | pdfrw/objects/pdfdict.py | 84 |
1 files changed, 56 insertions, 28 deletions
diff --git a/pdfrw/objects/pdfdict.py b/pdfrw/objects/pdfdict.py index 1b3f6a0..fc28492 100644 --- a/pdfrw/objects/pdfdict.py +++ b/pdfrw/objects/pdfdict.py @@ -1,18 +1,24 @@ -# A part of pdfrw (pdfrw.googlecode.com) -# Copyright (C) 2006-2012 Patrick Maupin, Austin, Texas +# A part of pdfrw (https://github.com/pmaupin/pdfrw) +# Copyright (C) 2006-2015 Patrick Maupin, Austin, Texas # MIT license -- See LICENSE.txt for details -from pdfrw.objects.pdfname import PdfName -from pdfrw.objects.pdfindirect import PdfIndirect -from pdfrw.objects.pdfobject import PdfObject +from .pdfname import PdfName, BasePdfName +from .pdfindirect import PdfIndirect +from .pdfobject import PdfObject +from ..py23_diffs import iteritems +from ..errors import PdfParseError + class _DictSearch(object): ''' Used to search for inheritable attributes. ''' + def __init__(self, basedict): self.basedict = basedict + def __getattr__(self, name, PdfName=PdfName): return self[PdfName(name)] + def __getitem__(self, name, set=set, getattr=getattr, id=id): visited = set() mydict = self.basedict @@ -27,28 +33,35 @@ class _DictSearch(object): if mydict is None: return + class _Private(object): ''' Used to store private attributes (not output to PDF files) on PdfDict classes ''' + def __init__(self, pdfdict): vars(self)['pdfdict'] = pdfdict + def __setattr__(self, name, value): vars(self.pdfdict)[name] = value + class PdfDict(dict): - ''' PdfDict objects are subclassed dictionaries with the following features: + ''' PdfDict objects are subclassed dictionaries + with the following features: - Every key in the dictionary starts with "/" - A dictionary item can be deleted by assigning it to None - - Keys that (after the initial "/") conform to Python naming conventions - can also be accessed (set and retrieved) as attributes of the dictionary. - E.g. mydict.Page is the same thing as mydict['/Page'] + - Keys that (after the initial "/") conform to Python + naming conventions can also be accessed (set and retrieved) + as attributes of the dictionary. E.g. mydict.Page is the + same thing as mydict['/Page'] - - Private attributes (not in the PDF space) can be set on the dictionary - object attribute dictionary by using the private attribute: + - Private attributes (not in the PDF space) can be set + on the dictionary object attribute dictionary by using + the private attribute: mydict.private.foo = 3 mydict.foo = 5 @@ -61,11 +74,11 @@ class PdfDict(dict): - PdfDicts have the following read-only properties: - - private -- as discussed above, provides write access to dictionary's - attributes - - inheritable -- this creates and returns a "view" attribute that - will search through the object hierarchy for any desired - attribute, such as /Rotate or /MediaBox + - private -- as discussed above, provides write access to + dictionary's attributes + - inheritable -- this creates and returns a "view" attribute + that will search through the object hierarchy for + any desired attribute, such as /Rotate or /MediaBox - PdfDicts also have the following special attributes: - indirect is not stored in the PDF dictionary, but in the object's @@ -84,13 +97,15 @@ class PdfDict(dict): indirect = False stream = None - _special = dict(indirect = ('indirect', False), - stream = ('stream', True), - _stream = ('stream', False), - ) + _special = dict(indirect=('indirect', False), + stream=('stream', True), + _stream=('stream', False), + ) - def __setitem__(self, name, value, setter=dict.__setitem__): - assert name.startswith('/'), name + def __setitem__(self, name, value, setter=dict.__setitem__, + BasePdfName=BasePdfName, isinstance=isinstance): + if not isinstance(name, BasePdfName): + raise PdfParseError('Dict key %s is not a PdfName' % repr(name)) if value is not None: setter(self, name, value) elif name in self: @@ -104,7 +119,7 @@ class PdfDict(dict): if isinstance(args, PdfDict): self.indirect = args.indirect self._stream = args.stream - for key, value in kw.iteritems(): + for key, value in iteritems(kw): setattr(self, key, value) def __getattr__(self, name, PdfName=PdfName): @@ -114,8 +129,10 @@ class PdfDict(dict): ''' return self.get(PdfName(name)) - def get(self, key, dictget=dict.get, isinstance=isinstance, PdfIndirect=PdfIndirect): - ''' Get a value out of the dictionary, after resolving any indirect objects. + def get(self, key, dictget=dict.get, isinstance=isinstance, + PdfIndirect=PdfIndirect): + ''' Get a value out of the dictionary, + after resolving any indirect objects. ''' value = dictget(self, key) if isinstance(value, PdfIndirect): @@ -125,7 +142,8 @@ class PdfDict(dict): def __getitem__(self, key): return self.get(key) - def __setattr__(self, name, value, special=_special.get, PdfName=PdfName, vars=vars): + def __setattr__(self, name, value, special=_special.get, + PdfName=PdfName, vars=vars): ''' Set an attribute on the dictionary. Handle the keywords indirect, stream, and _stream specially (for content objects) ''' @@ -139,28 +157,37 @@ class PdfDict(dict): notnone = value is not None self.Length = notnone and PdfObject(len(value)) or None - def iteritems(self, dictiter=dict.iteritems, isinstance=isinstance, PdfIndirect=PdfIndirect): + def iteritems(self, dictiter=iteritems, + isinstance=isinstance, PdfIndirect=PdfIndirect, + BasePdfName=BasePdfName): ''' Iterate over the dictionary, resolving any unresolved objects ''' for key, value in list(dictiter(self)): if isinstance(value, PdfIndirect): self[key] = value = value.real_value() if value is not None: - assert key.startswith('/'), (key, value) + if not isinstance(key, BasePdfName): + raise PdfParseError('Dict key %s is not a PdfName' % + repr(key)) yield key, value def items(self): return list(self.iteritems()) + def itervalues(self): for key, value in self.iteritems(): yield value + def values(self): return list((value for key, value in self.iteritems())) + def keys(self): return list((key for key, value in self.iteritems())) + def __iter__(self): for key, value in self.iteritems(): yield key + def iterkeys(self): return iter(self) @@ -197,6 +224,7 @@ class PdfDict(dict): return _Private(self) private = property(private) + class IndirectPdfDict(PdfDict): ''' IndirectPdfDict is a convenience class. You could create a direct PdfDict and then set indirect = True on it, |