/// <summary>Save to a stream</summary>
        /// <param name="reference">reference to save</param>
        /// <param name="writer">The BinaryWriter to persist this object to.
        /// This method will alter the stream pointer of the underlying stream as a side effect.
        /// Passing null simply calculates how many bytes would be written.</param>
        /// <returns>number of bytes written including any padding</returns>
        static internal int Save(CompoundFileReference reference, BinaryWriter writer)
        {
            int bytes = 0;

            // NOTE: Our RefComponentType must be written by our caller
            bool calcOnly = (writer == null);

            // what are we dealing with here?
            CompoundFileStreamReference streamReference = reference as CompoundFileStreamReference;

            if ((streamReference == null) && (!(reference is CompoundFileStorageReference)))
            {
                throw new ArgumentException(SR.Get(SRID.UnknownReferenceSerialize), "reference");
            }

            // first parse the path into strings
            string[] segments = ContainerUtilities.ConvertBackSlashPathToStringArrayPath(reference.FullName);
            int      entries  = segments.Length;

            // write the count
            if (!calcOnly)
            {
                writer.Write(entries);
            }

            bytes += ContainerUtilities.Int32Size;

            // write the segments - if we are dealing with a stream entry, don't write the last "segment"
            // because it is in fact a stream name
            for (int i = 0; i < segments.Length - (streamReference == null ? 0 : 1); i++)
            {
                if (!calcOnly)
                {
                    writer.Write((Int32)RefComponentType.Storage);
                }
                bytes += ContainerUtilities.Int32Size;
                bytes += ContainerUtilities.WriteByteLengthPrefixedDWordPaddedUnicodeString(writer, segments[i]);
            }

            if (streamReference != null)
            {
                // we are responsible for the prefix
                if (!calcOnly)
                {
                    writer.Write((Int32)RefComponentType.Stream);
                }
                bytes += ContainerUtilities.Int32Size;

                // write the stream name
                bytes += ContainerUtilities.WriteByteLengthPrefixedDWordPaddedUnicodeString(writer, segments[segments.Length - 1]);
            }

            return(bytes);
        }
        /// <summary>
        /// Deserialize from the given stream
        /// </summary>
        /// <param name="reader">the BinaryReader to deserialize from with the seek pointer at the beginning of the container reference</param>
        /// <param name="bytesRead">bytes consumed from the stream</param>
        /// <remarks>
        /// Side effect of change the stream pointer
        /// </remarks>
        /// <exception cref="FileFormatException">Throws a FileFormatException if any formatting errors are encountered</exception>
        internal static CompoundFileReference Load(BinaryReader reader, out int bytesRead)
        {
            ContainerUtilities.CheckAgainstNull(reader, "reader");

            bytesRead = 0;  // running count of how much we've read - sanity check

            // create the TypeMap
            // reconstitute ourselves from the given BinaryReader

            // in this version, the next Int32 is the number of entries
            Int32 entryCount = reader.ReadInt32();

            bytesRead += ContainerUtilities.Int32Size;
            // EntryCount of zero indicates the root storage.
            if (entryCount < 0)
            {
                throw new FileFormatException(
                          SR.Get(SRID.CFRCorrupt));
            }

            // need a temp collection because we don't know what we're dealing with until a non-storage component
            // type is encountered
            StringCollection storageList = null;
            String           streamName  = null;

            // loop through the entries - accumulating strings until we know what kind of object
            // we ultimately need
            int byteLength;     // reusable

            while (entryCount > 0)
            {
                // first Int32 tells us what kind of component this entry represents
                RefComponentType refType = (RefComponentType)reader.ReadInt32();
                bytesRead += ContainerUtilities.Int32Size;

                switch (refType)
                {
                case RefComponentType.Storage:
                {
                    if (streamName != null)
                    {
                        throw new FileFormatException(
                                  SR.Get(SRID.CFRCorruptStgFollowStm));
                    }

                    if (storageList == null)
                    {
                        storageList = new StringCollection();
                    }

                    String str = ContainerUtilities.ReadByteLengthPrefixedDWordPaddedUnicodeString(reader, out byteLength);
                    bytesRead += byteLength;
                    storageList.Add(str);
                } break;

                case RefComponentType.Stream:
                {
                    if (streamName != null)
                    {
                        throw new FileFormatException(
                                  SR.Get(SRID.CFRCorruptMultiStream));
                    }

                    streamName = ContainerUtilities.ReadByteLengthPrefixedDWordPaddedUnicodeString(reader, out byteLength);
                    bytesRead += byteLength;
                } break;

                // we don't handle these types yet
                default:
                    throw new FileFormatException(
                              SR.Get(SRID.UnknownReferenceComponentType));
                }

                --entryCount;
            }

            CompoundFileReference newRef = null;

            // stream or storage?
            if (streamName == null)
            {
                newRef = new CompoundFileStorageReference(
                    ContainerUtilities.ConvertStringArrayPathToBackSlashPath(storageList));
            }
            else
            {
                newRef = new CompoundFileStreamReference(
                    ContainerUtilities.ConvertStringArrayPathToBackSlashPath(storageList, streamName));
            }

            return(newRef);
        }
        /// <summary>Save to a stream</summary>
        /// <param name="reference">reference to save</param>
        /// <param name="writer">The BinaryWriter to persist this object to. 
        /// This method will alter the stream pointer of the underlying stream as a side effect.
        /// Passing null simply calculates how many bytes would be written.</param> 
        /// <returns>number of bytes written including any padding</returns> 
        static internal int Save(CompoundFileReference reference, BinaryWriter writer)
        { 
            int bytes = 0;

            // NOTE: Our RefComponentType must be written by our caller
            bool calcOnly = (writer == null); 

            // what are we dealing with here? 
            CompoundFileStreamReference streamReference = reference as CompoundFileStreamReference; 
            if ((streamReference == null) && (!(reference is CompoundFileStorageReference)))
                throw new ArgumentException(SR.Get(SRID.UnknownReferenceSerialize), "reference"); 

            // first parse the path into strings
            string[] segments = ContainerUtilities.ConvertBackSlashPathToStringArrayPath(reference.FullName);
            int entries = segments.Length; 

            // write the count 
            if (!calcOnly) 
                writer.Write( entries );
 
            bytes += ContainerUtilities.Int32Size;

            // write the segments - if we are dealing with a stream entry, don't write the last "segment"
            // because it is in fact a stream name 
            for (int i = 0; i < segments.Length - (streamReference == null ? 0 : 1); i++)
            { 
                if (!calcOnly) 
                {
                    writer.Write( (Int32)RefComponentType.Storage ); 
                }
                bytes += ContainerUtilities.Int32Size;
                bytes += ContainerUtilities.WriteByteLengthPrefixedDWordPaddedUnicodeString(writer, segments[i]);
            } 

            if (streamReference != null) 
            { 
                // we are responsible for the prefix
                if (!calcOnly) 
                {
                    writer.Write( (Int32)RefComponentType.Stream );
                }
                bytes += ContainerUtilities.Int32Size; 

                // write the stream name 
                bytes += ContainerUtilities.WriteByteLengthPrefixedDWordPaddedUnicodeString(writer, segments[segments.Length - 1]); 
            }
 
            return bytes;
        }
 /// <summary>
 /// Internal method to retrieve the data space label corresponding to
 /// a container reference.  Returns null if no data space is associated.
 /// </summary>
 /// <param name="target">CompoundFileReference whose data space label is to be retrieved</param>
 /// <returns>Data space label</returns>
 internal string DataSpaceOf( CompoundFileReference target )
 {
     // Can't simply return _dataSpaceMap[target] because I need to cast it
     //  into a string, and if it's null the cast `blows up.
     if( _dataSpaceMap.Contains(target) )
     {
         return (string)_dataSpaceMap[target];
     }
     else
     {
         return null;
     }
 }
 /// <summary>
 /// Removes the container reference from the dataspace map. This is called when the container/substorage is getting deleted from the root storage. [DeleteSubStorage in StorageInfo]
 /// </summary>
 internal void RemoveContainerFromDataSpaceMap(CompoundFileReference target)
 {
    CheckDisposedStatus();
    if (_dataSpaceMap.Contains(target))
    {
         _dataSpaceMap.Remove(target);
         _dirtyFlag = true;
    }
 }
 /// <summary>
 /// Internal method to create an entry in the data space mapping table
 /// </summary>
 /// <param name="containerReference">Package reference describing the scope of the data space</param>
 /// <param name="label">Label of the data space definition</param>
 internal void CreateDataSpaceMapping( CompoundFileReference containerReference, string label )
 {
     Debug.Assert( DataSpaceIsDefined( label ),
         "Internal method illegally defining a data space reference on a data space that has not yet been defined");
     _dataSpaceMap[containerReference] = label;
     _dirtyFlag = true;
 }