/// <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; }