Example #1
0
    def write(self, stream, prev, startdata):
        stream.write(pdf.b_("\r\n"))
        positions = {2: 0}
        for i in range(2, len(self._objects)):
            idnum = i + 1
            obj = self._objects[i]
            if obj is None:
                positions[idnum] = 0
                continue
            positions[idnum] = startdata + stream.tell()
            stream.write(pdf.b_(str(idnum) + " 0 obj\n"))
            key = None
            if self._encrypt_key is not None:
                pack1 = struct.pack("<i", i + 1)[:3]
                pack2 = struct.pack("<i", 0)[:2]
                key = self._encrypt_key + pack1 + pack2
                assert len(key) == (len(self._encrypt_key) + 5)
                md5_hash = hashlib.md5(key).digest()
                key = md5_hash[:min(16, len(self._encrypt_key) + 5)]
            obj.writeToStream(stream, key)
            stream.write(pdf.b_("\nendobj\n"))

        xref_location = startdata + stream.tell()
        if not prev.xrefstream:
            trailer = po.DictionaryObject()
        else:
            trailer = po.StreamObject()
            self._addObject(trailer)
        # xref table
        trailer.update({
            po.NameObject("/Size"):
            po.NumberObject(len(self._objects) + 1),
            po.NameObject("/Root"):
            self.x_root,
            po.NameObject("/Info"):
            self.x_info,
            po.NameObject("/Prev"):
            po.NumberObject(prev.startxref),
            po.NameObject("/ID"):
            self._ID,
        })
        if prev.isEncrypted:
            trailer[po.NameObject("/Encrypt")] = prev.trailer.raw_get(
                "/Encrypt")
        if not prev.xrefstream:
            stream.write(pdf.b_("xref\n"))
            stream.write(pdf.b_("0 1\n"))
            stream.write(pdf.b_("0000000000 65535 f \n"))
            keys = sorted(positions.keys())
            i = 0
            while i < len(keys):
                off = positions[keys[i]]
                if off == 0:
                    while i < len(keys) and positions[keys[i]] == 0:
                        i += 1
                    start = i
                    while i < len(keys) and positions[keys[i]] != 0:
                        i += 1
                    stream.write(pdf.b_("%d %d \n" % (keys[start], i - start)))
                    i = start
                    continue
                else:
                    stream.write(pdf.b_("%010d %05d n \n" % (off, 0)))
                i += 1

            # trailer
            stream.write(pdf.b_("trailer\n"))
            trailer.writeToStream(stream, None)
        else:

            def pack(offset):
                return struct.pack(">q", offset)

            dataindex = ["0 1"]
            dataxref = [b"\x00" + pack(0)]
            keys = sorted(positions.keys())
            i = 0
            while i < len(keys):
                off = positions[keys[i]]
                if off != 0:
                    start = i
                    while i < len(keys) and positions[keys[i]] != 0:
                        dataxref.append(b"\x01" + pack(positions[keys[i]]))
                        i += 1
                    stop = i
                    dataindex.append("%d %d" % (keys[start], stop - start))
                else:
                    i += 1
            dataindex = " ".join(dataindex)
            dataxref = b"".join(dataxref)
            trailer[po.NameObject("/Type")] = po.NameObject("/XRef")
            trailer[po.NameObject("/W")] = po.NameObject("[1 8 0]")
            trailer[po.NameObject("/Index")] = po.NameObject("[%s]" %
                                                             dataindex)
            trailer._data = dataxref
            retval = trailer.flateEncode()
            trailer.update(retval)
            trailer._data = retval._data
            stream.write(pdf.b_("%d 0 obj\n" % (len(self._objects))))
            trailer.writeToStream(stream, None)
            stream.write(pdf.b_("\nendobj"))

        # eof
        stream.write(pdf.b_("\nstartxref\n%s\n%%%%EOF\n" % (xref_location)))
Example #2
0
    def write(self, stream, prev, startxref):

        externalReferenceMap = {}

        # PDF objects sometimes have circular references to their /Page objects
        # inside their object tree (for example, annotations).  Those will be
        # indirect references to objects that we've recreated in this PDF.  To
        # address this problem, PageObject's store their original object
        # reference number, and we add it to the external reference map before
        # we sweep for indirect references.  This forces self-page-referencing
        # trees to reference the correct new object location, rather than
        # copying in a new copy of the page object.
        for objIndex in range(len(self._objects)):
            obj = self._objects[objIndex]
            if isinstance(obj, pdf.PageObject) and obj.indirectRef != None:
                data = obj.indirectRef
                if data.pdf not in externalReferenceMap:
                    externalReferenceMap[data.pdf] = {}
                if data.generation not in externalReferenceMap[data.pdf]:
                    externalReferenceMap[data.pdf][data.generation] = {}
                externalReferenceMap[data.pdf][data.generation][
                    data.idnum] = po.IndirectObject(objIndex + 1, 0, self)

        self.stack = []
        self._sweepIndirectReferences(externalReferenceMap, self._root)
        del self.stack

        # Begin writing:
        positions = {}
        for i in range(2, len(self._objects)):
            idnum = i + 1
            obj = self._objects[i]
            if obj is None:
                continue
            positions[idnum] = startxref + stream.tell()
            stream.write(pdf.b_(str(idnum) + " 0 obj\n"))
            key = None
            if hasattr(self, "_encrypt") and idnum != self._encrypt.idnum:
                pack1 = struct.pack("<i", i + 1)[:3]
                pack2 = struct.pack("<i", 0)[:2]
                key = self._encrypt_key + pack1 + pack2
                assert len(key) == (len(self._encrypt_key) + 5)
                md5_hash = hashlib.md5(key).digest()
                key = md5_hash[:min(16, len(self._encrypt_key) + 5)]
            obj.writeToStream(stream, key)
            stream.write(pdf.b_("\nendobj\n"))

        # xref table
        xref_location = startxref + stream.tell()
        stream.write(pdf.b_("xref\n"))
        stream.write(pdf.b_("0 1\n"))
        stream.write(pdf.b_("0000000000 65535 f\n"))
        stream.write(pdf.b_("9 %d\n" % (len(positions))))
        for key in sorted(positions.keys()):
            stream.write(pdf.b_("%010d %05d n\n" % (positions[key], 0)))

        # trailer
        stream.write(pdf.b_("trailer\n"))
        trailer = po.DictionaryObject()
        trailer.update({
            po.NameObject("/Size"):
            po.NumberObject(len(self._objects) + 1),
            po.NameObject("/Root"):
            self.x_root,
            po.NameObject("/Info"):
            self.x_info,
            po.NameObject("/Prev"):
            po.NumberObject(prev.startxref),
        })
        if hasattr(self, "_ID"):
            trailer[po.NameObject("/ID")] = self._ID
        if hasattr(self, "_encrypt"):
            trailer[po.NameObject("/Encrypt")] = self._encrypt
        trailer.writeToStream(stream, None)

        # eof
        stream.write(pdf.b_("\nstartxref\n%s\n%%%%EOF\n" % (xref_location)))