IndirectObjects.cs :  » PDF » PDF-Clown » it » stefanochizzolini » clown » files » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » PDF » PDF Clown 
PDF Clown » it » stefanochizzolini » clown » files » IndirectObjects.cs
/*
  Copyright 2006,2007,2008 Stefano Chizzolini. http://clown.stefanochizzolini.it

  Contributors:
    * Stefano Chizzolini (original code developer, http://www.stefanochizzolini.it)

  This file should be part of the source code distribution of "PDF Clown library"
  (the Program): see the accompanying README files for more info.

  This Program is free software; you can redistribute it and/or modify it under
  the terms of the GNU General Public License as published by the Free Software
  Foundation; either version 2 of the License, or (at your option) any later version.

  This Program is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY, either expressed or implied; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the License for more details.

  You should have received a copy of the GNU General Public License along with this
  Program (see README files); if not, go to the GNU website (http://www.gnu.org/).

  Redistribution and use, with or without modification, are permitted provided that such
  redistributions retain the above copyright notice, license and disclaimer, along with
  this list of conditions.
*/

using it.stefanochizzolini.clown.documents;
using it.stefanochizzolini.clown.documents.contents;
using it.stefanochizzolini.clown.objects;
using it.stefanochizzolini.clown.tokens;

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;

namespace it.stefanochizzolini.clown.files{
  /**
    <summary>Collection of the <b>alive indirect objects</b> available inside the
    file.</summary>
    <remarks>
      <para>According to the PDF spec, <i>indirect object entries may be free
      (no data object associated) or in-use (data object associated)</i>.</para>
      <para>We can effectively subdivide indirect objects in two possibly-overriding
      collections: the <b>original indirect objects</b> (coming from the associated
      preexisting file) and the <b>newly-registered indirect objects</b> (coming
      from new data objects or original indirect objects manipulated during the
      current session).</para>
      <para><i>To ensure that the modifications applied to an original indirect object
      are committed to being persistent</i> is critical that the modified original
      indirect object is newly-registered (practically overriding the original
      indirect object).</para>
      <para><b>Alive indirect objects</b> encompass all the newly-registered ones plus
      not-overridden original ones.</para>
    </remarks>
  */
  public class IndirectObjects
    : IList<PdfIndirectObject>
  {
    #region dynamic
    #region fields
    /**
      <summary>Associated file.</summary>
    */
    private File file;

    /**
      <summary>Map of matching references of imported indirect objects.</summary>
      <remarks>
        <para>This collection is used to prevent duplications among imported
        indirect objects.</para>
        <para><code>Key</code> is the external indirect object hashcode, <code>Value</code> is the
        matching internal indirect object.</para>
      </remarks>
    */
    private Dictionary<int,PdfIndirectObject> importedObjects = new Dictionary<int,PdfIndirectObject>();
    /**
      <summary>Collection of newly-registered indirect objects.</summary>
    */
    private SortedDictionary<int,PdfIndirectObject> modifiedObjects = new SortedDictionary<int,PdfIndirectObject>();
    /**
      <summary>Collection of instantiated original indirect objects.</summary>
      <remarks>
        <para>This collection is useful as a cache to avoid unconsistent parsing duplications.</para>
      </remarks>
    */
    private SortedDictionary<int,PdfIndirectObject> wokenObjects = new SortedDictionary<int,PdfIndirectObject>();

    /**
      <summary>Object counter.</summary>
    */
    private int lastObjectNumber = -1; // Empty.
    /**
      <summary>Offsets of the original indirect objects inside the associated file
      (to say: implicit collection of the original indirect objects).</summary>
      <remarks>This information is vital to randomly retrieve the indirect-object
      persistent representation inside the associated file.</remarks>
    */
    private XRefEntry[] xrefEntries;

    private UpdateModeEnum updateMode = UpdateModeEnum.Manual;
    #endregion

    #region constructors
    internal IndirectObjects(
      File file,
      XRefEntry[] xrefEntries
      )
    {
      this.file = file;
      this.xrefEntries = xrefEntries;
      // Are there original indirect objects?
      if(this.xrefEntries == null)
      {
        /*
          [PDF:1.6:3.4.3] Mandatory head of the linked list of free objects
          at object number 0.
        */
        // Register the leading free-object!
        lastObjectNumber++;
        modifiedObjects[lastObjectNumber] = new PdfIndirectObject(
          this.file,
          null,
          new XRefEntry(
            lastObjectNumber,
            XRefEntry.GenerationUnreusable,
            0,
            XRefEntry.UsageEnum.Free
            )
          );
      }
      else
      {
        // Adjust the object counter!
        lastObjectNumber = xrefEntries.Length - 1;
      }
    }
    #endregion

    #region interface
    #region public
    public File File
    {get{return file;}}

    /**
      <summary>Register an <b>internal data object</b>.</summary>
      <remarks>
        <para>Alternatives:</para>
        <ul>
          <li>To register a <b>modified internal indirect object</b>, use
          <see cref="this"> indexer</see>.</li>
          <li>To register an <b>external indirect object</b>, use
          <see cref="Add(PdfIndirectObject)"/>.</li>
        </ul>
      </remarks>
    */
    public PdfIndirectObject Add(
      PdfDataObject obj
      )
    {
      // Register a new indirect object wrapping the data object inside!
      lastObjectNumber++;
      PdfIndirectObject indirectObject = modifiedObjects[lastObjectNumber] = new PdfIndirectObject(
        file,
        obj,
        new XRefEntry(
          lastObjectNumber,
          0,
          0,
          XRefEntry.UsageEnum.InUse
          )
        );

      return indirectObject;
    }

    /**
      <summary>Registers and gets an <b>external indirect object</b>.</summary>
      <remarks>
        <para>External indirect objects come from alien PDF files. <i>This
        is a powerful way to import the content of one file into another</i>.</para>
        <para>Alternatives:</para>
        <ul>
          <li>To register a <b>modified internal indirect object</b>, use
          <see cref="this"> indexer</see>.</li>
          <li>To register an <b>internal data object</b>, use
          <see cref="Add(PdfDataObject)"/>.</li>
        </ul>
      </remarks>
    */
    public PdfIndirectObject Add(
      PdfIndirectObject obj
      )
    {
      PdfIndirectObject indirectObject;
      // Hasn't the external indirect object been imported yet?
      if(!importedObjects.TryGetValue(obj.GetHashCode(),out indirectObject))
      {
        // Register the clone of the data object corresponding to the external indirect object!
        indirectObject = Add((PdfDataObject)obj.DataObject.Clone(file));
        // Keep track of the imported indirect object!
        importedObjects.Add(obj.GetHashCode(),indirectObject);
      }

      return indirectObject;
    }

    public bool IsEmpty(
      )
    {
      /*
      NOTE: Semantics of the indirect objects collection imply that the collection is considered
      empty in any case no in-use object is available.
      */
      foreach(PdfIndirectObject obj in this)
      {
        if(obj.IsInUse())
          return false;
      }

      return true;
    }

    #region IList
    public int IndexOf(
      PdfIndirectObject obj
      )
    {
      // Is this indirect object associated to this file?
      if(obj.File != file)
        return -1;

      return obj.Reference.ObjectNumber;
    }

    public void Insert(
      int index,
      PdfIndirectObject obj
      )
    {throw new NotSupportedException();}

    public void RemoveAt(
      int index
      )
    {
      /*
        NOTE: Acrobat 6.0 and later (PDF 1.5+) DO NOT use the free list to recycle object numbers;
        new objects are assigned new numbers [PDF:1.6:H.3:16].
        According to such an implementation note, we simply mark the removed object as 'not-reusable'
        newly-freed entry, neglecting both to add it to the linked list of free entries
        and to increment by 1 its generation number.
      */
      Update(
        new PdfIndirectObject(
          file,
          null,
          new XRefEntry(
            index,
            XRefEntry.GenerationUnreusable,
            0,
            XRefEntry.UsageEnum.Free
            )
          )
        );
    }

    /**
      <summary>Gets/Sets an indirect object with the specified object number.</summary>
      <remarks>
        <para>This indexer's setter is currently limited to <b>internal indirect
        objects</b>: <i>use it to register modified internal indirect objects only</i>.
        If you need to register alternative-type objects, consider the following
        methods:</para>
        <ul>
          <li>to register an <b>internal data object</b>, use <see cref="Add(PdfDataObject)"/>.</li>
          <li>to register an <b>external indirect object</b>, use <see cref="Add(PdfIndirectObject)"/>.</li>
        </ul>
      </remarks>
      <returns>A <see cref="it.stefanochizzolini.clown.objects.PdfIndirectObject"/>.</returns>
    */
    public PdfIndirectObject this[
      int index
      ]
    {
      get
      {
        PdfIndirectObject obj;
        // Is it among the original objects?
        if(!modifiedObjects.TryGetValue(index, out obj))
        {
          // Is it among the sleeping original objects?
          if(!wokenObjects.TryGetValue(index, out obj))
          {
            obj = new PdfIndirectObject(
              file,
              null,
              xrefEntries[index]
              );

            // Now it's awake!
            /*
            NOTE: This operation allows to keep a consistant state across the whole session,
            avoiding multiple incoherent instantiations of the same original indirect object.
            */
            wokenObjects[index] = obj;

            // Early registration?
            if(updateMode == UpdateModeEnum.Automatic)
            {Update(obj); /* Force early registration. */}
          }
        }

        return obj;
      }
      set{throw new NotSupportedException();}
    }

    #region ICollection
    /**
      <summary>Registers an <b>external indirect object</b>.</summary>
      <remarks>
        <para>External indirect objects come from alien PDF files. <i>This is
        a powerful way to import the content of one file into another</i>.</para>
        <para>Alternatives:</para>
        <ul>
          <li>To register and get an <b>external indirect object</b>, use <see cref="Add(PdfIndirectObject)"/>.</li>
          <li>To register a <b>modified internal indirect object</b>, use <see cref="this"> indexer</see>.</li>
          <li>To register an <b>internal data object</b>, use <see cref="Add(PdfDataObject)"/>.</li>
        </ul>
      </remarks>
    */
    void ICollection<PdfIndirectObject>.Add(
      PdfIndirectObject obj
      )
    {Add(obj);}

    public void Clear(
      )
    {throw new NotSupportedException();}

    public bool Contains(
      PdfIndirectObject obj
      )
    {throw new NotSupportedException();}

    public void CopyTo(
      PdfIndirectObject[] objs,
      int index
      )
    {throw new NotSupportedException();}

    /**
      <summary>Gets the number of entries available (both in-use and free) in the
      collection.</summary>
      <returns>The number of entries available in the collection.</returns>
    */
    public int Count
    {get{return (lastObjectNumber + 1);}}

    public bool IsReadOnly
    {get{return false;}}

    public bool Remove(
      PdfIndirectObject obj
      )
    {
      try
      {
        RemoveAt(
          ((PdfIndirectObject)obj).Reference.ObjectNumber
          ); return true;
      }
      catch
      {return false;}
    }

    #region IEnumerable<ContentStream>
    public IEnumerator<PdfIndirectObject> GetEnumerator(
      )
    {
      for(
        int index = 0;
        index < this.Count;
        index++
        )
      {
        yield return this[index];
      }
    }

    #region IEnumerable
    IEnumerator IEnumerable.GetEnumerator(
      )
    {return this.GetEnumerator();}
    #endregion
    #endregion
    #endregion
    #endregion
    #endregion

    #region internal
    internal SortedDictionary<int,PdfIndirectObject> ModifiedObjects
    {get{return modifiedObjects;}}

    internal PdfIndirectObject Update(
      PdfIndirectObject obj
      )
    {
      int index = obj.Reference.ObjectNumber;

      // Get the old indirect object to be replaced!
      PdfIndirectObject old = this[index];
      if(old != obj)
      {old.DropFile(); /* Disconnect the old indirect object. */}

      // Insert the new indirect object into the modified objects collection!
      modifiedObjects[index] = obj;
      // Remove old indirect object from cache!
      wokenObjects.Remove(index);
      // Mark the new indirect object as modified!
      obj.DropOriginal();

      return old;
    }
    #endregion
    #endregion
    #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.