Exemplo n.º 1
0
        /// <summary>
        ///     Creates this object and sets all its properties
        /// </summary>
        /// <param name="storage">The OLE version 2.0 object as a <see cref="CFStorage" /></param>
        internal Ole10Native(CFStorage storage)
        {
            if (storage == null)
                throw new ArgumentNullException("storage");

            var ole10Native = storage.GetStream("\x0001Ole10Native");
            var compObj = storage.GetStream("\x0001CompObj");
            var compObjStream = new CompObjStream(compObj);

            AnsiUserType = compObjStream.AnsiUserType;
            StringFormat = compObjStream.StringFormat;
            ClipboardFormat = compObjStream.ClipboardFormat;

            switch (compObjStream.AnsiUserType)
            {
                case "OLE Package":
                    var ole10NativeSize = (int) ole10Native.Size - 4;
                    var data = ole10Native.GetData(4, ref ole10NativeSize);
                    var package = new Package(data);
                    Format = package.Format;
                    FileName = Path.GetFileName(package.FileName);
                    FilePath = package.FilePath;
                    NativeData = package.Data;
                    break;

                case "PBrush":
                case "Pakket":
                    // Ignore
                    break;

                default:
                    throw new OEObjectTypeNotSupported("Unsupported OleNative AnsiUserType '" +
                                                        compObjStream.AnsiUserType + "' found");
            }
        }
Exemplo n.º 2
0
        //[TestMethod]
        //public void Test_INCREMENTAL_TRANSACTED_CHANGE_CFS()
        //{

        //    Random r = new Random();

        //    for (int i = r.Next(1, 100); i < 1024 * 1024 * 70; i = i << 1)
        //    {
        //        SingleTransactedChange(i + r.Next(0, 3));
        //    }

        //}

        private void SingleTransactedChange(int size)
        {
            String filename = "INCREMENTAL_SIZE_MULTIPLE_WRITE_AND_READ_CFS.cfs";

            if (File.Exists(filename))
            {
                File.Delete(filename);
            }

            CompoundFile cf = new CompoundFile();
            CFStorage    st = cf.RootStorage.AddStorage("MyStorage");
            CFStream     sm = st.AddStream("MyStream");

            byte[] b = Helpers.GetBuffer(size);

            sm.SetData(b);
            cf.Save(filename);
            cf.Close();

            CompoundFile cf2 = new CompoundFile(filename);
            CFStorage    st2 = cf2.RootStorage.GetStorage("MyStorage");
            CFStream     sm2 = st2.GetStream("MyStream");

            Assert.IsNotNull(sm2);
            Assert.IsTrue(sm2.Size == size);
            Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b));

            cf2.Close();
        }
Exemplo n.º 3
0
        public void Test_WRITE_AND_READ_CFS()
        {
            String filename = "WRITE_AND_READ_CFS.cfs";

            CompoundFile cf = new CompoundFile();

            CFStorage st = cf.RootStorage.AddStorage("MyStorage");
            CFStream  sm = st.AddStream("MyStream");

            byte[] b = Helpers.GetBuffer(220, 0x0A);
            sm.SetData(b);

            cf.Save(filename);
            cf.Close();

            CompoundFile cf2 = new CompoundFile(filename);
            CFStorage    st2 = cf2.RootStorage.GetStorage("MyStorage");
            CFStream     sm2 = st2.GetStream("MyStream");

            cf2.Close();

            Assert.IsNotNull(sm2);
            Assert.IsTrue(sm2.Size == 220);


            if (File.Exists(filename))
            {
                File.Delete(filename);
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Reads the header record containing the size of the data.
 /// </summary>
 /// <param name="storage">
 /// Storage key where to look for the Header stream.
 /// </param>
 /// <returns>Size of the Data section.</returns>
 internal static uint ReadHeader(CFStorage storage)
 {
     using (var header = storage.GetStream("Header").GetBinaryReader())
     {
         return(header.ReadUInt32());
     }
 }
        public static string GetIQPDetailFromStream(CFStorage storage, string streamName)
        {
            CFStream IQPDetailStream = storage.GetStream(streamName);
            int      IQPDetailSize   = (int)IQPDetailStream.Size;

            byte[] IQPDetailBytes = IQPDetailStream.GetData(3, ref IQPDetailSize);
            return(Encoding.UTF8.GetString(IQPDetailBytes));
        }
Exemplo n.º 6
0
        /// <summary>
        ///     Creates this object and sets all its properties
        /// </summary>
        /// <param name="storage">The OLE version 2.0 object as a <see cref="CFStorage" /></param>
        internal Ole10Native(CFStorage storage)
        {
            if (storage == null)
            {
                throw new ArgumentNullException("storage");
            }

            var ole10Native   = storage.GetStream("\x0001Ole10Native");
            var compObj       = storage.GetStream("\x0001CompObj");
            var compObjStream = new CompObjStream(compObj);

            AnsiUserType    = compObjStream.AnsiUserType;
            StringFormat    = compObjStream.StringFormat;
            ClipboardFormat = compObjStream.ClipboardFormat;

            switch (compObjStream.AnsiUserType)
            {
            case "OLE Package":
                var olePackageSize = (int)ole10Native.Size - 4;
                var olePackageData = new byte[olePackageSize];
                ole10Native.Read(olePackageData, 4, olePackageSize);
                var package = new Package(olePackageData);
                Format     = package.Format;
                FileName   = Path.GetFileName(package.FileName);
                FilePath   = package.FilePath;
                NativeData = package.Data;
                break;

            case "PBrush":
                var pbBrushSize = (int)ole10Native.Size - 4;
                var pbBrushData = new byte[pbBrushSize];
                ole10Native.Read(pbBrushData, 4, pbBrushSize);
                FileName   = "Embedded PBrush image.bmp";
                Format     = OleFormat.File;
                NativeData = pbBrushData;
                break;

            case "Pakket":
                // Ignore
                break;

            default:
                throw new OEObjectTypeNotSupported("Unsupported OleNative AnsiUserType '" +
                                                   compObjStream.AnsiUserType + "' found");
            }
        }
Exemplo n.º 7
0
        private _VBA_PROJECTStream ReadVbaProjectStream(CFStorage VBAStorage)
        {
            CFStream stream = VBAStorage.GetStream("_VBA_PROJECT");

            Byte[] uncompressedData = stream.GetData();

            var dataReader = new XlBinaryReader(ref uncompressedData);
            var result     = new _VBA_PROJECTStream(dataReader);

            return(result);
        }
Exemplo n.º 8
0
        /// <summary>
        /// Получить ссылку на поток из файла MCDF по его пути
        /// </summary>
        /// <param name="file">Файл - хранилище</param>
        /// <param name="streamPath">Путь к потоку в файле</param>
        /// <returns></returns>
        public static CFStream GetFileStream(CompoundFile file, string streamPath)
        {
            string[]  path   = streamPath.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
            CFStorage curDir = file.RootStorage;

            for (int i = 0; i < path.Length - 1; i++)
            {
                curDir = curDir.GetStorage(path[i]);
            }
            return(curDir.GetStream(path[path.Length - 1]));
        }
Exemplo n.º 9
0
        /// <summary>
        ///     Creates this object and reads all the <see cref="StringStreamItem" /> objects
        ///     from the given <paramref name="storage"/>
        /// </summary>
        /// <param name="storage">The <see cref="CFStorage"/> that contains the <see cref="PropertyTags.EntryStream"/></param>
        internal StringStream(CFStorage storage)
        {
            var stream = storage.GetStream(PropertyTags.StringStream);

            using (var memoryStream = new MemoryStream(stream.GetData()))
                using (var binaryReader = new BinaryReader(memoryStream))
                    while (!binaryReader.Eos())
                    {
                        var stringStreamItem = new StringStreamItem(binaryReader);
                        Add(stringStreamItem);
                    }
        }
Exemplo n.º 10
0
        /// <summary>
        ///     Creates this object and reads all the <see cref="Guid" /> objects from
        ///     the given <paramref name="storage"/>
        /// </summary>
        /// <param name="storage">The <see cref="CFStorage"/> that containts the <see cref="PropertyTags.GuidStream"/></param>
        internal GuidStream(CFStorage storage)
        {
            var stream = storage.GetStream(PropertyTags.GuidStream);

            using (var memoryStream = new MemoryStream(stream.GetData()))
                using (var binaryReader = new BinaryReader(memoryStream))
                    while (!binaryReader.Eos())
                    {
                        var guid = new Guid(binaryReader.ReadBytes(16));
                        Add(guid);
                    }
        }
        private CFStream GetStream(CFStorage cfstorage, string streamname)
        {
            CFStream stream = null;

            try
            {
                stream = cfstorage.GetStream(streamname);
            }
            catch (Exception)
            {
            }

            return(stream);
        }
Exemplo n.º 12
0
        /// <summary>
        ///     Writes all the <see cref="Guid"/>'s as a <see cref="CFStream" /> to the
        ///     given <paramref name="storage" />
        /// </summary>
        /// <param name="storage">The <see cref="CFStorage" /></param>
        internal void Write(CFStorage storage)
        {
            var stream = storage.GetStream(PropertyTags.GuidStream);

            using (var memoryStream = new MemoryStream())
                using (var binaryWriter = new BinaryWriter(memoryStream))
                {
                    foreach (var guid in this)
                    {
                        binaryWriter.Write(guid.ToByteArray());
                    }

                    stream.SetData(memoryStream.ToArray());
                }
        }
Exemplo n.º 13
0
        /// <summary>
        ///     Writes all the <see cref="EntryStreamItem"/>'s as a <see cref="CFStream" /> to the
        ///     given <paramref name="storage" />
        /// </summary>
        /// <param name="storage">The <see cref="CFStorage" /></param>
        internal void Write(CFStorage storage)
        {
            var stream = storage.GetStream(PropertyTags.EntryStream);

            using (var memoryStream = new MemoryStream())
                using (var binaryWriter = new BinaryWriter(memoryStream))
                {
                    foreach (var entryStreamItem in this)
                    {
                        entryStreamItem.Write(binaryWriter);
                    }

                    stream.SetData(memoryStream.ToArray());
                }
        }
Exemplo n.º 14
0
 /// <summary>
 /// Adds a complete stream to the hash data.
 /// </summary>
 /// <param name="hashBuf">Current data to hash</param>
 /// <param name="streamName">Stream to hash</param>
 /// <param name="stg">Storage of the stream</param>
 private void AddStream(ICollection <byte[]> hashBuf, string streamName, CFStorage stg)
 {
     try {
         var stream = stg.GetStream(streamName);
         if (stream != null)
         {
             var data = stream.GetData();
             hashBuf.Add(data);
         }
     } catch (CFItemNotFound) {
         _logger.Warn("Skipping non-existent Stream {0}.", streamName);
     } catch (Exception e) {
         _logger.Error(e, "Error reading data!");
         _crashManager.Report(e, "vpt");
     }
 }
Exemplo n.º 15
0
 /// <summary>
 /// Reads the component parameter information.
 /// </summary>
 /// <param name="componentStorage">Component footprint storage key.</param>
 /// <param name="component">Component instance where the parameters will be imported into.</param>
 private void ReadFootprintParameters(CFStorage componentStorage, PcbComponent component)
 {
     BeginContext("Parameters");
     try
     {
         using (var reader = componentStorage.GetStream("Parameters").GetBinaryReader())
         {
             var parameters = ReadBlock(reader, size => ReadParameters(reader, size));
             component.ImportFromParameters(parameters);
         }
     }
     finally
     {
         EndContext();
     }
 }
Exemplo n.º 16
0
        /// <summary>
        /// Reads the library data from the current file which contains the PCB library
        /// header information parameters and also a list of the existing components.
        /// </summary>
        /// <param name="library"></param>
        private void ReadLibraryData(CFStorage library)
        {
            using (var reader = library.GetStream("Data").GetBinaryReader())
            {
                var parameters = ReadBlock(reader, size => ReadParameters(reader, size));
                Data.Header.ImportFromParameters(parameters);

                var footprintCount = reader.ReadUInt32();
                for (var i = 0; i < footprintCount; ++i)
                {
                    var refName    = ReadStringBlock(reader);
                    var sectionKey = GetSectionKeyFromRefName(refName);
                    Data.Items.Add(ReadFootprint(sectionKey));
                }
            }
        }
Exemplo n.º 17
0
        public VPXFile(string filename)
        {
            _cf = new CompoundFile(filename, CFSUpdateMode.ReadOnly, CFSConfiguration.Default);
            CFStorage gameStg = _cf.RootStorage.GetStorage("GameStg");
            UInt32    version = new VPXReader(gameStg.GetStream("Version")).ReadUInt32();

            void visitor(CFItem item)
            {
                if (item.Name.StartsWith("Image") && item is CFStream stream)
                {
                    ReadImage(stream, true);
                }
            }

            gameStg.VisitEntries(visitor, true);
        }
Exemplo n.º 18
0
        private bool ContainsPattern(CFStorage storage, string fileName)
        {
            var stream = storage.GetStream(fileName);
            var data   = stream.GetData();

            if (data.Length == 0)
            {
                Logger.Debug($"Ignoring \"{fileName}\", len: 0");
                return(false);
            }

            foreach (var pattern in _masks)
            {
                try {
                    var target = GetLnkTarget(data);
                    if (target.ToLowerInvariant().StartsWith(pattern.ToLowerInvariant()))
                    {
                        Logger.Debug($"Target \"{target}\" matches pattern \"{pattern}\"");
                        return(true);
                    }
                    else if (string.Empty.Equals(target))
                    {
                        Logger.Debug($"Target \"{target}\" ignored, not a lnk file");
                    }
                }
                catch (System.Runtime.InteropServices.COMException ex) {
                    if (LinkUtil.IsMissingDriveException(ex))
                    {
                        Logger.Debug($"Target drive does not exist, marking for deletion");
                        return(true);
                    }
                    else
                    {
                        Logger.Debug($"Target ignored, not a lnk file");
                    }
                }

                /*if (ContainsSubstring(data, pattern)) {
                 *  return true;
                 * }*/
            }

            return(false);
        }
Exemplo n.º 19
0
 static void CopyCfStreamsExcept(CFStorage src, CFStorage dest, string excludeName)
 {
     src.VisitEntries(i => {
         if (i.Name?.Equals(excludeName, StringComparison.InvariantCultureIgnoreCase) ?? false)
         {
             return;
         }
         if (i.IsStorage)
         {
             dest.AddStorage(i.Name);
             CopyCfStreamsExcept((CFStorage)i, dest.GetStorage(i.Name), null);
         }
         else
         {
             dest.AddStream(i.Name);
             dest.GetStream(i.Name).SetData(((CFStream)i).GetData());
         }
     }, false);
 }
Exemplo n.º 20
0
        public void Test_CHECK_DISPOSED_()
        {
            const String FILENAME = "MultipleStorage.cfs";
            CompoundFile cf       = new CompoundFile(FILENAME);

            CFStorage st = cf.RootStorage.GetStorage("MyStorage");

            cf.Close();

            try
            {
                byte[] temp = st.GetStream("MyStream").GetData();
                Assert.Fail("Stream without media");
            }
            catch (Exception ex)
            {
                Assert.IsTrue(ex is CFDisposedException);
            }
        }
Exemplo n.º 21
0
        public void Test_WRITE_AND_READ_CFS_VERSION_4()
        {
            String filename = "WRITE_AND_READ_CFS_V4.cfs";

            CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.EraseFreeSectors | CFSConfiguration.SectorRecycle);

            CFStorage st = cf.RootStorage.AddStorage("MyStorage");
            CFStream sm = st.AddStream("MyStream");
            byte[] b = new byte[220];
            sm.SetData(b);

            cf.Save(filename);
            cf.Close();

            CompoundFile cf2 = new CompoundFile(filename);
            CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage");
            CFStream sm2 = st2.GetStream("MyStream");

            Assert.IsNotNull(sm2);
            Assert.IsTrue(sm2.Size == 220);

            cf2.Close();
        }
Exemplo n.º 22
0
        public void Test_WRITE_READ_CFS_VERSION_4_STREAM()
        {
            String filename = "WRITE_COMMIT_READ_CFS_V4.cfs";

            CompoundFile cf = new CompoundFile(CFSVersion.Ver_4, CFSConfiguration.SectorRecycle | CFSConfiguration.EraseFreeSectors);

            CFStorage st = cf.RootStorage.AddStorage("MyStorage");
            CFStream sm = st.AddStream("MyStream");
            byte[] b = Helpers.GetBuffer(227);
            sm.SetData(b);

            cf.Save(filename);
            cf.Close();

            CompoundFile cf2 = new CompoundFile(filename);
            CFStorage st2 = cf2.RootStorage.GetStorage("MyStorage");
            CFStream sm2 = st2.GetStream("MyStream");

            Assert.IsNotNull(sm2);
            Assert.IsTrue(sm2.Size == b.Length);

            cf2.Close();
        }
Exemplo n.º 23
0
        private void SingleWriteReadMatchingSTREAMED(int size)
        {
            MemoryStream ms = new MemoryStream(size);

            CompoundFile cf = new CompoundFile();
            CFStorage    st = cf.RootStorage.AddStorage("MyStorage");
            CFStream     sm = st.AddStream("MyStream");

            byte[] b = Helpers.GetBuffer(size);

            sm.SetData(b);
            cf.Save(ms);
            cf.Close();

            CompoundFile cf2 = new CompoundFile(ms);
            CFStorage    st2 = cf2.RootStorage.GetStorage("MyStorage");
            CFStream     sm2 = st2.GetStream("MyStream");

            Assert.IsNotNull(sm2);
            Assert.IsTrue(sm2.Size == size);
            Assert.IsTrue(Helpers.CompareBuffer(sm2.GetData(), b));

            cf2.Close();
        }
Exemplo n.º 24
0
        /// <summary>
        /// When a Excel document is embedded in for example a Word document the Workbook
        /// is set to hidden. Don't know why Microsoft does this but they do. To solve this
        /// problem we seek the WINDOW1 record in the BOF record of the stream. In there a
        /// gbit structure is located. The first bit in this structure controls the visibility
        /// of the workbook, so we check if this bit is set to 1 (hidden) and if so set it to 0.
        /// Normally a Workbook stream only contains one WINDOW record but when it is embedded
        /// it will contain 2 or more records.
        /// </summary>
        /// <param name="rootStorage">The <see cref="CFStorage">Root storage</see> of a <see cref="CompoundFile"/></param>
        /// <exception cref="OEFileIsCorrupt">Raised when the <paramref name="rootStorage"/> does not have a Workbook stream</exception>
        public static void SetWorkbookVisibility(CFStorage rootStorage)
        {
            if (!rootStorage.ExistsStream("WorkBook"))
            {
                throw new OEFileIsCorrupt("Could not check workbook visibility because the WorkBook stream is not present");
            }

            try
            {
                var stream = rootStorage.GetStream("WorkBook") as CFStream;
                if (stream == null)
                {
                    return;
                }

                var bytes = stream.GetData();

                using (var memoryStream = new MemoryStream(bytes))
                    using (var binaryReader = new BinaryReader(memoryStream))
                    {
                        // Get the record type, at the beginning of the stream this should always be the BOF
                        var recordType   = binaryReader.ReadUInt16();
                        var recordLength = binaryReader.ReadUInt16();

                        // Something seems to be wrong, we would expect a BOF but for some reason it isn't
                        if (recordType != 0x809)
                        {
                            throw new OEFileIsCorrupt("The file is corrupt");
                        }

                        binaryReader.BaseStream.Position += recordLength;

                        while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
                        {
                            recordType   = binaryReader.ReadUInt16();
                            recordLength = binaryReader.ReadUInt16();

                            // Window1 record (0x3D)
                            if (recordType == 0x3D)
                            {
                                // ReSharper disable UnusedVariable
                                var xWn  = binaryReader.ReadUInt16();
                                var yWn  = binaryReader.ReadUInt16();
                                var dxWn = binaryReader.ReadUInt16();
                                var dyWn = binaryReader.ReadUInt16();
                                // ReSharper restore UnusedVariable

                                // The grbit contains the bit that hides the sheet
                                var grbit    = binaryReader.ReadBytes(2);
                                var bitArray = new BitArray(grbit);

                                // When the bit is set then unset it (bitArray.Get(0) == true)
                                if (bitArray.Get(0))
                                {
                                    bitArray.Set(0, false);

                                    // Copy the byte back into the stream, 2 positions back so that we overwrite the old bytes
                                    bitArray.CopyTo(bytes, (int)binaryReader.BaseStream.Position - 2);
                                }

                                break;
                            }
                            binaryReader.BaseStream.Position += recordLength;
                        }
                    }

                stream.SetData(bytes);
            }
            catch (Exception exception)
            {
                throw new OEFileIsCorrupt(
                          "Could not check workbook visibility because the file seems to be corrupt", exception);
            }
        }
Exemplo n.º 25
0
        /// <summary>
        /// When a Excel document is embedded in for example a Word document the Workbook
        /// is set to hidden. Don't know why Microsoft does this but they do. To solve this
        /// problem we seek the WINDOW1 record in the BOF record of the stream. In there a
        /// gbit structure is located. The first bit in this structure controls the visibility
        /// of the workbook, so we check if this bit is set to 1 (hidden) en is so set it to 0.
        /// Normally a Workbook stream only contains one WINDOW record but when it is embedded
        /// it will contain 2 or more records.
        /// </summary>
        /// <param name="rootStorage">The <see cref="CFStorage">Root storage</see> of a <see cref="CompoundFile"/></param>
        /// <exception cref="OEFileIsCorrupt">Raised when the <paramref name="rootStorage"/> does not have a Workbook stream</exception>
        public static void SetWorkbookVisibility(CFStorage rootStorage)
        {
            if (!rootStorage.ExistsStream("WorkBook"))
                throw new OEFileIsCorrupt("Could not check workbook visibility because the WorkBook stream is not present");

            try
            {
                var stream = rootStorage.GetStream("WorkBook") as CFStream;
                if (stream == null) return;

                var bytes = stream.GetData();

                using (var memoryStream = new MemoryStream(bytes))
                using (var binaryReader = new BinaryReader(memoryStream))
                {
                    // Get the record type, at the beginning of the stream this should always be the BOF
                    var recordType = binaryReader.ReadUInt16();
                    var recordLength = binaryReader.ReadUInt16();

                    // Something seems to be wrong, we would expect a BOF but for some reason it isn't 
                    if (recordType != 0x809)
                        throw new OEFileIsCorrupt("The file is corrupt");

                    binaryReader.BaseStream.Position += recordLength;

                    while (binaryReader.BaseStream.Position < binaryReader.BaseStream.Length)
                    {
                        recordType = binaryReader.ReadUInt16();
                        recordLength = binaryReader.ReadUInt16();

                        // Window1 record (0x3D)
                        if (recordType == 0x3D)
                        {
                            // ReSharper disable UnusedVariable
                            var xWn = binaryReader.ReadUInt16();
                            var yWn = binaryReader.ReadUInt16();
                            var dxWn = binaryReader.ReadUInt16();
                            var dyWn = binaryReader.ReadUInt16();
                            // ReSharper restore UnusedVariable

                            // The grbit contains the bit that hides the sheet
                            var grbit = binaryReader.ReadBytes(2);
                            var bitArray = new BitArray(grbit);

                            // When the bit is set then unset it (bitArray.Get(0) == true)
                            if (bitArray.Get(0))
                            {
                                bitArray.Set(0, false);

                                // Copy the byte back into the stream, 2 positions back so that we overwrite the old bytes
                                bitArray.CopyTo(bytes, (int)binaryReader.BaseStream.Position - 2);
                            }

                            break;
                        }
                        binaryReader.BaseStream.Position += recordLength;
                    }
                }

                stream.SetData(bytes);
            }
            catch (Exception exception)
            {
                throw new OEFileIsCorrupt(
                    "Could not check workbook visibility because the file seems to be corrupt", exception);
            }
            
        }
Exemplo n.º 26
0
        static bool CfStoragesAreDifferent(CFStorage s1, CFStorage s2, out string explain)
        {
            var s1Names = new List <Tuple <string, bool> >();
            var s2Names = new List <Tuple <string, bool> >();

            s1.VisitEntries(i => s1Names.Add(Tuple.Create(i.Name, i.IsStorage)), false);
            s2.VisitEntries(i => s2Names.Add(Tuple.Create(i.Name, i.IsStorage)), false);
            s1Names.Sort();
            s2Names.Sort();
            if (!s1Names.SequenceEqual(s2Names))
            {
                explain = $"Different file lists in storage '{s1.Name}'.\r\nFile 1: {{'{string.Join("', '", s1Names)}'}}\r\nFile 2: {{'{string.Join("'', '", s2Names)}'}}.";
                return(true);
            }
            FormControl fc1 = null;

            foreach (var t in s1Names)
            {
                if (t.Item2)
                {
                    if (CfStoragesAreDifferent(s1.GetStorage(t.Item1), s2.GetStorage(t.Item1), out explain))
                    {
                        return(true);
                    }
                }
                else if (t.Item1 == "f")
                {
                    fc1 = new FormControl(s1.GetStream("f").GetData());
                    var fc2 = new FormControl(s2.GetStream("f").GetData());
                    if (!fc1.Equals(fc2))
                    {
                        explain = $"Different contents of stream 'f' in storage '{s1.Name}'.";
                        return(true);
                    }
                }
                else if (t.Item1 == "o" && fc1 != null)
                {
                    var  o1  = s1.GetStream("o").GetData();
                    var  o2  = s2.GetStream("o").GetData();
                    uint idx = 0;
                    foreach (var site in fc1.Sites)
                    {
                        explain = $"Different contents of stream 'o', site '{site.Name}' in storage '{s1.Name}'.";
                        var o1Range = o1.Range(idx, site.ObjectStreamSize);
                        var o2Range = o2.Range(idx, site.ObjectStreamSize);
                        switch (site.ClsidCacheIndex)
                        {
                        case 15:     // MorphData
                        case 26:     // CheckBox
                        case 25:     // ComboBox
                        case 24:     // ListBox
                        case 27:     // OptionButton
                        case 23:     // TextBox
                        case 28:     // ToggleButton
                            if (!new MorphDataControl(o1Range).Equals(new MorphDataControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        case 17:     // CommandButton
                            if (!new CommandButtonControl(o1Range).Equals(new CommandButtonControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        case 21:     // Label
                            if (!new LabelControl(o1Range).Equals(new LabelControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        default:
                            if (!o1Range.SequenceEqual(o2Range))
                            {
                                return(true);
                            }
                            break;
                        }
                        idx += site.ObjectStreamSize;
                    }
                }
                else if (!s1.GetStream(t.Item1).GetData().SequenceEqual(s2.GetStream(t.Item1).GetData()))
                {
                    explain = $"Different contents of stream '{t.Item1}' in storage '{s1.Name}'.";
                    return(true);
                }
            }
            explain = "No differences found.";
            return(false);
        }
Exemplo n.º 27
0
    static public void Main(string[] args)
    {
        // List of target VBA modules to stomp, if empty => all modules will be stomped
        List <string> targetModules = new List <string>();

        // Filename that contains the VBA code used for substitution
        string VBASourceFileName = "";

        // Target MS Office version for pcode
        string targetOfficeVersion = "";

        // Option to hide modules from VBA editor GUI
        bool optionHideInGUI = false;

        // Option to start web server to serve malicious template
        int optionWebserverPort = 0;

        // Option to display help
        bool optionShowHelp = false;

        // File format is OpenXML (docm or xlsm)
        bool is_OpenXML = false;

        // Option to delete metadata from file
        bool optionDeleteMetadata = false;

        // Option to set random module names in dir stream
        bool optionSetRandomNames = false;

        // Temp path to unzip OpenXML files to
        String unzipTempPath = "";


        // Start parsing command line arguments
        var p = new OptionSet()
        {
            { "n|name=", "The target module name to stomp.\n" +
              "This argument can be repeated.",
              v => targetModules.Add(v) },
            { "s|sourcefile=", "File containing substitution VBA code (fake code).",
              v => VBASourceFileName = v },
            { "g|guihide", "Hide code from VBA editor GUI.",
              v => optionHideInGUI = v != null },
            { "t|targetversion=", "Target MS Office version the pcode will run on.",
              v => targetOfficeVersion = v },
            { "w|webserver=", "Start web server on specified port to serve malicious template.",
              (int v) => optionWebserverPort = v },
            { "d|delmetadata", "Remove metadata stream (may include your name etc.).",
              v => optionDeleteMetadata = v != null },
            { "r|randomnames", "Set random module names, confuses some analyst tools.",
              v => optionSetRandomNames = v != null },
            { "v", "Increase debug message verbosity.",
              v => { if (v != null)
                     {
                         ++verbosity;
                     }
              } },
            { "h|help", "Show this message and exit.",
              v => optionShowHelp = v != null },
        };

        List <string> extra;

        try
        {
            extra = p.Parse(args);
        }
        catch (OptionException e)
        {
            Console.WriteLine(e.Message);
            Console.WriteLine("Try '--help' for more information.");
            return;
        }

        if (extra.Count > 0)
        {
            filename = string.Join(" ", extra.ToArray());
        }
        else
        {
            optionShowHelp = true;
        }

        if (optionShowHelp)
        {
            ShowHelp(p);
            return;
        }
        // End parsing command line arguments

        // OLE Filename (make a copy so we don't overwrite the original)
        string outFilename = getOutFilename(filename);
        string oleFilename = outFilename;

        // Attempt to unzip as docm or xlsm OpenXML format
        try
        {
            unzipTempPath = CreateUniqueTempDirectory();
            ZipFile.ExtractToDirectory(filename, unzipTempPath);
            if (File.Exists(Path.Combine(unzipTempPath, "word", "vbaProject.bin")))
            {
                oleFilename = Path.Combine(unzipTempPath, "word", "vbaProject.bin");
            }
            else if (File.Exists(Path.Combine(unzipTempPath, "xl", "vbaProject.bin")))
            {
                oleFilename = Path.Combine(unzipTempPath, "xl", "vbaProject.bin");
            }
            is_OpenXML = true;
        }
        catch (Exception)
        {
            // Not OpenXML format, Maybe 97-2003 format, Make a copy
            if (File.Exists(outFilename))
            {
                File.Delete(outFilename);
            }
            File.Copy(filename, outFilename);
        }

        // Open OLE compound file for editing
        try
        {
            cf = new CompoundFile(oleFilename, CFSUpdateMode.Update, 0);
        }
        catch (Exception e)
        {
            Console.WriteLine("ERROR: Could not open file " + filename);
            Console.WriteLine("Please make sure this file exists and is .docm or .xlsm file or a .doc in the Office 97-2003 format.");
            Console.WriteLine();
            Console.WriteLine(e.Message);
            return;
        }

        // Read relevant streams
        CFStorage commonStorage = cf.RootStorage; // docm or xlsm

        if (cf.RootStorage.TryGetStorage("Macros") != null)
        {
            commonStorage = cf.RootStorage.GetStorage("Macros");                                                         // .doc
        }
        if (cf.RootStorage.TryGetStorage("_VBA_PROJECT_CUR") != null)
        {
            commonStorage = cf.RootStorage.GetStorage("_VBA_PROJECT_CUR");                                                                   // xls
        }
        vbaProjectStream = commonStorage.GetStorage("VBA").GetStream("_VBA_PROJECT").GetData();
        projectStream    = commonStorage.GetStream("project").GetData();
        dirStream        = Decompress(commonStorage.GetStorage("VBA").GetStream("dir").GetData());

        // Read project stream as string
        string projectStreamString = System.Text.Encoding.UTF8.GetString(projectStream);

        // Find all VBA modules in current file
        List <ModuleInformation> vbaModules = ParseModulesFromDirStream(dirStream);

        // Write streams to debug log (if verbosity enabled)
        DebugLog("Hex dump of original _VBA_PROJECT stream:\n" + Utils.HexDump(vbaProjectStream));
        DebugLog("Hex dump of original dir stream:\n" + Utils.HexDump(dirStream));
        DebugLog("Hex dump of original project stream:\n" + Utils.HexDump(projectStream));

        // Replace Office version in _VBA_PROJECT stream
        if (targetOfficeVersion != "")
        {
            ReplaceOfficeVersionInVBAProject(vbaProjectStream, targetOfficeVersion);
            commonStorage.GetStorage("VBA").GetStream("_VBA_PROJECT").SetData(vbaProjectStream);
        }

        // Hide modules from GUI
        if (optionHideInGUI)
        {
            foreach (var vbaModule in vbaModules)
            {
                if ((vbaModule.moduleName != "ThisDocument") && (vbaModule.moduleName != "ThisWorkbook"))
                {
                    Console.WriteLine("Hiding module: " + vbaModule.moduleName);
                    projectStreamString = projectStreamString.Replace("Module=" + vbaModule.moduleName, "");
                }
            }

            // Write changes to project stream
            commonStorage.GetStream("project").SetData(Encoding.UTF8.GetBytes(projectStreamString));
        }

        // Stomp VBA modules
        if (VBASourceFileName != "")
        {
            byte[] streamBytes;

            foreach (var vbaModule in vbaModules)
            {
                DebugLog("VBA module name: " + vbaModule.moduleName + "\nOffset for code: " + vbaModule.textOffset);

                // If this module is a target module, or if no targets are specified, then stomp
                if (targetModules.Contains(vbaModule.moduleName) || !targetModules.Any())
                {
                    Console.WriteLine("Now stomping VBA code in module: " + vbaModule.moduleName);

                    streamBytes = commonStorage.GetStorage("VBA").GetStream(vbaModule.moduleName).GetData();

                    DebugLog("Existing VBA source:\n" + GetVBATextFromModuleStream(streamBytes, vbaModule.textOffset));

                    // Get new VBA source code from specified text file. If not specified, VBA code is removed completely.
                    string newVBACode = "";
                    if (VBASourceFileName != "")
                    {
                        try
                        {
                            newVBACode = System.IO.File.ReadAllText(VBASourceFileName);
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine("ERROR: Could not open VBA source file " + VBASourceFileName);
                            Console.WriteLine("Please make sure this file exists and contains ASCII only characters.");
                            Console.WriteLine();
                            Console.WriteLine(e.Message);
                            return;
                        }
                    }

                    DebugLog("Replacing with VBA code:\n" + newVBACode);

                    streamBytes = ReplaceVBATextInModuleStream(streamBytes, vbaModule.textOffset, newVBACode);

                    DebugLog("Hex dump of VBA module stream " + vbaModule.moduleName + ":\n" + Utils.HexDump(streamBytes));

                    commonStorage.GetStorage("VBA").GetStream(vbaModule.moduleName).SetData(streamBytes);
                }
            }
        }

        // Set random ASCII names for VBA modules in dir stream
        if (optionSetRandomNames)
        {
            Console.WriteLine("Setting random ASCII names for VBA modules in dir stream (while leaving unicode names intact).");

            // Recompress and write to dir stream
            commonStorage.GetStorage("VBA").GetStream("dir").SetData(Compress(SetRandomNamesInDirStream(dirStream)));
        }

        // Delete metadata from document
        if (optionDeleteMetadata)
        {
            try
            {
                cf.RootStorage.Delete("\u0005SummaryInformation");
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR: metadata stream does not exist (option ignored)");
                DebugLog(e.Message);
            }
        }

        // Commit changes and close file
        cf.Commit();
        cf.Close();

        // Purge unused space in file
        CompoundFile.ShrinkCompoundFile(oleFilename);

        // Zip the file back up as a docm or xlsm
        if (is_OpenXML)
        {
            if (File.Exists(outFilename))
            {
                File.Delete(outFilename);
            }
            ZipFile.CreateFromDirectory(unzipTempPath, outFilename);
            // Delete Temporary Files
            Directory.Delete(unzipTempPath, true);
        }

        // Start web server, if option is specified
        if (optionWebserverPort != 0)
        {
            try
            {
                WebServer ws = new WebServer(SendFile, "http://*:" + optionWebserverPort.ToString() + "/");
                ws.Run();
                Console.WriteLine("Webserver starting on port " + optionWebserverPort.ToString() + ". Press a key to quit.");
                Console.ReadKey();
                ws.Stop();
                Console.WriteLine("Webserver closed. Goodbye!");
            }
            catch (Exception e)
            {
                Console.WriteLine("ERROR: could not start webserver on specified port");
                DebugLog(e.Message);
            }
        }
    }
Exemplo n.º 28
0
        private static bool CfStoragesAreDifferent(CFStorage s1, CFStorage s2, out string explain)
        {
            var s1Names = new List <Tuple <string, bool> >();
            var s2Names = new List <Tuple <string, bool> >();

            s1.VisitEntries(i => s1Names.Add(Tuple.Create(i.Name, i.IsStorage)), false);
            s2.VisitEntries(i => s2Names.Add(Tuple.Create(i.Name, i.IsStorage)), false);
            s1Names.Sort();
            s2Names.Sort();
            if (!s1Names.SequenceEqual(s2Names))
            {
                explain = string.Format(VBASyncResources.ExplainFrxDifferentFileLists, s1.Name,
                                        string.Join("', '", s1Names.Select(t => t.Item1)),
                                        string.Join("', '", s2Names.Select(t => t.Item1)));
                return(true);
            }
            FormControl fc1 = null;

            foreach (var t in s1Names)
            {
                if (t.Item2)
                {
                    if (CfStoragesAreDifferent(s1.GetStorage(t.Item1), s2.GetStorage(t.Item1), out explain))
                    {
                        return(true);
                    }
                }
                else if (t.Item1 == "f")
                {
                    fc1 = new FormControl(s1.GetStream("f").GetData());
                    var fc2 = new FormControl(s2.GetStream("f").GetData());
                    if (!fc1.Equals(fc2))
                    {
                        explain = string.Format(VBASyncResources.ExplainFrxGeneralStreamDifference, "f", s1.Name);
                        return(true);
                    }
                }
                else if (t.Item1 == "o" && fc1 != null)
                {
                    var  o1  = s1.GetStream("o").GetData();
                    var  o2  = s2.GetStream("o").GetData();
                    uint idx = 0;
                    foreach (var site in fc1.Sites)
                    {
                        explain = string.Format(VBASyncResources.ExplainFrxOStreamDifference, site.Name, s1.Name);
                        var o1Range = o1.Range(idx, site.ObjectStreamSize);
                        var o2Range = o2.Range(idx, site.ObjectStreamSize);
                        switch (site.ClsidCacheIndex)
                        {
                        case 15: // MorphData
                        case 26: // CheckBox
                        case 25: // ComboBox
                        case 24: // ListBox
                        case 27: // OptionButton
                        case 23: // TextBox
                        case 28: // ToggleButton
                            if (!new MorphDataControl(o1Range).Equals(new MorphDataControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        case 17: // CommandButton
                            if (!new CommandButtonControl(o1Range).Equals(new CommandButtonControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        case 18: // TabStrip
                            if (!new TabStripControl(o1Range).Equals(new TabStripControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        case 21: // Label
                            if (!new LabelControl(o1Range).Equals(new LabelControl(o2Range)))
                            {
                                return(true);
                            }
                            break;

                        default:
                            if (!o1Range.SequenceEqual(o2Range))
                            {
                                return(true);
                            }
                            break;
                        }
                        idx += site.ObjectStreamSize;
                    }
                }
                else if (!s1.GetStream(t.Item1).GetData().SequenceEqual(s2.GetStream(t.Item1).GetData()))
                {
                    explain = string.Format(VBASyncResources.ExplainFrxGeneralStreamDifference, t.Item1, s1.Name);
                    return(true);
                }
            }
            explain = "No differences found.";
            return(false);
        }
Exemplo n.º 29
0
        /// <summary>
        ///     Creates this object and sets all its properties
        /// </summary>
        /// <param name="storage">The OLE version 2.0 object as a <see cref="CFStorage" /></param>
        internal Ole10Native(CFStorage storage)
        {
            if (storage == null)
            {
                throw new ArgumentNullException(nameof(storage));
            }

            var ole10Native   = storage.GetStream("\x0001Ole10Native");
            var compObj       = storage.GetStream("\x0001CompObj");
            var compObjStream = new CompObjStream(compObj);

            AnsiUserType    = compObjStream.AnsiUserType;
            StringFormat    = compObjStream.StringFormat;
            ClipboardFormat = compObjStream.ClipboardFormat;

            switch (compObjStream.AnsiUserType)
            {
            case "OLE Package":
                var olePackageSize = (int)ole10Native.Size - 4;
                if (olePackageSize <= 0)
                {
                    break;
                }
                var olePackageData = new byte[olePackageSize];
                ole10Native.Read(olePackageData, 4, olePackageSize);
                var package = new Package(olePackageData);
                Format     = package.Format;
                FileName   = Path.GetFileName(package.FileName);
                FilePath   = package.FilePath;
                NativeData = package.Data;
                break;

            case "PBrush":
            case "Paintbrush-afbeelding":
                var pbBrushSize = (int)ole10Native.Size - 4;
                if (pbBrushSize <= 0)
                {
                    break;
                }
                var pbBrushData = new byte[pbBrushSize];
                ole10Native.Read(pbBrushData, 4, pbBrushSize);
                FileName   = "Embedded PBrush image.bmp";
                Format     = OleFormat.File;
                NativeData = pbBrushData;
                break;

            case "Pakket":
                // Ignore
                break;

            // MathType (http://docs.wiris.com/en/mathtype/start) is a equations editor
            // The data is stored in the MTEF format within image file formats (PICT, WMF, EPS, GIF) or Office documents
            // as kind of pickaback data. (http://docs.wiris.com/en/mathtype/mathtype_desktop/mathtype-sdk/mtefstorage).
            // Within Office, a placeholder image shows the created equation.
            // Because MathType does not support storing equations in a separate MTEF file, a export of the data is not
            // directly possible and would require a conversion into the mentioned file formats.
            // Due that facts, it make no sense try to export the data.
            case "MathType 5.0 Equation":
                break;

            // Used by the depreciated Microsoft Office ClipArt Gallery
            // supposedly to store some metadata
            case "MS_ClipArt_Gallery":
            case "Microsoft ClipArt Gallery":
                break;

            default:
                throw new OEObjectTypeNotSupported("Unsupported OleNative AnsiUserType '" +
                                                   compObjStream.AnsiUserType + "' found");
            }
        }
Exemplo n.º 30
0
        /// <summary>
        /// This method will extract and save the data from the given <see cref="storage"/> node to the <see cref="outputFolder"/>
        /// </summary>
        /// <param name="storage">The <see cref="CFStorage"/> node</param>
        /// <param name="outputFolder">The outputFolder</param>
        /// <param name="fileName">The fileName to use, null when the fileName is unknown</param>
        /// <returns></returns>
        /// <exception cref="OEFileIsPasswordProtected">Raised when a WordDocument, WorkBook or PowerPoint Document stream is password protected</exception>
        public static string SaveFromStorageNode(CFStorage storage, string outputFolder, string fileName)
        {
            if (storage.ExistsStream("CONTENTS"))
            {
                var contents = storage.GetStream("CONTENTS");
                if (contents.Size <= 0) return null;
                if (string.IsNullOrWhiteSpace(fileName)) fileName = DefaultEmbeddedObjectName;
                return SaveByteArrayToFile(contents.GetData(), Path.Combine(outputFolder, fileName));
            }
            
            if (storage.ExistsStream("Package"))
            {
                var package = storage.GetStream("Package");
                if (package.Size <= 0) return null;
                if (string.IsNullOrWhiteSpace(fileName)) fileName = DefaultEmbeddedObjectName;
                return SaveByteArrayToFile(package.GetData(), Path.Combine(outputFolder, fileName));
            }

            if (storage.ExistsStream("EmbeddedOdf"))
            {
                // The embedded object is an Embedded ODF file
                var package = storage.GetStream("EmbeddedOdf");
                if (package.Size <= 0) return null;
                if (string.IsNullOrWhiteSpace(fileName)) fileName = DefaultEmbeddedObjectName;
                return SaveByteArrayToFile(package.GetData(), Path.Combine(outputFolder, fileName));
            }

            if (storage.ExistsStream("\x0001Ole10Native"))
            {
                var ole10Native = new Ole10Native(storage);
                return ole10Native.Format == OleFormat.File
                    ? SaveByteArrayToFile(ole10Native.NativeData, Path.Combine(outputFolder, ole10Native.FileName))
                    : null;
            }

            if (storage.ExistsStream("WordDocument"))
            {
                // The embedded object is a Word file
                if (string.IsNullOrWhiteSpace(fileName)) fileName = "Embedded Word document.doc";
                return SaveStorageTreeToCompoundFile(storage, Path.Combine(outputFolder, fileName));
            }
            
            if (storage.ExistsStream("Workbook"))
            {
                // The embedded object is an Excel file   
                if (string.IsNullOrWhiteSpace(fileName)) fileName = "Embedded Excel document.xls";
                Excel.SetWorkbookVisibility(storage);
                return SaveStorageTreeToCompoundFile(storage, Path.Combine(outputFolder, fileName));
            }
            
            if (storage.ExistsStream("PowerPoint Document"))
            {
                // The embedded object is a PowerPoint file
                if (string.IsNullOrWhiteSpace(fileName)) fileName = "Embedded PowerPoint document.ppt";
                return SaveStorageTreeToCompoundFile(storage, Path.Combine(outputFolder, fileName));
            }
            
            return null;
        }
Exemplo n.º 31
0
        /// <summary>
        /// This method will extract and save the data from the given <see cref="storage"/> node to the <see cref="outputFolder"/>
        /// </summary>
        /// <param name="storage">The <see cref="CFStorage"/> node</param>
        /// <param name="outputFolder">The outputFolder</param>
        /// <param name="fileName">The fileName to use, null when the fileName is unknown</param>
        /// <returns></returns>
        /// <exception cref="OEFileIsPasswordProtected">Raised when a WordDocument, WorkBook or PowerPoint Document stream is password protected</exception>
        public static string SaveFromStorageNode(CFStorage storage, string outputFolder, string fileName)
        {
            if (storage.ExistsStream("CONTENTS"))
            {
                var contents = storage.GetStream("CONTENTS");
                if (contents.Size <= 0)
                {
                    return(null);
                }
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    fileName = DefaultEmbeddedObjectName;
                }
                return(SaveByteArrayToFile(contents.GetData(), Path.Combine(outputFolder, fileName)));
            }

            if (storage.ExistsStream("Package"))
            {
                var package = storage.GetStream("Package");
                if (package.Size <= 0)
                {
                    return(null);
                }
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    fileName = DefaultEmbeddedObjectName;
                }
                return(SaveByteArrayToFile(package.GetData(), Path.Combine(outputFolder, fileName)));
            }

            if (storage.ExistsStream("EmbeddedOdf"))
            {
                // The embedded object is an Embedded ODF file
                var package = storage.GetStream("EmbeddedOdf");
                if (package.Size <= 0)
                {
                    return(null);
                }
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    fileName = DefaultEmbeddedObjectName;
                }
                return(SaveByteArrayToFile(package.GetData(), Path.Combine(outputFolder, fileName)));
            }

            if (storage.ExistsStream("\x0001Ole10Native"))
            {
                var ole10Native = new Ole10Native(storage);
                return(ole10Native.Format == OleFormat.File
                    ? SaveByteArrayToFile(ole10Native.NativeData, Path.Combine(outputFolder, ole10Native.FileName))
                    : null);
            }

            if (storage.ExistsStream("WordDocument"))
            {
                // The embedded object is a Word file
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    fileName = "Embedded Word document.doc";
                }
                return(SaveStorageTreeToCompoundFile(storage, Path.Combine(outputFolder, fileName)));
            }

            if (storage.ExistsStream("Workbook"))
            {
                // The embedded object is an Excel file
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    fileName = "Embedded Excel document.xls";
                }
                Excel.SetWorkbookVisibility(storage);
                return(SaveStorageTreeToCompoundFile(storage, Path.Combine(outputFolder, fileName)));
            }

            if (storage.ExistsStream("PowerPoint Document"))
            {
                // The embedded object is a PowerPoint file
                if (string.IsNullOrWhiteSpace(fileName))
                {
                    fileName = "Embedded PowerPoint document.ppt";
                }
                return(SaveStorageTreeToCompoundFile(storage, Path.Combine(outputFolder, fileName)));
            }

            return(null);
        }
Exemplo n.º 32
0
        /// <summary>
        /// Gets the MAPI property value from a stream or storage in this storage.
        /// </summary>
        /// <param name="propIdentifier">The 4 char hexadecimal prop identifier.</param>
        /// <returns>The value of the MAPI property or null if not found.</returns>
        private object GetMapiPropertyFromStreamOrStorage(string propIdentifier)
        {
            //determine if the property identifier is in a stream or sub storage
            string propTag  = null;
            var    propType = PropertyType.PT_UNSPECIFIED;

            foreach (string propKey in _keys)
            {
                if (propKey.StartsWith(MapiTags.SubStgVersion1 + propIdentifier))
                {
                    propTag  = propKey.Substring(12, 8);
                    propType = (PropertyType)ushort.Parse(propKey.Substring(16, 4), System.Globalization.NumberStyles.HexNumber);
                    break;
                }
            }

            //depending on prop type use method to get property value
            string containerName = MapiTags.SubStgVersion1 + propTag;

            switch (propType)
            {
            case PropertyType.PT_UNSPECIFIED:
                return(null);

            case PropertyType.PT_STRING8:
                return(this.GetStreamAsString(containerName, Encoding.Default));

            case PropertyType.PT_UNICODE:
                return(this.GetStreamAsString(containerName, Encoding.Unicode));

            case PropertyType.PT_BINARY:
                return(_storage.GetStream(containerName).GetData());

            case PropertyType.PT_OBJECT:
                return(_storage.GetStorage(containerName));

            case PropertyType.PT_MV_STRING8:
            case PropertyType.PT_MV_UNICODE:

                // If the property is a unicode multiview item we need to read all the properties
                // again and filter out all the multivalue names, they end with -00000000, -00000001, etc..
                var multiValueContainerNames = _keys.Where(propKey => propKey.StartsWith(containerName + "-")).ToList();

                var values = new List <string>();
                foreach (var multiValueContainerName in multiValueContainerNames)
                {
                    var value = GetStreamAsString(multiValueContainerName,
                                                  propType == PropertyType.PT_MV_STRING8 ? Encoding.Default : Encoding.Unicode);

                    // Multi values always end with a null char so we need to strip that one off
                    if (value.EndsWith("/0"))
                    {
                        value = value.Substring(0, value.Length - 1);
                    }

                    values.Add(value);
                }

                return(values);

            default:
                throw new ApplicationException("MAPI property has an unsupported type and can not be retrieved.");
            }
        }
        public void LoadAttachmentProps(CFStorage attachmentStorage)
        {
            byte[] descBytes;
            try
            {
                descBytes = attachmentStorage.GetStream("AttachDesc").GetData();
            }
            catch (CFItemNotFound ex)
            {
                throw new NotSupportedException("Attachment description stream not found", ex);
            }

            if (descBytes.Length == 0)
            {
                throw new ArgumentException("no description bytes to read");
            }

            int nextIndex = 2;             //first two bytes are the version

            StringUtils.ReadStringA(descBytes, ref nextIndex);
            StringUtils.ReadStringA(descBytes, ref nextIndex);
            string displayName = StringUtils.ReadStringA(descBytes, ref nextIndex);

            StringUtils.ReadStringA(descBytes, ref nextIndex);
            StringUtils.ReadStringA(descBytes, ref nextIndex);
            string extension = StringUtils.ReadStringA(descBytes, ref nextIndex);

            nextIndex += 16;

            AttachmentMethod = (AttachType)BitConverter.ToUInt32(descBytes, nextIndex);
            nextIndex       += 4;

            ContentID = StringUtils.ReadStringW(descBytes, ref nextIndex);
            StringUtils.ReadStringW(descBytes, ref nextIndex);
            StringUtils.ReadStringW(descBytes, ref nextIndex);
            StringUtils.ReadStringW(descBytes, ref nextIndex);
            string displayNameW = StringUtils.ReadStringW(descBytes, ref nextIndex);

            StringUtils.ReadStringW(descBytes, ref nextIndex);
            StringUtils.ReadStringW(descBytes, ref nextIndex);
            string extensionW = StringUtils.ReadStringW(descBytes, ref nextIndex);

            //there's other stuff here, but I'm not going to read it

            Name      = displayName ?? displayNameW;
            Extension = extension ?? extensionW;

#if __ANDROID__
            MimeType = MimeTypeMap.Singleton.GetMimeTypeFromExtension(Extension == null ? null : Extension.Trim('.'));
#endif

            switch (AttachmentMethod)
            {
            case AttachType.afByBalue:
                Content = attachmentStorage.GetStream("AttachContents").GetData();
                return;

            case AttachType.afEmbeddedMessage:
                LoadRpmsgDataFromEmbeddedAttachment(attachmentStorage.GetStorage("MAPIMessage"));
                return;

            default:
                LogUtils.Error("unsupported attachment method: " + AttachmentMethod);
                Content = new byte[0];
                return;
            }
        }