Beispiel #1
0
        /// <summary>
        /// Converts a raw string into a raw hexadecimal string literal, possibly encrypted.
        /// </summary>
        public static string ToHexStringLiteral(string text, PdfStringEncoding encoding, PdfStandardSecurityHandler securityHandler, int paddingLeft)
        {
            if (String.IsNullOrEmpty(text) && paddingLeft == 0)
            {
                return("<>");
            }

            byte[] bytes;
            switch (encoding)
            {
            case PdfStringEncoding.RawEncoding:
                bytes = RawEncoding.GetBytes(text);
                break;

            case PdfStringEncoding.WinAnsiEncoding:
                bytes = WinAnsiEncoding.GetBytes(text);
                break;

            case PdfStringEncoding.PDFDocEncoding:
                bytes = DocEncoding.GetBytes(text);
                break;

            case PdfStringEncoding.Unicode:
                //bytes = UnicodeEncoding.GetBytes(text);
                bytes = RawUnicodeEncoding.GetBytes(text);
                break;

            default:
                throw new NotImplementedException(encoding.ToString());
            }

            if (bytes.Length < paddingLeft)
            {
                byte[] tmp = new byte[paddingLeft];
                Array.Copy(bytes, tmp, bytes.Length);
                bytes = tmp;
            }

            byte[] agTemp = FormatStringLiteral(bytes, encoding == PdfStringEncoding.Unicode, true, true, securityHandler);
            return(RawEncoding.GetString(agTemp, 0, agTemp.Length));
        }
        /// <summary>
        /// Implements saving a PDF file.
        /// </summary>
        void DoSave(PdfWriter writer)
        {
            if (this.pages == null || this.pages.Count == 0)
            {
                throw new InvalidOperationException("Cannot save a PDF document with no pages.");
            }

            try
            {
                bool encrypt = this.securitySettings.DocumentSecurityLevel != PdfDocumentSecurityLevel.None;
                if (encrypt)
                {
                    PdfStandardSecurityHandler securityHandler = this.securitySettings.SecurityHandler;
                    if (securityHandler.Reference == null)
                    {
                        this.irefTable.Add(securityHandler);
                    }
                    else
                    {
                        Debug.Assert(this.irefTable.Contains(securityHandler.ObjectID));
                    }
                    this.trailer.Elements[PdfTrailer.Keys.Encrypt] = this.securitySettings.SecurityHandler.Reference;
                }
                else
                {
                    this.trailer.Elements.Remove(PdfTrailer.Keys.Encrypt);
                }

                PrepareForSave();

                if (encrypt)
                {
                    this.securitySettings.SecurityHandler.PrepareEncryption();
                }

                writer.WriteFileHeader(this);
                PdfReference[] irefs = this.irefTable.AllReferences;
                int            count = irefs.Length;
                for (int idx = 0; idx < count; idx++)
                {
                    PdfReference iref = irefs[idx];
#if DEBUG_
                    if (iref.ObjectNumber == 378)
                    {
                        GetType();
                    }
#endif
                    iref.Position = writer.Position;
                    iref.Value.WriteObject(writer);
                }
                int startxref = writer.Position;
                this.irefTable.WriteObject(writer);
                writer.WriteRaw("trailer\n");
                this.trailer.Elements.SetInteger("/Size", count + 1);
                this.trailer.WriteObject(writer);
                writer.WriteEof(this, startxref);

                //if (encrypt)
                //{
                //  this.state &= ~DocumentState.SavingEncrypted;
                //  //this.securitySettings.SecurityHandler.EncryptDocument();
                //}
            }
            finally
            {
                if (writer != null)
                {
                    writer.Stream.Flush();
                    // DO NOT CLOSE WRITER HERE
                    //writer.Close();
                }
            }
        }
Beispiel #3
0
        //public static string EncodeAsLiteral(string text)
        //{
        //  return EncodeAsLiteral(text, false);
        //}

        /// <summary>
        /// Converts a raw string into a raw string literal, possibly encrypted.
        /// </summary>
        public static string ToStringLiteral(string text, PdfStringEncoding encoding, PdfStandardSecurityHandler securityHandler)
        {
            if (String.IsNullOrEmpty(text))
            {
                return("()");
            }

            byte[] bytes;
            switch (encoding)
            {
            case PdfStringEncoding.RawEncoding:
                bytes = RawEncoding.GetBytes(text);
                break;

            case PdfStringEncoding.WinAnsiEncoding:
                bytes = WinAnsiEncoding.GetBytes(text);
                break;

            case PdfStringEncoding.PDFDocEncoding:
                bytes = DocEncoding.GetBytes(text);
                break;

            case PdfStringEncoding.Unicode:
                bytes = RawUnicodeEncoding.GetBytes(text);
                break;

            default:
                throw new NotImplementedException(encoding.ToString());
            }
            byte[] temp = FormatStringLiteral(bytes, encoding == PdfStringEncoding.Unicode, true, false, securityHandler);
            return(RawEncoding.GetString(temp, 0, temp.Length));
        }
        /// <summary>
        /// Converts the specified byte array into a byte array representing a string literal.
        /// </summary>
        /// <param name="bytes">The bytes of the string.</param>
        /// <param name="unicode">Indicates whether one or two bytes are one character.</param>
        /// <param name="prefix">Indicates whether to use Unicode prefix.</param>
        /// <param name="hex">Indicates whether to create a hexadecimal string literal.</param>
        /// <param name="securityHandler">Encrypts the bytes if specified.</param>
        /// <returns>The PDF bytes.</returns>
        public static byte[] FormatStringLiteral(byte[] bytes, bool unicode, bool prefix, bool hex, PdfStandardSecurityHandler securityHandler)
        {
            if (bytes == null || bytes.Length == 0)
            {
                return hex ? new byte[] { (byte)'<', (byte)'>' }
            }
            : new byte[] { (byte)'(', (byte)')' };

            Debug.Assert(!unicode || bytes.Length % 2 == 0, "Odd number of bytes in Unicode string.");

            bool encrypted = false;

            if (securityHandler != null)
            {
                bytes = (byte[])bytes.Clone();

                bytes     = securityHandler.EncryptBytes(bytes);
                encrypted = true;
            }

            int           count = bytes.Length;
            StringBuilder pdf   = new StringBuilder();

            if (!unicode)
            {
                if (!hex)
                {
                    pdf.Append("(");
                    for (int idx = 0; idx < count; idx++)
                    {
                        char ch = (char)bytes[idx];
                        if (ch < 32)
                        {
                            switch (ch)
                            {
                            case '\n':
                                pdf.Append("\\n");
                                break;

                            case '\r':
                                pdf.Append("\\r");
                                break;

                            case '\t':
                                pdf.Append("\\t");
                                break;

                            case '\b':
                                pdf.Append("\\b");
                                break;

                            // Corrupts encrypted text.
                            //case '\f':
                            //  pdf.Append("\\f");
                            //  break;

                            default:
                                // Don't escape characters less than 32 if the string is encrypted, because it is
                                // unreadable anyway.
                                encrypted = true;
                                if (!encrypted)
                                {
                                    pdf.Append("\\0");
                                    pdf.Append((char)(ch % 8 + '0'));
                                    pdf.Append((char)(ch / 8 + '0'));
                                }
                                else
                                {
                                    pdf.Append(ch);
                                }
                                break;
                            }
                        }
                        else
                        {
                            switch (ch)
                            {
                            case '(':
                                pdf.Append("\\(");
                                break;

                            case ')':
                                pdf.Append("\\)");
                                break;

                            case '\\':
                                pdf.Append("\\\\");
                                break;

                            default:
                                pdf.Append(ch);
                                break;
                            }
                        }
                    }
                    pdf.Append(')');
                }
                else
                {
                    pdf.Append('<');
                    for (int idx = 0; idx < count; idx++)
                    {
                        pdf.AppendFormat("{0:X2}", bytes[idx]);
                    }
                    pdf.Append('>');
                }
            }
            else
            {
                Hex:
                if (hex)
                {
                    pdf.Append(prefix ? "<FEFF" : "<");
                    for (int idx = 0; idx < count; idx += 2)
                    {
                        pdf.AppendFormat("{0:X2}{1:X2}", bytes[idx], bytes[idx + 1]);
                        if (idx != 0 && (idx % 48) == 0)
                        {
                            pdf.Append("\n");
                        }
                    }
                    pdf.Append(">");
                }
                else
                {
                    // TODO non hex literals... not sure how to treat linefeeds, '(', '\' etc.
                    hex = true;
                    goto Hex;
                }
            }
            return(RawEncoding.GetBytes(pdf.ToString()));
        }
Beispiel #5
0
        /// <summary>
        /// Converts the specified byte array into a byte array representing a string literal.
        /// </summary>
        /// <param name="bytes">The bytes of the string.</param>
        /// <param name="unicode">Indicates whether one or two bytes are one character.</param>
        /// <param name="prefix">Indicates whether to use Unicode prefix.</param>
        /// <param name="hex">Indicates whether to create a hexadecimal string literal.</param>
        /// <param name="securityHandler">Encrypts the bytes if specified.</param>
        /// <returns>The PDF bytes.</returns>
        public static byte[] FormatStringLiteral(byte[] bytes, bool unicode, bool prefix, bool hex, PdfStandardSecurityHandler securityHandler)
        {
            if (bytes == null || bytes.Length == 0)
            {
                return hex ? new byte[] { (byte)'<', (byte)'>' }
            }
            : new byte[] { (byte)'(', (byte)')' };

            Debug.Assert(!unicode || bytes.Length % 2 == 0, "Odd number of bytes in Unicode string.");

            byte[] originalBytes = null;

            bool encrypted = false;

            if (securityHandler != null && !hex)
            {
                originalBytes = bytes;

                bytes     = (byte[])bytes.Clone();
                bytes     = securityHandler.EncryptBytes(bytes);
                encrypted = true;
            }

            int           count = bytes.Length;
            StringBuilder pdf   = new StringBuilder();

            if (!unicode)
            {
                if (!hex)
                {
                    pdf.Append("(");
                    for (int idx = 0; idx < count; idx++)
                    {
                        char ch = (char)bytes[idx];
                        if (ch < 32)
                        {
                            switch (ch)
                            {
                            case '\n':
                                pdf.Append("\\n");
                                break;

                            case '\r':
                                pdf.Append("\\r");
                                break;

                            case '\t':
                                pdf.Append("\\t");
                                break;

                            case '\b':
                                pdf.Append("\\b");
                                break;

                            // Corrupts encrypted text.
                            //case '\f':
                            //  pdf.Append("\\f");
                            //  break;

                            default:
                                // Don't escape characters less than 32 if the string is encrypted, because it is
                                // unreadable anyway.
                                encrypted = true;
                                if (!encrypted)
                                {
                                    pdf.Append("\\0");
                                    pdf.Append((char)(ch % 8 + '0'));
                                    pdf.Append((char)(ch / 8 + '0'));
                                }
                                else
                                {
                                    pdf.Append(ch);
                                }
                                break;
                            }
                        }
                        else
                        {
                            switch (ch)
                            {
                            case '(':
                                pdf.Append("\\(");
                                break;

                            case ')':
                                pdf.Append("\\)");
                                break;

                            case '\\':
                                pdf.Append("\\\\");
                                break;

                            default:
                                pdf.Append(ch);
                                break;
                            }
                        }
                    }
                    pdf.Append(')');
                }
                else
                {
                    pdf.Append('<');
                    for (int idx = 0; idx < count; idx++)
                    {
                        pdf.AppendFormat("{0:X2}", bytes[idx]);
                    }
                    pdf.Append('>');
                }
            }
            else
            {
                //Hex:
                if (hex)
                {
                    if (securityHandler != null && prefix)
                    {
                        // TODO Reduce redundancy.
                        // Encrypt data after padding BOM.
                        var bytes2 = new byte[bytes.Length + 2];
                        // Add BOM.
                        bytes2[0] = 0xfe;
                        bytes2[1] = 0xff;
                        // Copy bytes.
                        Array.Copy(bytes, 0, bytes2, 2, bytes.Length);
                        // Encyption.
                        bytes2    = securityHandler.EncryptBytes(bytes2);
                        encrypted = true;
                        pdf.Append("<");
                        var count2 = bytes2.Length;
                        for (int idx = 0; idx < count2; idx += 2)
                        {
                            pdf.AppendFormat("{0:X2}{1:X2}", bytes2[idx], bytes2[idx + 1]);
                            if (idx != 0 && (idx % 48) == 0)
                            {
                                pdf.Append("\n");
                            }
                        }
                        pdf.Append(">");
                    }
                    else
                    {
                        // No prefix or no encryption.
                        pdf.Append(prefix ? "<FEFF" : "<");
                        for (int idx = 0; idx < count; idx += 2)
                        {
                            pdf.AppendFormat("{0:X2}{1:X2}", bytes[idx], bytes[idx + 1]);
                            if (idx != 0 && (idx % 48) == 0)
                            {
                                pdf.Append("\n");
                            }
                        }
                        pdf.Append(">");
                    }
                }
                else
                {
                    // TODO non hex literals... not sure how to treat linefeeds, '(', '\' etc.
                    if (encrypted)
                    {
                        // Hack: Call self with hex := true.
                        return(FormatStringLiteral(originalBytes, unicode, prefix, true, securityHandler));
                    }
                    else
                    {
                        // Hack: Call self with hex := true.
                        return(FormatStringLiteral(bytes, true, prefix, true, null));
                    }
                }
            }
            return(RawEncoding.GetBytes(pdf.ToString()));
        }
        /// <summary>
        /// Opens an existing PDF document.
        /// </summary>
        public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider)
        {
            PdfDocument document;

            try
            {
                Lexer lexer = new Lexer(stream);
                document           = new PdfDocument(lexer);
                document._state   |= DocumentState.Imported;
                document._openMode = openmode;
                document._fileSize = stream.Length;

                // Get file version.
                byte[] header = new byte[1024];
                stream.Position = 0;
                stream.Read(header, 0, 1024);
                document._version = GetPdfFileVersion(header);
                if (document._version == 0)
                {
                    throw new InvalidOperationException(PSSR.InvalidPdf);
                }

                document._irefTable.IsUnderConstruction = true;
                Parser parser = new Parser(document);
                // Read all trailers or cross-reference streams, but no objects.
                document._trailer = parser.ReadTrailer();
                if (document._trailer == null)
                {
                    ParserDiagnostics.ThrowParserException("Invalid PDF file: no trailer found."); // TODO L10N using PSSR.
                }
                Debug.Assert(document._irefTable.IsUnderConstruction);
                document._irefTable.IsUnderConstruction = false;

                // Is document encrypted?
                PdfReference xrefEncrypt = document._trailer.Elements[PdfTrailer.Keys.Encrypt] as PdfReference;
                if (xrefEncrypt != null)
                {
                    //xrefEncrypt.Value = parser.ReadObject(null, xrefEncrypt.ObjectID, false);
                    PdfObject encrypt = parser.ReadObject(null, xrefEncrypt.ObjectID, false, false);

                    encrypt.Reference = xrefEncrypt;
                    xrefEncrypt.Value = encrypt;
                    PdfStandardSecurityHandler securityHandler = document.SecurityHandler;
TryAgain:
                    PasswordValidity validity = securityHandler.ValidatePassword(password);
                    if (validity == PasswordValidity.Invalid)
                    {
                        if (passwordProvider != null)
                        {
                            PdfPasswordProviderArgs args = new PdfPasswordProviderArgs();
                            passwordProvider(args);
                            if (args.Abort)
                            {
                                return(null);
                            }
                            password = args.Password;
                            goto TryAgain;
                        }
                        else
                        {
                            if (password == null)
                            {
                                throw new PdfReaderException(PSSR.PasswordRequired);
                            }
                            else
                            {
                                throw new PdfReaderException(PSSR.InvalidPassword);
                            }
                        }
                    }
                    else if (validity == PasswordValidity.UserPassword && openmode == PdfDocumentOpenMode.Modify)
                    {
                        if (passwordProvider != null)
                        {
                            PdfPasswordProviderArgs args = new PdfPasswordProviderArgs();
                            passwordProvider(args);
                            if (args.Abort)
                            {
                                return(null);
                            }
                            password = args.Password;
                            goto TryAgain;
                        }
                        else
                        {
                            throw new PdfReaderException(PSSR.OwnerPasswordRequired);
                        }
                    }
                }
                else
                {
                    if (password != null)
                    {
                        // Password specified but document is not encrypted.
                        // ignore
                    }
                }

                PdfReference[] irefs2 = document._irefTable.AllReferences;
                int            count2 = irefs2.Length;

                // 3rd: Create iRefs for all compressed objects.
                Dictionary <int, object> objectStreams = new Dictionary <int, object>();
                for (int idx = 0; idx < count2; idx++)
                {
                    PdfReference            iref       = irefs2[idx];
                    PdfCrossReferenceStream xrefStream = iref.Value as PdfCrossReferenceStream;
                    if (xrefStream != null)
                    {
                        for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++)
                        {
                            PdfCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2];
                            // Is type xref to compressed object?
                            if (item.Type == 2)
                            {
                                //PdfReference irefNew = parser.ReadCompressedObject(new PdfObjectID((int)item.Field2), (int)item.Field3);
                                //document._irefTable.Add(irefNew);
                                int objectNumber = (int)item.Field2;
                                if (!objectStreams.ContainsKey(objectNumber))
                                {
                                    objectStreams.Add(objectNumber, null);
                                    PdfObjectID objectID = new PdfObjectID((int)item.Field2);
                                    parser.ReadIRefsFromCompressedObject(objectID);
                                }
                            }
                        }
                    }
                }

                // 4th: Read compressed objects.
                for (int idx = 0; idx < count2; idx++)
                {
                    PdfReference            iref       = irefs2[idx];
                    PdfCrossReferenceStream xrefStream = iref.Value as PdfCrossReferenceStream;
                    if (xrefStream != null)
                    {
                        for (int idx2 = 0; idx2 < xrefStream.Entries.Count; idx2++)
                        {
                            PdfCrossReferenceStream.CrossReferenceStreamEntry item = xrefStream.Entries[idx2];
                            // Is type xref to compressed object?
                            if (item.Type == 2)
                            {
                                PdfReference irefNew = parser.ReadCompressedObject(new PdfObjectID((int)item.Field2),
                                                                                   (int)item.Field3);
                                Debug.Assert(document._irefTable.Contains(iref.ObjectID));
                                //document._irefTable.Add(irefNew);
                            }
                        }
                    }
                }


                PdfReference[] irefs = document._irefTable.AllReferences;
                int            count = irefs.Length;

                // Read all indirect objects.
                for (int idx = 0; idx < count; idx++)
                {
                    PdfReference iref = irefs[idx];
                    if (iref.Value == null)
                    {
#if DEBUG_
                        if (iref.ObjectNumber == 1074)
                        {
                            iref.GetType();
                        }
#endif
                        try
                        {
                            Debug.Assert(document._irefTable.Contains(iref.ObjectID));
                            PdfObject pdfObject = parser.ReadObject(null, iref.ObjectID, false, false);
                            Debug.Assert(pdfObject.Reference == iref);
                            pdfObject.Reference = iref;
                            Debug.Assert(pdfObject.Reference.Value != null, "Something went wrong.");
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine(ex.Message);
                            // 4STLA rethrow exception to notify caller.
                            throw;
                        }
                    }
                    else
                    {
                        Debug.Assert(document._irefTable.Contains(iref.ObjectID));
                        //iref.GetType();
                    }
                    // Set maximum object number.
                    document._irefTable._maxObjectNumber = Math.Max(document._irefTable._maxObjectNumber,
                                                                    iref.ObjectNumber);
                }

                // Encrypt all objects.
                if (xrefEncrypt != null)
                {
                    document.SecurityHandler.EncryptDocument();
                }

                // Fix references of trailer values and then objects and irefs are consistent.
                document._trailer.Finish();

#if DEBUG_
                // Some tests...
                PdfReference[] reachables = document.xrefTable.TransitiveClosure(document.trailer);
                reachables.GetType();
                reachables = document.xrefTable.AllXRefs;
                document.xrefTable.CheckConsistence();
#endif

                if (openmode == PdfDocumentOpenMode.Modify)
                {
                    // Create new or change existing document IDs.
                    if (document.Internals.SecondDocumentID == "")
                    {
                        document._trailer.CreateNewDocumentIDs();
                    }
                    else
                    {
                        byte[] agTemp = Guid.NewGuid().ToByteArray();
                        document.Internals.SecondDocumentID = PdfEncoders.RawEncoding.GetString(agTemp, 0, agTemp.Length);
                    }

                    // Change modification date
                    document.Info.ModificationDate = DateTime.Now;

                    // Remove all unreachable objects
                    int removed = document._irefTable.Compact();
                    if (removed != 0)
                    {
                        Debug.WriteLine("Number of deleted unreachable objects: " + removed);
                    }

                    // Force flattening of page tree
                    PdfPages pages = document.Pages;
                    Debug.Assert(pages != null);

                    //bool b = document.irefTable.Contains(new PdfObjectID(1108));
                    //b.GetType();

                    document._irefTable.CheckConsistence();
                    document._irefTable.Renumber();
                    document._irefTable.CheckConsistence();
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                throw;
            }
            return(document);
        }
        /// <summary>
        /// Opens an existing PDF document.
        /// </summary>
        public static PdfDocument Open(Stream stream, string password, PdfDocumentOpenMode openmode, PdfPasswordProvider passwordProvider)
        {
            PdfDocument document = null;

            try
            {
                Lexer lexer = new Lexer(stream);
                document          = new PdfDocument(lexer);
                document.state   |= DocumentState.Imported;
                document.openMode = openmode;
                document.fileSize = stream.Length;

                // Get file version
                byte[] header = new byte[1024];
                stream.Position = 0;
                stream.Read(header, 0, 1024);
                document.version = GetPdfFileVersion(header);
                if (document.version == 0)
                {
                    throw new InvalidOperationException(PSSR.InvalidPdf);
                }

                // Read all trailers
                document.irefTable.IsUnderConstruction = true;
                Parser parser = new Parser(document);
                document.trailer = parser.ReadTrailer();

                document.irefTable.IsUnderConstruction = false;

                // Is document encrypted?
                PdfReference xrefEncrypt = document.trailer.Elements[PdfTrailer.Keys.Encrypt] as PdfReference;
                if (xrefEncrypt != null)
                {
                    //xrefEncrypt.Value = parser.ReadObject(null, xrefEncrypt.ObjectID, false);
                    PdfObject encrypt = parser.ReadObject(null, xrefEncrypt.ObjectID, false);

                    encrypt.Reference = xrefEncrypt;
                    xrefEncrypt.Value = encrypt;
                    PdfStandardSecurityHandler securityHandler = document.SecurityHandler;
TryAgain:
                    PasswordValidity validity = securityHandler.ValidatePassword(password);
                    if (validity == PasswordValidity.Invalid)
                    {
                        if (passwordProvider != null)
                        {
                            PdfPasswordProviderArgs args = new PdfPasswordProviderArgs();
                            passwordProvider(args);
                            if (args.Abort)
                            {
                                return(null);
                            }
                            password = args.Password;
                            goto TryAgain;
                        }
                        else
                        {
                            if (password == null)
                            {
                                throw new PdfReaderException(PSSR.PasswordRequired);
                            }
                            else
                            {
                                throw new PdfReaderException(PSSR.InvalidPassword);
                            }
                        }
                    }
                    else if (validity == PasswordValidity.UserPassword && openmode == PdfDocumentOpenMode.Modify)
                    {
                        if (passwordProvider != null)
                        {
                            PdfPasswordProviderArgs args = new PdfPasswordProviderArgs();
                            passwordProvider(args);
                            if (args.Abort)
                            {
                                return(null);
                            }
                            password = args.Password;
                            goto TryAgain;
                        }
                        else
                        {
                            throw new PdfReaderException(PSSR.OwnerPasswordRequired);
                        }
                    }
                }
                else
                {
                    if (password != null)
                    {
                        // Password specified but document is not encrypted.
                        // ignore
                    }
                }

                PdfReference[] irefs = document.irefTable.AllReferences;
                int            count = irefs.Length;

                // Read all indirect objects
                for (int idx = 0; idx < count; idx++)
                {
                    PdfReference iref = irefs[idx];
                    if (iref.Value == null)
                    {
                        try
                        {
                            Debug.Assert(document.irefTable.Contains(iref.ObjectID));
                            PdfObject pdfObject = parser.ReadObject(null, iref.ObjectID, false);
                            Debug.Assert(pdfObject.Reference == iref);
                            pdfObject.Reference = iref;
                            Debug.Assert(pdfObject.Reference.Value != null, "something got wrong");
                        }
                        catch (Exception ex)
                        {
                            Debug.WriteLine(ex.Message);
                        }
                    }
                    else
                    {
                        Debug.Assert(document.irefTable.Contains(iref.ObjectID));
                        iref.GetType();
                    }
                    // Set maximum object number
                    document.irefTable.maxObjectNumber = Math.Max(document.irefTable.maxObjectNumber, iref.ObjectNumber);
                }
                // Encrypt all objects
                if (xrefEncrypt != null)
                {
                    document.SecurityHandler.EncryptDocument();
                }

                // Fix references of trailer values and then objects and irefs are consistent.
                document.trailer.Finish();

#if DEBUG_
                // Some tests...
                PdfReference[] reachables = document.xrefTable.TransitiveClosure(document.trailer);
                reachables.GetType();
                reachables = document.xrefTable.AllXRefs;
                document.xrefTable.CheckConsistence();
#endif

                if (openmode == PdfDocumentOpenMode.Modify)
                {
                    // Create new or change existing document IDs
                    if (document.Internals.SecondDocumentID == "")
                    {
                        document.trailer.CreateNewDocumentIDs();
                    }
                    else
                    {
                        byte[] agTemp = Guid.NewGuid().ToByteArray();
                        document.Internals.SecondDocumentID = PdfEncoders.RawEncoding.GetString(agTemp, 0, agTemp.Length);
                    }

                    // Change modification date
                    document.Info.ModificationDate = DateTime.Now;

                    // Remove all unreachable objects
                    int removed = document.irefTable.Compact();
                    if (removed != 0)
                    {
                        Debug.WriteLine("Number of deleted unreachable objects: " + removed.ToString());
                    }

                    // Force flattening of page tree
                    PdfPages pages = document.Pages;

                    //bool b = document.irefTable.Contains(new PdfObjectID(1108));
                    //b.GetType();

                    document.irefTable.CheckConsistence();
                    document.irefTable.Renumber();
                    document.irefTable.CheckConsistence();
                }
            }
            finally
            {
                //if (filestream != null)
                //  filestream.Close();
            }
            return(document);
        }
Beispiel #8
0
        /// <summary>
        /// Implements saving a PDF file.
        /// </summary>
        void DoSave(PdfWriter writer)
        {
            if (_pages == null || _pages.Count == 0)
            {
                if (_outStream != null)
                {
                    // Give feedback if the wrong constructor was used.
                    throw new InvalidOperationException("Cannot save a PDF document with no pages. Do not use \"public PdfDocument(string filename)\" or \"public PdfDocument(Stream outputStream)\" if you want to open an existing PDF document from a file or stream; use PdfReader.Open() for that purpose.");
                }
                throw new InvalidOperationException("Cannot save a PDF document with no pages.");
            }

            try
            {
                // HACK: Remove XRefTrailer
                if (_trailer is PdfCrossReferenceStream)
                {
                    // HACK^2: Preserve the SecurityHandler.
                    PdfStandardSecurityHandler securityHandler = _securitySettings.SecurityHandler;
                    _trailer = new PdfTrailer((PdfCrossReferenceStream)_trailer);
                    _trailer._securityHandler = securityHandler;
                }

                bool encrypt = _securitySettings.DocumentSecurityLevel != PdfDocumentSecurityLevel.None;
                if (encrypt)
                {
                    PdfStandardSecurityHandler securityHandler = _securitySettings.SecurityHandler;
                    if (securityHandler.Reference == null)
                    {
                        _irefTable.Add(securityHandler);
                    }
                    else
                    {
                        Debug.Assert(_irefTable.Contains(securityHandler.ObjectID));
                    }
                    _trailer.Elements[PdfTrailer.Keys.Encrypt] = _securitySettings.SecurityHandler.Reference;
                }
                else
                {
                    _trailer.Elements.Remove(PdfTrailer.Keys.Encrypt);
                }

                PrepareForSave();

                if (encrypt)
                {
                    _securitySettings.SecurityHandler.PrepareEncryption();
                }

                writer.WriteFileHeader(this);
                PdfReference[] irefs = _irefTable.AllReferences;
                int            count = irefs.Length;
                for (int idx = 0; idx < count; idx++)
                {
                    PdfReference iref = irefs[idx];
#if DEBUG_
                    if (iref.ObjectNumber == 378)
                    {
                        GetType();
                    }
#endif
                    iref.Position = writer.Position;
                    iref.Value.WriteObject(writer);
                }
                var startxref = writer.Position;
                _irefTable.WriteObject(writer);
                writer.WriteRaw("trailer\n");
                _trailer.Elements.SetInteger("/Size", count + 1);
                _trailer.WriteObject(writer);
                writer.WriteEof(this, startxref);

                //if (encrypt)
                //{
                //  state &= ~DocumentState.SavingEncrypted;
                //  //_securitySettings.SecurityHandler.EncryptDocument();
                //}
            }
            finally
            {
                if (writer != null)
                {
                    writer.Stream.Flush();
                    // DO NOT CLOSE WRITER HERE
                    //writer.Close();
                }
            }
        }