Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/3.1.3/EPPlus-3.1.3/Utils/CompoundDocument.cs @ 12073

Last change on this file since 12073 was 9580, checked in by sforsten, 12 years ago

#1730:

  • added SymbolicDataAnalysisExpressionExcelFormatter
  • changed modifiers in SymbolicExpressionTreeChart of methods SaveImageAsBitmap and SaveImageAsEmf to public
  • added menu item ExportSymbolicSolutionToExcelMenuItem to export a symbolic solution to an excel file
  • added EPPlus-3.1.3 to ExtLibs
File size: 26.8 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 *******************************************************************************
29 * Jan Källman    Added   01-01-2012
30 * Jan Källman      Added compression support 27-03-2012
31 *******************************************************************************/
32using System;
33using System.Collections.Generic;
34using System.Linq;
35using System.Text;
36using System.Runtime.InteropServices;
37using comTypes = System.Runtime.InteropServices.ComTypes;
38using System.IO;
39
40namespace OfficeOpenXml.Utils
41{
42    internal class CompoundDocument
43    {
44        internal class StoragePart
45        {
46            public StoragePart()
47            {
48
49            }
50            internal Dictionary<string, StoragePart> SubStorage = new Dictionary<string, StoragePart>();
51            internal Dictionary<string, byte[]> DataStreams = new Dictionary<string, byte[]>();
52        }
53        internal StoragePart Storage = null;
54        internal CompoundDocument()
55        {
56        }
57        internal CompoundDocument(byte[] doc)
58        {
59            ILockBytes lb;
60            var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
61
62            IntPtr buffer = Marshal.AllocHGlobal(doc.Length);
63            Marshal.Copy(doc, 0, buffer, doc.Length);
64            UIntPtr readSize;
65            lb.WriteAt(0, buffer, doc.Length, out readSize);
66            Marshal.FreeHGlobal(buffer);
67
68            if (StgIsStorageILockBytes(lb) == 0)
69            {
70                IStorage storage = null;
71                if (StgOpenStorageOnILockBytes(
72                    lb,
73                    null,
74                    STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE,
75                    IntPtr.Zero,
76                    0,
77                    out storage) == 0)
78                {
79                    Storage = new StoragePart();
80                    ReadParts(storage, Storage);
81                    Marshal.ReleaseComObject(storage);
82                }
83            }
84            else
85            {
86                throw (new InvalidDataException(string.Format("Part is not a compound document")));
87            }
88        }
89        #region  Compression
90        /// <summary>
91        /// Compression using a run length encoding algorithm.
92        /// See MS-OVBA Section 2.4
93        /// </summary>
94        /// <param name="part">Byte array to decompress</param>
95        /// <returns></returns>
96        internal static byte[] CompressPart(byte[] part)
97        {
98            MemoryStream ms = new MemoryStream(4096);
99            BinaryWriter br = new BinaryWriter(ms);
100            br.Write((byte)1);
101
102            int compStart = 1;
103            int compEnd = 4098;
104            int decompStart = 0;
105            int decompEnd = part.Length < 4096 ? part.Length : 4096;
106
107            while (decompStart < decompEnd && compStart < compEnd)
108            {
109                byte[] chunk = CompressChunk(part, ref decompStart);
110                ushort header;
111                if (chunk == null || chunk.Length == 0)
112                {
113                    header = 4096 | 0x600;  //B=011 A=0
114                }
115                else
116                {
117                    header = (ushort)(((chunk.Length - 1) & 0xFFF));
118                    header |= 0xB000;   //B=011 A=1
119                    br.Write(header);
120                    br.Write(chunk);                   
121                }
122                decompEnd = part.Length < decompStart + 4096 ? part.Length : decompStart+4096;
123            }
124
125           
126            br.Flush();
127            return ms.ToArray();       
128        }
129        private static byte[] CompressChunk(byte[] buffer, ref int startPos)
130        {
131            var comprBuffer=new byte[4096];
132            int flagPos = 0;
133            int cPos=1;
134            int dPos = startPos;
135            int dEnd=startPos+4096 < buffer.Length? startPos+4096 : buffer.Length;
136            while(dPos<dEnd)
137            {
138                byte tokenFlags = 0;
139                for (int i = 0; i < 8; i++)
140                {
141                    if (dPos - startPos > 0)
142                    {
143                        int bestCandidate = -1;
144                        int bestLength = 0;
145                        int candidate = dPos - 1;
146                        int bitCount = GetLengthBits(dPos-startPos);
147                        int bits = (16 - bitCount);
148                        ushort lengthMask = (ushort)((0xFFFF) >> bits);
149
150                        while (candidate >= startPos)
151                        {
152                            if (buffer[candidate] == buffer[dPos])
153                            {
154                                int length = 1;
155
156                                while (buffer.Length > dPos + length && buffer[candidate + length] == buffer[dPos + length] && length < lengthMask)
157                                {
158                                    length++;
159                                }
160                                if (length > bestLength)
161                                {
162                                    bestCandidate = candidate;
163                                    bestLength = length;
164                                    if (bestLength == lengthMask)
165                                    {
166                                        break;
167                                    }
168                                }
169                            }
170                            candidate--;
171                        }
172                        if (bestLength >= 3)    //Copy token
173                        {
174                            tokenFlags |= (byte)(1 << i);
175
176                            UInt16 offsetMask = (ushort)~lengthMask;
177                            ushort token = (ushort)(((ushort)(dPos - (bestCandidate+1))) << (bitCount) | (ushort)(bestLength - 3));
178                            Array.Copy(BitConverter.GetBytes(token), 0, comprBuffer, cPos, 2);
179                            dPos = dPos + bestLength;
180                            cPos += 2;
181                            //SetCopy Token                       
182                        }
183                        else
184                        {
185                            comprBuffer[cPos++] = buffer[dPos++];
186                        }
187                    }
188                   
189                    else
190                    {
191                        comprBuffer[cPos++] = buffer[dPos++];
192                    }
193                    if (dPos >= dEnd) break;
194                }
195                comprBuffer[flagPos] = tokenFlags;
196                flagPos = cPos++;
197            }
198            var ret = new byte[cPos - 1];
199            Array.Copy(comprBuffer, ret, ret.Length);
200            startPos = dEnd;
201            return ret;
202        }
203        internal static byte[] DecompressPart(byte[] part)
204        {
205            return DecompressPart(part, 0);
206        }
207        /// <summary>
208        /// Decompression using a run length encoding algorithm.
209        /// See MS-OVBA Section 2.4
210        /// </summary>
211        /// <param name="part">Byte array to decompress</param>
212        /// <param name="startPos"></param>
213        /// <returns></returns>
214        internal static byte[] DecompressPart(byte[] part, int startPos)
215        {
216
217            if (part[startPos] != 1)
218            {
219                return null;
220            }
221            MemoryStream ms = new MemoryStream(4096);
222            BinaryWriter br=new BinaryWriter(ms);
223            int compressPos = startPos+1;
224            while(compressPos<part.Length-1)
225            {
226                byte[] chunk = GetChunk(part, ref compressPos);
227                if (chunk != null)
228                {
229                    br.Write(chunk);
230                }
231            }
232            br.Flush();
233            return ms.ToArray();
234        }
235        private static byte[] GetChunk(byte[] compBuffer, ref int pos)
236        {
237            ushort header = BitConverter.ToUInt16(compBuffer, pos);
238            int  decomprPos=0;
239            byte[] buffer = new byte[4098];
240            int size = (int)(header & 0xFFF)+3;
241            int endPos = pos+size;
242            int a = (int)(header & 0x7000) >> 12;
243            int b = (int)(header & 0x8000) >> 15;
244            pos += 2;
245            if (b == 1) //Compressed chunk
246            {
247                while (pos < compBuffer.Length && pos < endPos)
248                {
249                    //Decompress token
250                    byte token = compBuffer[pos++];
251                    if (pos >= endPos)
252                        break;
253                    for (int i = 0; i < 8; i++)
254                    {
255                        //Literal token
256                        if ((token & (1 << i)) == 0)
257                        {
258                            buffer[decomprPos++] = compBuffer[pos++];
259                        }
260                        else //copy token
261                        {
262                            var t = BitConverter.ToUInt16(compBuffer, pos);
263                            int bitCount = GetLengthBits(decomprPos);
264                            int bits = (16 - bitCount);
265                            ushort lengthMask = (ushort)((0xFFFF) >> bits);
266                            UInt16 offsetMask = (ushort)~lengthMask;
267                            var length = (lengthMask & t) + 3;
268                            var offset = (offsetMask & t) >> (bitCount);
269                            int source = decomprPos - offset - 1;
270                            for (int c = 0; c < length; c++)
271                            {
272                                buffer[decomprPos++] = buffer[source++];
273                            }
274
275                            pos += 2;
276
277                        }
278                        if (pos >= endPos)
279                            break;
280                    }
281                }
282                if (decomprPos > 0)
283                {
284                    byte[] ret = new byte[decomprPos];
285                    Array.Copy(buffer, ret, decomprPos);
286                    return ret;
287                }
288                else
289                {
290                    return null;
291                }
292            }
293            else //Raw chunk
294            {
295                byte[] ret = new byte[size];
296                Array.Copy(compBuffer, pos, ret,0, size);
297                pos += size;
298                return ret;
299            }
300        }
301        private static int GetLengthBits(int decompPos)
302        {
303            if (decompPos <= 16)
304            {
305                return 12;
306            }
307            else if (decompPos <= 32)
308            {
309                return 11;
310            }
311            else if (decompPos <= 64)
312            {
313                return 10;
314            }
315            else if (decompPos <= 128)
316            {
317                return 9;
318            }
319            else if (decompPos <= 256)
320            {
321                return 8;
322            }
323            else if (decompPos <= 512)
324            {
325                return 7;
326            }
327            else if (decompPos <= 1024)
328            {
329                return 6;
330            }
331            else if (decompPos <= 2048)
332            {
333                return 5;
334            }
335            else if (decompPos <= 4096)
336            {
337                return 4;
338            }
339            else
340            {
341                //We should never end up here, but if so this is the formula to calculate the bits...
342                return 12 - (int)Math.Truncate(Math.Log(decompPos - 1 >> 4, 2) + 1);
343            }
344        }
345        #endregion
346        #region "API declare"
347        [ComImport]
348        [Guid("0000000d-0000-0000-C000-000000000046")]
349        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
350        internal interface IEnumSTATSTG
351        {
352            // The user needs to allocate an STATSTG array whose size is celt.
353            [PreserveSig]
354            uint Next(
355                uint celt,
356                [MarshalAs(UnmanagedType.LPArray), Out]
357            System.Runtime.InteropServices.ComTypes.STATSTG[] rgelt,
358                out uint pceltFetched
359            );
360
361            void Skip(uint celt);
362
363            void Reset();
364
365            [return: MarshalAs(UnmanagedType.Interface)]
366            IEnumSTATSTG Clone();
367        }
368
369        [ComImport]
370        [Guid("0000000b-0000-0000-C000-000000000046")]
371        [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
372        interface IStorage
373        {
374            void CreateStream(
375                /* [string][in] */ string pwcsName,
376                /* [in] */ uint grfMode,
377                /* [in] */ uint reserved1,
378                /* [in] */ uint reserved2,
379                /* [out] */ out comTypes.IStream ppstm);
380
381            void OpenStream(
382                /* [string][in] */ string pwcsName,
383                /* [unique][in] */ IntPtr reserved1,
384                /* [in] */ uint grfMode,
385                /* [in] */ uint reserved2,
386                /* [out] */ out comTypes.IStream ppstm);
387
388            void CreateStorage(
389                /* [string][in] */ string pwcsName,
390                /* [in] */ uint grfMode,
391                /* [in] */ uint reserved1,
392                /* [in] */ uint reserved2,
393                /* [out] */ out IStorage ppstg);
394
395            void OpenStorage(
396                /* [string][unique][in] */ string pwcsName,
397                /* [unique][in] */ IStorage pstgPriority,
398                /* [in] */ STGM grfMode,
399                /* [unique][in] */ IntPtr snbExclude,
400                /* [in] */ uint reserved,
401                /* [out] */ out IStorage ppstg);
402
403            void CopyTo(
404                [InAttribute] uint ciidExclude,
405                [InAttribute] Guid[] rgiidExclude,
406                [InAttribute] IntPtr snbExclude,
407                [InAttribute] IStorage pstgDest
408            );
409
410            void MoveElementTo(
411                /* [string][in] */ string pwcsName,
412                /* [unique][in] */ IStorage pstgDest,
413                /* [string][in] */ string pwcsNewName,
414                /* [in] */ uint grfFlags);
415
416            void Commit(
417                /* [in] */ uint grfCommitFlags);
418
419            void Revert();
420
421            void EnumElements(
422                /* [in] */ uint reserved1,
423                /* [size_is][unique][in] */ IntPtr reserved2,
424                /* [in] */ uint reserved3,
425                /* [out] */ out IEnumSTATSTG ppenum);
426
427            void DestroyElement(
428                /* [string][in] */ string pwcsName);
429
430            void RenameElement(
431                /* [string][in] */ string pwcsOldName,
432                /* [string][in] */ string pwcsNewName);
433
434            void SetElementTimes(
435                /* [string][unique][in] */ string pwcsName,
436                /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME pctime,
437                /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME patime,
438                /* [unique][in] */ System.Runtime.InteropServices.ComTypes.FILETIME pmtime);
439
440            void SetClass(
441                /* [in] */ Guid clsid);
442
443            void SetStateBits(
444                /* [in] */ uint grfStateBits,
445                /* [in] */ uint grfMask);
446
447            void Stat(
448                /* [out] */ out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg,
449                /* [in] */ uint grfStatFlag);
450
451        }
452        [ComVisible(false)]
453        [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("0000000A-0000-0000-C000-000000000046")]
454        internal interface ILockBytes
455        {
456            void ReadAt(long ulOffset, System.IntPtr pv, int cb, out UIntPtr pcbRead);
457            void WriteAt(long ulOffset, System.IntPtr pv, int cb, out UIntPtr pcbWritten);
458            void Flush();
459            void SetSize(long cb);
460            void LockRegion(long libOffset, long cb, int dwLockType);
461            void UnlockRegion(long libOffset, long cb, int dwLockType);
462            void Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag);
463        }
464        [Flags]
465        internal enum STGM : int
466        {
467            DIRECT = 0x00000000,
468            TRANSACTED = 0x00010000,
469            SIMPLE = 0x08000000,
470            READ = 0x00000000,
471            WRITE = 0x00000001,
472            READWRITE = 0x00000002,
473            SHARE_DENY_NONE = 0x00000040,
474            SHARE_DENY_READ = 0x00000030,
475            SHARE_DENY_WRITE = 0x00000020,
476            SHARE_EXCLUSIVE = 0x00000010,
477            PRIORITY = 0x00040000,
478            DELETEONRELEASE = 0x04000000,
479            NOSCRATCH = 0x00100000,
480            CREATE = 0x00001000,
481            CONVERT = 0x00020000,
482            FAILIFTHERE = 0x00000000,
483            NOSNAPSHOT = 0x00200000,
484            DIRECT_SWMR = 0x00400000,
485        }
486
487        internal enum STATFLAG : uint
488        {
489            STATFLAG_DEFAULT = 0,
490            STATFLAG_NONAME = 1,
491            STATFLAG_NOOPEN = 2
492        }
493
494        internal enum STGTY : int
495        {
496            STGTY_STORAGE = 1,
497            STGTY_STREAM = 2,
498            STGTY_LOCKBYTES = 3,
499            STGTY_PROPERTY = 4
500        }
501        [DllImport("ole32.dll")]
502        private static extern int StgIsStorageFile(
503            [MarshalAs(UnmanagedType.LPWStr)] string pwcsName);
504        [DllImport("ole32.dll")]
505        private static extern int StgIsStorageILockBytes(
506            ILockBytes plkbyt);
507
508
509        [DllImport("ole32.dll")]
510        static extern int StgOpenStorage(
511            [MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
512            IStorage pstgPriority,
513            STGM grfMode,
514            IntPtr snbExclude,
515            uint reserved,
516            out IStorage ppstgOpen);
517
518        [DllImport("ole32.dll")]
519        static extern int StgOpenStorageOnILockBytes(
520            ILockBytes plkbyt,
521            IStorage pStgPriority,
522            STGM grfMode,
523            IntPtr snbEnclude,
524            uint reserved,
525            out IStorage ppstgOpen);
526        [DllImport("ole32.dll")]
527        static extern int CreateILockBytesOnHGlobal(
528            IntPtr hGlobal,
529            bool fDeleteOnRelease,
530            out ILockBytes ppLkbyt);
531
532        [DllImport("ole32.dll")]
533        static extern int StgCreateDocfileOnILockBytes(ILockBytes plkbyt, STGM grfMode, int reserved, out IStorage ppstgOpen);
534       
535        #endregion
536        internal static int IsStorageFile(string Name)
537        {
538            return StgIsStorageFile(Name);
539        }
540        internal static int IsStorageILockBytes(ILockBytes lb)
541        {
542            return StgIsStorageILockBytes(lb);
543        }
544        internal ILockBytes GetLockbyte(MemoryStream stream)
545        {
546            ILockBytes lb;
547            var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
548            byte[] docArray = stream.GetBuffer();
549            IntPtr buffer = Marshal.AllocHGlobal(docArray.Length);
550            Marshal.Copy(docArray, 0, buffer, docArray.Length);
551            UIntPtr readSize;
552            lb.WriteAt(0, buffer, docArray.Length, out readSize);
553            Marshal.FreeHGlobal(buffer);
554            return lb;
555        }
556        private MemoryStream ReadParts(IStorage storage, StoragePart storagePart)
557        {
558            MemoryStream ret = null;
559            comTypes.STATSTG statstg;
560
561            storage.Stat(out statstg, (uint)STATFLAG.STATFLAG_DEFAULT);
562
563            IEnumSTATSTG pIEnumStatStg = null;
564            storage.EnumElements(0, IntPtr.Zero, 0, out pIEnumStatStg);
565
566            comTypes.STATSTG[] regelt = { statstg };
567            uint fetched = 0;
568            uint res = pIEnumStatStg.Next(1, regelt, out fetched);
569
570            //if (regelt[0].pwcsName == "DataSpaces")
571            //{
572            //    PrintStorage(storage, regelt[0],"");
573            //}
574            while (res != 1)
575            {
576                foreach (var item in regelt)
577                {
578                    if (item.type == 1)
579                    {
580                        IStorage subStorage;
581                        storage.OpenStorage(item.pwcsName, null, STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE, IntPtr.Zero, 0, out subStorage);
582                        StoragePart subStoragePart=new StoragePart();
583                        storagePart.SubStorage.Add(item.pwcsName, subStoragePart);
584                        ReadParts(subStorage, subStoragePart);
585                    }
586                    else
587                    {
588                        storagePart.DataStreams.Add(item.pwcsName, GetOleStream(storage, item));                   
589                    }
590                }
591                res = pIEnumStatStg.Next(1, regelt, out fetched);
592            }
593            Marshal.ReleaseComObject(pIEnumStatStg);
594            return ret;
595        }
596        // Help method to print a storage part binary to c:\temp
597        //private void PrintStorage(IStorage storage, System.Runtime.InteropServices.ComTypes.STATSTG sTATSTG, string topName)
598        //{
599        //    IStorage ds;
600        //    if (topName.Length > 0)
601        //    {
602        //        topName = topName[0] < 'A' ? topName.Substring(1, topName.Length - 1) : topName;
603        //    }
604        //    storage.OpenStorage(sTATSTG.pwcsName,
605        //        null,
606        //        (uint)(STGM.DIRECT | STGM.READ | STGM.SHARE_EXCLUSIVE),
607        //        IntPtr.Zero,
608        //        0,
609        //        out ds);
610
611        //    System.Runtime.InteropServices.ComTypes.STATSTG statstgSub;
612        //    ds.Stat(out statstgSub, (uint)STATFLAG.STATFLAG_DEFAULT);
613
614        //    IEnumSTATSTG pIEnumStatStgSub = null;
615        //    System.Runtime.InteropServices.ComTypes.STATSTG[] regeltSub = { statstgSub };
616        //    ds.EnumElements(0, IntPtr.Zero, 0, out pIEnumStatStgSub);
617
618        //    uint fetched = 0;
619        //    while (pIEnumStatStgSub.Next(1, regeltSub, out fetched) == 0)
620        //    {
621        //        string sName = regeltSub[0].pwcsName[0] < 'A' ? regeltSub[0].pwcsName.Substring(1, regeltSub[0].pwcsName.Length - 1) : regeltSub[0].pwcsName;
622        //        if (regeltSub[0].type == 1)
623        //        {
624        //            PrintStorage(ds, regeltSub[0], topName + sName + "_");
625        //        }
626        //        else if(regeltSub[0].type==2)
627        //        {
628        //            File.WriteAllBytes(@"c:\temp\" + topName + sName + ".bin", GetOleStream(ds, regeltSub[0]));
629        //        }
630        //    }
631        //}    }
632        /// <summary>
633        /// Read the stream and return it as a byte-array
634        /// </summary>
635        /// <param name="storage"></param>
636        /// <param name="statstg"></param>
637        /// <returns></returns>
638        private byte[] GetOleStream(IStorage storage, comTypes.STATSTG statstg)
639        {
640            comTypes.IStream pIStream;
641            storage.OpenStream(statstg.pwcsName,
642               IntPtr.Zero,
643               (uint)(STGM.READ | STGM.SHARE_EXCLUSIVE),
644               0,
645               out pIStream);
646
647            byte[] data = new byte[statstg.cbSize];
648            pIStream.Read(data, (int)statstg.cbSize, IntPtr.Zero);
649            Marshal.ReleaseComObject(pIStream);
650
651            return data;
652        }
653        internal byte[] Save()
654        {
655            ILockBytes lb;
656            var iret = CreateILockBytesOnHGlobal(IntPtr.Zero, true, out lb);
657
658            IStorage storage = null;
659            byte[] ret = null;
660
661            //Create the document in-memory
662            if (StgCreateDocfileOnILockBytes(lb,
663                    STGM.CREATE | STGM.READWRITE | STGM.SHARE_EXCLUSIVE | STGM.TRANSACTED,
664                    0,
665                    out storage)==0)
666            {
667                foreach(var store in this.Storage.SubStorage)
668                {
669                    CreateStore(store.Key, store.Value, storage);
670                }
671                CreateStreams(this.Storage, storage);                               
672                lb.Flush();
673               
674                //Now copy the unmanaged stream to a byte array --> memory stream
675                var statstg = new comTypes.STATSTG();
676                lb.Stat(out statstg, 0);
677                int size = (int)statstg.cbSize;
678                IntPtr buffer = Marshal.AllocHGlobal(size);
679                UIntPtr readSize;
680                ret=new byte[size];
681                lb.ReadAt(0, buffer, size, out readSize);
682                Marshal.Copy(buffer, ret, 0, size);
683                Marshal.FreeHGlobal(buffer);
684            }
685            Marshal.ReleaseComObject(storage);
686            Marshal.ReleaseComObject(lb);
687
688            return ret;
689        }
690
691        private void CreateStore(string name, StoragePart subStore, IStorage storage)
692        {
693            IStorage subStorage;
694            storage.CreateStorage(name, (uint)(STGM.CREATE | STGM.WRITE | STGM.DIRECT | STGM.SHARE_EXCLUSIVE), 0, 0, out subStorage);
695            storage.Commit(0);
696            foreach (var store in subStore.SubStorage)
697            {
698                CreateStore(store.Key, store.Value, subStorage);
699            }
700           
701            CreateStreams(subStore, subStorage);
702        }
703
704        private void CreateStreams(StoragePart subStore, IStorage subStorage)
705        {
706            foreach (var ds in subStore.DataStreams)
707            {
708                comTypes.IStream stream;
709                subStorage.CreateStream(ds.Key, (uint)(STGM.CREATE | STGM.WRITE | STGM.DIRECT | STGM.SHARE_EXCLUSIVE), 0, 0, out stream);
710                stream.Write(ds.Value, ds.Value.Length, IntPtr.Zero);
711            }
712            subStorage.Commit(0);
713        }
714
715    }
716}
Note: See TracBrowser for help on using the repository browser.