// Copyright (C) 2003-2026, Foxit Software Inc..
// All Rights Reserved.
//
// http://www.foxitsoftware.com
//
// The following code is copyrighted and contains proprietary information and trade secrets of Foxit Software Inc..
// You cannot distribute any part of Foxit PDF SDK to any third party or general public,
// unless there is a separate license agreement with Foxit Software Inc. which explicitly grants you such rights.
//
// This file contains an example to demonstrate how to use Foxit PDF SDK to save a PDF document as a wrapper file
// and then open the wrapper file.

using System;
using System.IO;
using System.Runtime.InteropServices;


using foxit;
using foxit.common;
using foxit.common.fxcrt;
using foxit.pdf;
using foxit.pdf.graphics;
using foxit.pdf.objects;

namespace pdfwrapperCS
{

    class FileReader : FileReaderCallback
    {
        private FileStream file_ = null;
        private long filesize_ = 0;

        public FileReader(long offset)
        {
            this.filesize_ = offset;
        }

        public Boolean LoadFile(String file_path)
        {
            file_ = new FileStream(file_path, FileMode.OpenOrCreate);
            return true;
        }

        public override long GetSize()
        {
            return this.filesize_;
        }

        public override bool ReadBlock(IntPtr buffer, long offset, uint size)
        {
            int read_size = 0;
            file_.Seek(offset, SeekOrigin.Begin);
            byte[] array = new byte[size + 1];
            read_size = file_.Read(array, 0, (int)size);
            Marshal.Copy(array, 0, buffer, (int)size);
            return read_size == size ? true : false;
        }

        public override void Release()
        {
            this.file_.Close();
        }
    }

    class FileWriter : FileWriterCallback
    {
        private FileStream file_ = null;

        public Boolean LoadFile(String file_path)
        {
            file_ = new FileStream(file_path, FileMode.Create);
            return true;
        }

        public override void Release()
        {
            this.file_.Close();
        }

        public override bool Flush()
        {
            return true;
        }

        public override long GetSize()
        {
            return this.file_.Length;
        }

        public override bool WriteBlock(IntPtr pData, long offset, uint size)
        {
            file_.Seek(offset, SeekOrigin.Begin);

            byte[] ys = new byte[size];
            Marshal.Copy(pData, ys, 0, (int)size);
            file_.Write(ys, (int)0, (int)size);
            return true;
        }
    }

    class pdfwrapper
    {
        private static String output_path = "../output_files/pdfwrapper/";
        static void RenderPDF2Img(PDFDoc doc)
        {
            int page_count = doc.GetPageCount();

            for (int i = 0; i < page_count; i++)
            {
                using (PDFPage page = doc.GetPage(i))
                {
                    // Parse page.
                    page.StartParse((int)PDFPage.ParseFlags.e_ParsePageNormal, null, false);

                    int width = (int)page.GetWidth();
                    int height = (int)page.GetHeight();
                    Matrix2D matrix = page.GetDisplayMatrix(0, 0, width, height, page.GetRotation());

                    // Prepare a bitmap for rendering.
                    using (foxit.common.Bitmap bitmap = new foxit.common.Bitmap(width, height, foxit.common.Bitmap.DIBFormat.e_DIBArgb, System.IntPtr.Zero, 0))
                    {
                        bitmap.FillRect(0xFFFFFFFF, null);
                        // Render page.
                        using (Renderer render = new Renderer(bitmap, false))
                        {
                          render.StartRender(page, matrix, null);
                          // Add the bitmap to an image and save the image.
                          foxit.common.Image image = new foxit.common.Image();
                          image.AddFrame(bitmap);
                          String image_name;
                          image_name = "AboutFoxit_" + i;
                          image_name = output_path + image_name + "_wrapper.jpg";

                          if (!image.SaveAs(image_name))
                          {
                            Console.WriteLine("[Failed] Cannot save image file.\r\nPage index: " + i);
                          }
                        }
                    }
                }
            }
        }


        static void OpenWrapperFile(String file_name)
        {
            String file_info = output_path + "Wrapperinfo.txt";
            FileStream sfile = new FileStream(file_info, FileMode.OpenOrCreate);
            StreamWriter sw = new StreamWriter(sfile);

            using (PDFDoc doc = new PDFDoc(file_name))
            {
                ErrorCode code = doc.Load(null);
                if (code != ErrorCode.e_ErrSuccess)
                {
                    Console.WriteLine("[Failed] Cannot load PDF document: " + file_name + "\r\nError Message: " + code);
                    return;
                }
                if (!doc.IsWrapper())
                {
                    Console.WriteLine("[Failed] " + file_name + " is not a wrapper file.");
                    return;
                }
                long offset = doc.GetWrapperOffset();
                sw.Write("offset: " + offset + "\r\n");
                WrapperData wrapper_data = doc.GetWrapperData();
                sw.Write("version: " + wrapper_data.version + "\r\n");
                sw.Write("type: " + wrapper_data.type + "\r\n");
                sw.Write("app_id: " + wrapper_data.app_id + "\r\n");
                sw.Write("uri: " + wrapper_data.uri + "\r\n");
                sw.Write("description: " + wrapper_data.description + "\r\n");
                sw.Close();
                
                //"offset" can also indicate the end position of the document or the document size
                FileReader file_reader = new FileReader(offset);
                file_reader.LoadFile(file_name);

                using (PDFDoc doc_real = new PDFDoc(file_reader, false))
                {
                    code = doc_real.Load(null);
                    if (code != ErrorCode.e_ErrSuccess)
                    {
                        Console.WriteLine("[Failed] Cannot load real PDF document.\r\nError Message: " + code);
                        return;
                    }

                    RenderPDF2Img(doc_real);
                }
            }
          
        }
        static void Main(String[] args)
        {
            string input_path = "../input_files/";

            System.IO.Directory.CreateDirectory(output_path);
            string sn = "Rew1vB0TqoMIxX444UcpScARWdhgJpsJfzmyMLR32a0+EgrCjp2NaQ==";
            string key = "8f3g1sFttW8NAgfSNv+BvaJWy4Pp8flcm7ncNDkdvCCO4JwUFbGLyZdujReMaiplbYJwwxam3lr7uHtQaEf0xTSu8j2ZBdrZ8FS4OQkEUjOI9UEGb3Ic0GqmlP9T9OnSItOYqoZZA/OnYg5EaVP+c/ha32nUquOk+5riEdhYgINAZDdgJkPc+YSWsrfixOIROf6t34j3eRcyFnOY0MS7tSXi1AEPE0VZdyu+5bfmBSGvLI+WR5lQ+oOQR5hRGwqf990WEdBelNO7dxhZELVhEZ+/L60PpDf5y9A8qmrY6PiEU8nhqIyLpks0BxeIsYyZ3Cr82jjfbItPGyEARsIVzluBSgVMD4oGjojz8T6wGDEXUbmZH/pra94XAs8wZ28mzbmIEppWnhBqX0c6Ov8iXCfFfUZr4KNuPxMEgk4VOYTMOd70GEjGnylivw18hbn7ZpkWh2Zql+uU2HejvOgn+WHvT0HF9NhK0Xb5vH8aFkgBP92PJx8obIbxBVeeExczxvsqWufuPdXS2sPNIgMYZ2TtvqVVsiUToeGB2FQo09fzZOSH5Vi18u/siyvC3FmjeMf4+OYWPuDPNCcrb21NgcHam7XI8AAoGLTGtLLWR+fxynbBBcg2d2ZPcZ5CMFIfOBHRWCkcA0sDT3cl9nsBppHNJze/jVxHy+lREeQEA/etSIgohTGAWW3ZlpibRXqMxlmVWEPifCubbWTzQ6U54mRMpW2UghH3gvCNFNgdday3Av7EtlIJOdUuiMq3zmmd5J4Jt4C82CKnVewA0DtZ4EEtwRG9IYuLrfpuZlnjBAtoeXRV1lqUZ6BcCe0E3m9jO28sGkALuIeJQ74XG7X8lMC7lMWWQYiYD7D6G9QT6X3qV4vXJwNKRKpYc/rI+amEawTSnDYAMEaYPwtZ0rb/7BL+atsZZaI+ncebdfVfjDJZbCZAc+JnkuNlUn2xrNRuObw8h/G0lm2pNOEJ10S8R4+yplo5B1QmC2dCDhaTaW67QJPqnJPKbVmjw7i6KGBi+CDP3JnAKlOX/YUu8uk56JfeQUuGcQg/KaBMGctnchH2n1i3+oGbibhurQj22+OO66Q6mijKoCRP/QJm5WTGcO4c0iVX0B8dIlai/uv/pGU8Wps9MxysH5ViVIj56LWKuNfy1FNO9+wx4iHYnUxfW0Iccq3YJYAlOBkMv8VZIJl9aTEEFJ626LJEw/UbEBdR9CdlwnylPf4RuNW/lcGYMgq3xNVpp/bzYKwZivvQOFgMdX1tv8D33SHvAm3zrRCU+v94BJXnBi9k25fnKsc705IMwv+I6bueXA+mDnagj1oTqsWXZ0WnPAYI3WUO7sBf7XUH230wfYXnTSVhujJxiEP/2oWqi2813gtQkKwz9N2p6yT8Vsh3+BaAwwDvtOZMJKUFcabTBSL6NoouzmzwItJ4mIboT6KXaef66rs8jCU=";
            // Initialize library
            ErrorCode error_code = Library.Initialize(sn, key);
            if (error_code != ErrorCode.e_ErrSuccess)
                Console.WriteLine("Library Initialize Error: {0}", error_code);

            try
            {
                String input_file = input_path + "wrapper.pdf";
                // Load PDF document.
                using (PDFDoc doc_wrapper = new PDFDoc(input_file))
                {
                    error_code = doc_wrapper.Load(null);
                    if (error_code != ErrorCode.e_ErrSuccess)
                    {
                        Console.WriteLine("[Failed] Cannot load PDF document: " + input_file + ".\r\nError Code: " + error_code);
                        Library.Release();
                        return;
                    }
                    // Save the PDF document as a wrapper file.
                    using (WrapperData wrapperData = new WrapperData(10, "Foxit", "Foxit", "www.foxitsoftware.com", "foxit"))
                    {
                        String output_file = output_path + "AboutFoxit_wrapper.pdf";
                        using (PDFDoc doc_real = new PDFDoc(input_path + "AboutFoxit.pdf"))
                        {
                            error_code = doc_real.Load(null);
                            if (error_code != ErrorCode.e_ErrSuccess)
                            {
                                Console.WriteLine("[Failed] Cannot load PDF document: " + input_path + "SamplePDF.pdf.\r\nError Code: " + error_code);
                                Library.Release();
                                return;
                            }
                            doc_real.SaveAs(output_file, (int)PDFDoc.SaveFlags.e_SaveFlagNormal);

                            // "0xFFFFFFFC" can be changed to other values defined in enumeration FSUserPermissions.
                            int flag = (int)Convert.ToUInt32(0xFFFFFFFC);
                            doc_wrapper.SaveAsWrapperFile(output_file, wrapperData, flag, "");
                            // Open the wrapper file.
                            OpenWrapperFile(output_file);
                            Console.WriteLine("Add wrapper to PDF file.");

                            output_file = output_path + "AboutFoxit_payloadfile.pdf";
                            doc_wrapper.StartSaveAsPayloadFile(output_file, input_path + "AboutFoxit.pdf", "Unknown", "no_description", 1.0f, (int)PDFDoc.SaveFlags.e_SaveFlagIncremental, null);

                            Console.WriteLine("Save as payload file.");
                        }
                    }
                }

                input_file = input_path + "Microsoft IRM protection 2.pdf";
                using (PDFDoc doc_rmsv2 = new PDFDoc(input_file))
                {
                    error_code = doc_rmsv2.Load(null);
                    if (error_code != ErrorCode.e_ErrSuccess)
                    {
                        Console.WriteLine("[Failed] Cannot load PDF document: " + input_file + ".\r\nError Code: " + error_code);
                        Library.Release();
                        return;
                    }

                    if (foxit.pdf.PDFDoc.WrapperType.e_WrapperPDFV2 == doc_rmsv2.GetWrapperType()) {
                       FileWriter payloadfile = new FileWriter();
                       payloadfile.LoadFile(output_path + "MicrosoftIRMServices Protected PDF.pdf");
                       doc_rmsv2.StartGetPayloadFile(payloadfile, null);
                    }

                    Console.WriteLine("Get RMS V2 payload file.");
                }
            }
            catch (System.Exception e)
            {
                Console.WriteLine(e.Message);
            }
            Library.Release();
        }
    }
}
