Exemple #1
0
        public static IList <KeyValuePair <string, Tuple <string, ModuleType> > > GetFolderModules(string folderPath)
        {
            var modulesText = new Dictionary <string, Tuple <string, ModuleType> >();
            var extensions  = new[] { ".bas", ".cls", ".frm" };
            var projIni     = new ProjectIni(Path.Combine(folderPath, "Project.INI"));

            if (File.Exists(Path.Combine(folderPath, "Project.INI.local")))
            {
                projIni.AddFile(Path.Combine(folderPath, "Project.INI.local"));
            }
            var projEncoding = Encoding.GetEncoding(projIni.GetInt("General", "CodePage") ?? Encoding.Default.CodePage);

            foreach (var filePath in Directory.GetFiles(folderPath, "*.*").Where(s => extensions.Any(s.EndsWith)).Select(s => Path.Combine(folderPath, Path.GetFileName(s))))
            {
                var moduleText = File.ReadAllText(filePath, projEncoding).TrimEnd('\r', '\n') + "\r\n";
                modulesText[Path.GetFileNameWithoutExtension(filePath)] = Tuple.Create(moduleText, ModuleProcessing.TypeFromText(moduleText));
            }
            return(modulesText.ToList());
        }
Exemple #2
0
        public void Write(string filePath)
        {
            if (string.IsNullOrEmpty(filePath))
            {
                throw new ArgumentException("Path to file cannot be null or empty.", nameof(filePath));
            }

            File.Delete(Path.Combine(FolderPath, "vbaProject.bin"));
            var cf         = new CompoundFile();
            var vbaProject = cf.RootStorage;

            var projIni = new ProjectIni(Path.Combine(FolderPath, "Project.INI"));

            if (File.Exists(Path.Combine(FolderPath, "Project.INI.local")))
            {
                projIni.AddFile(Path.Combine(FolderPath, "Project.INI.local"));
            }
            var projEncoding = Encoding.GetEncoding(projIni.GetInt("General", "CodePage") ?? Encoding.Default.CodePage);

            if (!projEncoding.Equals(Encoding.Default))
            {
                projIni = new ProjectIni(Path.Combine(FolderPath, "Project.INI"), projEncoding);
                if (File.Exists(Path.Combine(FolderPath, "Project.INI.local")))
                {
                    projIni.AddFile(Path.Combine(FolderPath, "Project.INI.local"));
                }
            }
            var projSysKind = (uint)(projIni.GetInt("General", "SysKind") ?? 1);
            var projVersion = projIni.GetVersion("General", "Version") ?? new Version(1, 1);

            var refs = new List <Reference>();

            foreach (var refName in projIni.GetReferenceNames())
            {
                var refSubj = $"Reference {refName}";
                if (projIni.GetString(refSubj, "LibIdTwiddled") != null)
                {
                    refs.Add(new ReferenceControl {
                        Cookie             = (uint)(projIni.GetInt(refSubj, "Cookie") ?? 0),
                        LibIdExtended      = projIni.GetString(refSubj, "LibIdExtended"),
                        LibIdTwiddled      = projIni.GetString(refSubj, "LibIdTwiddled"),
                        Name               = refName,
                        NameRecordExtended = projIni.GetString(refSubj, "NameRecordExtended"),
                        OriginalLibId      = projIni.GetString(refSubj, "OriginalLibId"),
                        OriginalTypeLib    = projIni.GetGuid(refSubj, "OriginalTypeLib") ?? Guid.Empty
                    });
                }
                else if (projIni.GetString(refSubj, "LibIdAbsolute") != null)
                {
                    refs.Add(new ReferenceProject {
                        LibIdAbsolute = projIni.GetString(refSubj, "LibIdAbsolute"),
                        LibIdRelative = projIni.GetString(refSubj, "LibIdRelative"),
                        Name          = refName,
                        Version       = projIni.GetVersion(refSubj, "Version")
                    });
                }
                else
                {
                    refs.Add(new ReferenceRegistered {
                        LibId = projIni.GetString(refSubj, "LibId"),
                        Name  = refName
                    });
                }
            }

            var mods    = new List <Module>();
            var modExts = new[] { ".bas", ".cls", ".frm" };

            foreach (var modPath in Directory.GetFiles(FolderPath).Where(s => modExts.Contains(Path.GetExtension(s) ?? "", StringComparer.InvariantCultureIgnoreCase)))
            {
                var modName = Path.GetFileNameWithoutExtension(modPath);
                var modText = File.ReadAllText(modPath, projEncoding);
                var modType = ModuleProcessing.TypeFromText(modText);
                projIni.RegisterModule(modName, modType, (uint)(projIni.GetInt("DocTLibVersions", modName) ?? 0));
                mods.Add(new Module {
                    DocString   = GetAttribute(modText, "VB_Description"),
                    HelpContext = GetAttributeUInt(modText, "VB_HelpID"),
                    Name        = modName,
                    StreamName  = modName,
                    Type        = modType
                });
            }

            vbaProject.AddStream("PROJECT");
            vbaProject.GetStream("PROJECT").SetData(projEncoding.GetBytes(projIni.GetProjectText()));

            vbaProject.AddStream("PROJECTlk");
            vbaProject.GetStream("PROJECTlk").SetData(File.Exists(Path.Combine(FolderPath, "LicenseKeys.bin"))
                ? File.ReadAllBytes(Path.Combine(FolderPath, "LicenseKeys.bin"))
                : new byte[] { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 });

            var projectWm = new List <byte>();

            foreach (var modName in mods.Select(m => m.Name))
            {
                projectWm.AddRange(projEncoding.GetBytes(modName));
                projectWm.Add(0x00);
                projectWm.AddRange(Encoding.Unicode.GetBytes(modName));
                projectWm.Add(0x00);
                projectWm.Add(0x00);
            }
            projectWm.AddRange(new byte[] { 0x00, 0x00 });
            vbaProject.AddStream("PROJECTwm");
            vbaProject.GetStream("PROJECTwm").SetData(projectWm.ToArray());

            vbaProject.AddStorage("VBA");
            var vbaProjectVba = vbaProject.GetStorage("VBA");

            vbaProjectVba.AddStream("_VBA_PROJECT");
            vbaProjectVba.GetStream("_VBA_PROJECT").SetData(new byte[] { 0xCC, 0x61, 0xFF, 0xFF, 0x00, 0x00, 0x00 });

            var dirUc = new List <byte>(); // uncompressed dir stream

            dirUc.AddRange(BitConverter.GetBytes((short)0x0001));
            dirUc.AddRange(BitConverter.GetBytes(4));
            dirUc.AddRange(BitConverter.GetBytes(projSysKind));
            dirUc.AddRange(BitConverter.GetBytes((short)0x0002));
            dirUc.AddRange(BitConverter.GetBytes(4));
            dirUc.AddRange(BitConverter.GetBytes(0x00000409)); // LCID
            dirUc.AddRange(BitConverter.GetBytes((short)0x0014));
            dirUc.AddRange(BitConverter.GetBytes(4));
            dirUc.AddRange(BitConverter.GetBytes(0x00000409)); // LCIDINVOKE
            dirUc.AddRange(BitConverter.GetBytes((short)0x0003));
            dirUc.AddRange(BitConverter.GetBytes(2));
            dirUc.AddRange(BitConverter.GetBytes((short)projEncoding.CodePage));
            var projNameBytes = projEncoding.GetBytes(projIni.GetString("General", "Name") ?? "");

            dirUc.AddRange(BitConverter.GetBytes((short)0x0004));
            dirUc.AddRange(BitConverter.GetBytes(projNameBytes.Length));
            dirUc.AddRange(projNameBytes);
            var projDocStringBytes    = projEncoding.GetBytes(projIni.GetString("General", "Description") ?? "");
            var projDocStringUtfBytes = Encoding.Unicode.GetBytes(projIni.GetString("General", "Description") ?? "");

            dirUc.AddRange(BitConverter.GetBytes((short)0x0005));
            dirUc.AddRange(BitConverter.GetBytes(projDocStringBytes.Length));
            dirUc.AddRange(projDocStringBytes);
            dirUc.AddRange(BitConverter.GetBytes((short)0x0040));
            dirUc.AddRange(BitConverter.GetBytes(projDocStringUtfBytes.Length));
            dirUc.AddRange(projDocStringUtfBytes);
            var projHelpFileBytes = projEncoding.GetBytes(projIni.GetString("General", "HelpFile") ?? "");

            dirUc.AddRange(BitConverter.GetBytes((short)0x0006));
            dirUc.AddRange(BitConverter.GetBytes(projHelpFileBytes.Length));
            dirUc.AddRange(projHelpFileBytes);
            dirUc.AddRange(BitConverter.GetBytes((short)0x003D));
            dirUc.AddRange(BitConverter.GetBytes(projHelpFileBytes.Length));
            dirUc.AddRange(projHelpFileBytes);
            dirUc.AddRange(BitConverter.GetBytes((short)0x0007));
            dirUc.AddRange(BitConverter.GetBytes(4));
            dirUc.AddRange(BitConverter.GetBytes(projIni.GetInt("General", "HelpContextID") ?? 0));
            dirUc.AddRange(BitConverter.GetBytes((short)0x0008));
            dirUc.AddRange(BitConverter.GetBytes(4));
            dirUc.AddRange(BitConverter.GetBytes(0)); // LIBFLAGS
            dirUc.AddRange(BitConverter.GetBytes((short)0x0009));
            dirUc.AddRange(BitConverter.GetBytes(4));
            dirUc.AddRange(BitConverter.GetBytes(projVersion.Major));
            dirUc.AddRange(BitConverter.GetBytes((short)projVersion.Minor));
            var projConstantsBytes    = projEncoding.GetBytes(projIni.GetConstantsString());
            var projConstantsUtfBytes = Encoding.Unicode.GetBytes(projIni.GetConstantsString());

            dirUc.AddRange(BitConverter.GetBytes((short)0x000C));
            dirUc.AddRange(BitConverter.GetBytes(projConstantsBytes.Length));
            dirUc.AddRange(projConstantsBytes);
            dirUc.AddRange(BitConverter.GetBytes((short)0x003C));
            dirUc.AddRange(BitConverter.GetBytes(projConstantsUtfBytes.Length));
            dirUc.AddRange(projConstantsUtfBytes);
            foreach (var rfc in refs)
            {
                dirUc.AddRange(rfc.GetBytes(projEncoding));
            }
            dirUc.AddRange(BitConverter.GetBytes((short)0x000F));
            dirUc.AddRange(BitConverter.GetBytes(2));
            dirUc.AddRange(BitConverter.GetBytes((short)mods.Count));
            dirUc.AddRange(BitConverter.GetBytes((short)0x0013));
            dirUc.AddRange(BitConverter.GetBytes(2));
            dirUc.AddRange(BitConverter.GetBytes((short)-1)); // PROJECTCOOKIE
            foreach (var mod in mods)
            {
                dirUc.AddRange(mod.GetBytes(projEncoding));
            }
            dirUc.AddRange(BitConverter.GetBytes((short)0x0010));
            dirUc.AddRange(BitConverter.GetBytes(0)); // global terminator
            vbaProjectVba.AddStream("dir");
            vbaProjectVba.GetStream("dir").SetData(CompoundDocumentCompression.CompressPart(dirUc.ToArray()));

            foreach (var mod in mods)
            {
                switch (mod.Type)
                {
                case ModuleType.Class:
                case ModuleType.StaticClass:
                    vbaProjectVba.AddStream(mod.StreamName);
                    var fileText = File.ReadAllText(Path.Combine(FolderPath, mod.Name + ModuleProcessing.ExtensionFromType(mod.Type)), projEncoding);
                    vbaProjectVba.GetStream(mod.StreamName).SetData(CompoundDocumentCompression.CompressPart(projEncoding.GetBytes(SeparateClassCode(fileText))));
                    break;

                case ModuleType.Form:
                    string vbFrame;
                    vbaProjectVba.AddStream(mod.StreamName);
                    vbaProjectVba.GetStream(mod.StreamName).SetData(CompoundDocumentCompression.CompressPart(
                                                                        projEncoding.GetBytes(SeparateVbFrame(File.ReadAllText(Path.Combine(FolderPath, mod.Name + ".frm"), projEncoding), out vbFrame))));
                    vbaProject.AddStorage(mod.StreamName);
                    var frmStorage = vbaProject.GetStorage(mod.StreamName);
                    frmStorage.AddStream("\x03VBFrame");
                    frmStorage.GetStream("\x03VBFrame").SetData(projEncoding.GetBytes(vbFrame));
                    var b = File.ReadAllBytes(Path.Combine(FolderPath, mod.Name + ".frx"));
                    using (var ms = new MemoryStream(b, 24, b.Length - 24)) {
                        var frx = new CompoundFile(ms);
                        CopyCfStreamsExcept(frx.RootStorage, frmStorage, "\x03VBFrame");
                    }
                    break;

                default:
                    vbaProjectVba.AddStream(mod.StreamName);
                    vbaProjectVba.GetStream(mod.StreamName).SetData(CompoundDocumentCompression.CompressPart(
                                                                        File.ReadAllBytes(Path.Combine(FolderPath, mod.Name + ModuleProcessing.ExtensionFromType(mod.Type)))));
                    break;
                }
            }

            cf.Save(Path.Combine(FolderPath, "vbaProject.bin"));

            if (Path.GetFileName(filePath).Equals("vbaProject.bin", StringComparison.InvariantCultureIgnoreCase))
            {
                File.Copy(Path.Combine(FolderPath, "vbaProject.bin"), filePath, true);
            }
            else
            {
                FileStream fs = null;
                try {
                    fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite);
                    var sig = new byte[4];
                    fs.Read(sig, 0, 4);
                    fs.Seek(0, SeekOrigin.Begin);
                    if (sig.SequenceEqual(new byte[] { 0x50, 0x4b, 0x03, 0x04 }))
                    {
                        var zipFile  = new ZipFile(fs);
                        var zipEntry = zipFile.Cast <ZipEntry>().FirstOrDefault(e => e.Name.EndsWith("vbaProject.bin", StringComparison.InvariantCultureIgnoreCase));
                        if (zipEntry == null)
                        {
                            throw new ApplicationException("Cannot find 'vbaProject.bin' in ZIP archive.");
                        }
                        zipFile.BeginUpdate();
                        zipFile.Add(Path.Combine(FolderPath, "vbaProject.bin"), zipEntry.Name);
                        zipFile.CommitUpdate();
                        zipFile.Close();
                    }
                    else
                    {
                        var destCf         = new CompoundFile(fs, CFSUpdateMode.Update, CFSConfiguration.Default);
                        var destVbaProject = destCf.GetAllNamedEntries("_VBA_PROJECT_CUR").FirstOrDefault() as CFStorage
                                             ?? destCf.GetAllNamedEntries("OutlookVbaData").FirstOrDefault() as CFStorage
                                             ?? destCf.GetAllNamedEntries("Macros").FirstOrDefault() as CFStorage;
                        var ls = new List <string>();
                        destVbaProject.VisitEntries(i => ls.Add(i.Name), true);
                        while (ls.Count > 0)
                        {
                            DeleteStorageChildren(destVbaProject);
                            ls.Clear();
                            destVbaProject.VisitEntries(i => ls.Add(i.Name), true);
                        }
                        CopyCfStreamsExcept(cf.RootStorage, destVbaProject, null);
                        destCf.Commit();
                        //destCf.Save(fs);
                        destCf.Close();
                    }
                } finally {
                    fs?.Dispose();
                }
            }
        }
Exemple #3
0
        void changesGrid_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            var    sel      = (Patch)ChangesGrid.SelectedItem;
            var    fileName = sel.ModuleName + (sel.ChangeType != ChangeType.ChangeFormControls ? ModuleProcessing.ExtensionFromType(sel.ModuleType) : ".frx");
            string oldPath;
            string newPath;

            if (Session.Action == ActionType.Extract)
            {
                oldPath = Path.Combine(Session.FolderPath, fileName);
                newPath = Path.Combine(_evf.FolderPath, fileName);
            }
            else
            {
                oldPath = Path.Combine(_evf.FolderPath, fileName);
                newPath = Path.Combine(Session.FolderPath, fileName);
            }
            if (sel.ChangeType == ChangeType.ChangeFormControls)
            {
                string explain;
                Lib.FrxFilesAreDifferent(oldPath, newPath, out explain);
                MessageBox.Show(explain, "FRX file difference", MessageBoxButton.OK, MessageBoxImage.Information);
            }
            else
            {
                var diffExePath = Environment.ExpandEnvironmentVariables(Session.DiffTool);
                if (!File.Exists(oldPath) || !File.Exists(newPath) || !File.Exists(diffExePath))
                {
                    return;
                }
                var p = new Process {
                    StartInfo = new ProcessStartInfo(diffExePath, Session.DiffToolParameters.Replace("{OldFile}", oldPath).Replace("{NewFile}", newPath))
                    {
                        UseShellExecute = false
                    }
                };
                p.Start();
            }
        }
Exemple #4
0
        public VbaFolder(string path, IDictionary <string, string> compareModules)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentException("Path to file cannot be null or empty.", nameof(path));
            }

            FileStream fs = null;

            try {
                fs         = new FileStream(path, FileMode.Open);
                FolderPath = $"{Path.GetTempPath()}VBASync-{Guid.NewGuid()}";
                Directory.CreateDirectory(FolderPath);

                CFStorage vbaProject;
                if (Path.GetFileName(path).Equals("vbaProject.bin", StringComparison.InvariantCultureIgnoreCase))
                {
                    vbaProject = new CompoundFile(fs).RootStorage;
                }
                else
                {
                    var sig = new byte[4];
                    fs.Read(sig, 0, 4);
                    if (sig.SequenceEqual(new byte[] { 0x50, 0x4b, 0x03, 0x04 }))
                    {
                        var zipFile  = new ZipFile(fs);
                        var zipEntry = zipFile.Cast <ZipEntry>().FirstOrDefault(e => e.Name.EndsWith("vbaProject.bin", StringComparison.InvariantCultureIgnoreCase));
                        if (zipEntry == null)
                        {
                            throw new ApplicationException("Cannot find 'vbaProject.bin' in ZIP archive.");
                        }
                        using (var sw = File.Create(Path.Combine(FolderPath, "vbaProject.bin"))) {
                            StreamUtils.Copy(zipFile.GetInputStream(zipEntry), sw, new byte[4096]);
                        }
                        fs.Dispose();
                        fs         = new FileStream(Path.Combine(FolderPath, "vbaProject.bin"), FileMode.Open);
                        vbaProject = new CompoundFile(fs).RootStorage;
                    }
                    else
                    {
                        fs.Seek(0, SeekOrigin.Begin);
                        vbaProject = new CompoundFile(fs).GetAllNamedEntries("_VBA_PROJECT_CUR").FirstOrDefault() as CFStorage
                                     ?? new CompoundFile(fs).GetAllNamedEntries("OutlookVbaData").FirstOrDefault() as CFStorage
                                     ?? new CompoundFile(fs).GetAllNamedEntries("Macros").FirstOrDefault() as CFStorage;
                    }
                }
                if (vbaProject == null)
                {
                    throw new ApplicationException("Cannot find VBA project storage in file.");
                }

                var projectLk = vbaProject.TryGetStream("PROJECTlk");
                if (projectLk != null)
                {
                    File.WriteAllBytes(Path.Combine(FolderPath, "LicenseKeys.bin"), projectLk.GetData());
                }

                var    projEncoding   = Encoding.Default;
                uint   projSysKind    = 1;
                var    projVersion    = new Version(1, 1);
                var    projConstants  = new List <string>();
                string currentRefName = null;
                var    references     = new List <Reference>();
                var    originalLibIds = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase);
                var    modules        = new List <Module>();
                Module currentModule  = null;
                var    projStrings    = new List <string>();
                using (var br = new BinaryReader(new MemoryStream(DecompressStream(vbaProject.GetStorage("VBA").GetStream("dir"))))) {
                    Action <int> seek = i => br.BaseStream.Seek(i, SeekOrigin.Current);
                    while (br.BaseStream.Position < br.BaseStream.Length)
                    {
                        switch (br.ReadUInt16())
                        {
                        case 0x0001:
                            // PROJECTSYSKIND
                            seek(4);     // seek past size (always 4)
                            projSysKind = br.ReadUInt32();
                            break;

                        case 0x0002:
                        case 0x0014:
                        case 0x0008:
                        case 0x0007:
                            // PROJECTLCID, PROJECTLCIDINVOKE, PROJECTLIBFLAGS, and PROJECTHELPCONTEXT
                            seek(8);     // seek past whole record (always 8 bytes long)
                            break;

                        case 0x0003:
                            // PROJECTCODEPAGE
                            seek(4);     // seek past size (always 4)
                            projEncoding = Encoding.GetEncoding(br.ReadInt16());
                            break;

                        case 0x0004:
                            // PROJECTNAME
                            seek(br.ReadInt32());     // seek past whole record, since its contents are already in PROJECT
                            break;

                        case 0x0005:
                        case 0x0006:
                            // PROJECTDOCSTRING and PROJECTHELPFILEPATH
                            seek(br.ReadInt32() + 2);     // seek past whole record, since its contents are already in PROJECT
                            seek(br.ReadInt32());
                            break;

                        case 0x0009:
                            // PROJECTVERSION
                            seek(4);     // seek past Reserved
                            projVersion = new Version(br.ReadInt32(), br.ReadInt16());
                            break;

                        case 0x000c:
                            // PROJECTCONSTANTS
                            seek(br.ReadInt32() + 2);     // seek past Constants and Reserved
                            projConstants.AddRange(Encoding.Unicode.GetString(br.ReadBytes(br.ReadInt32())).Split(':').Select(s => s.Trim()));
                            if (projConstants.Count == 1 && string.IsNullOrEmpty(projConstants[0]))
                            {
                                projConstants.RemoveAt(0);
                            }
                            break;

                        case 0x0016:
                            // REFERENCENAME
                            seek(br.ReadInt32() + 2);     // seek past Name and Reserved
                            currentRefName = Encoding.Unicode.GetString(br.ReadBytes(br.ReadInt32()));
                            break;

                        case 0x0033:
                            // REFERENCEORIGINAL
                            originalLibIds.Add(currentRefName, projEncoding.GetString(br.ReadBytes(br.ReadInt32())));
                            break;

                        case 0x002f:
                            // REFERENCECONTROL (after optional REFERENCEORIGINAL)
                            seek(4);     // seek past SizeTwiddled
                            var libIdTwiddled = projEncoding.GetString(br.ReadBytes(br.ReadInt32()));
                            seek(6);     // seek past Reserved1 and Reserved2
                            string nameRecordExtended = null;
                            if (br.PeekChar() == 0x16)
                            {
                                // an optional REFERENCENAME record
                                seek(2);                  // seek past Id
                                seek(br.ReadInt32() + 2); // seek past Name and Reserved
                                nameRecordExtended = Encoding.Unicode.GetString(br.ReadBytes(br.ReadInt32()));
                            }
                            seek(6);     // seek past Reserved3 and SizeExtended
                            var libIdExtended = projEncoding.GetString(br.ReadBytes(br.ReadInt32()));
                            seek(6);     // seek past Reserved4 and Reserved5
                            var originalTypeLib = new Guid(br.ReadBytes(16));
                            var cookie          = br.ReadUInt32();
                            var refCtl          = new ReferenceControl {
                                Name               = currentRefName,
                                Cookie             = cookie, LibIdExtended = libIdExtended, LibIdTwiddled = libIdTwiddled,
                                NameRecordExtended = nameRecordExtended, OriginalTypeLib = originalTypeLib
                            };
                            if (originalLibIds.ContainsKey(currentRefName))
                            {
                                refCtl.OriginalLibId = originalLibIds[currentRefName];
                            }
                            references.Add(refCtl);
                            break;

                        case 0x000d:
                            // REFERENCEREGISTERED
                            seek(4);     // seek past Size
                            references.Add(new ReferenceRegistered {
                                Name = currentRefName, LibId = projEncoding.GetString(br.ReadBytes(br.ReadInt32()))
                            });
                            seek(6);     // seek past Reserved1 and Reserved2
                            break;

                        case 0x000e:
                            // REFERENCEPROJECT
                            seek(4);     // seek past Size
                            references.Add(new ReferenceProject {
                                Name          = currentRefName,
                                LibIdAbsolute = projEncoding.GetString(br.ReadBytes(br.ReadInt32())),
                                LibIdRelative = projEncoding.GetString(br.ReadBytes(br.ReadInt32())),
                                Version       = new Version(br.ReadInt32(), br.ReadInt16())
                            });
                            break;

                        case 0x000f:
                            // PROJECTMODULES
                            seek(6);     // ignore entire record
                            break;

                        case 0x0013:
                            // PROJECTCOOKIE
                            seek(6);     // ignore entire record
                            break;

                        case 0x0019:
                            // MODULENAME
                            seek(br.ReadInt32());     // ignore entire record
                            break;

                        case 0x0047:
                            // MODULENAMEUNICODE
                            modules.Add(currentModule = new Module {
                                Name = Encoding.Unicode.GetString(br.ReadBytes(br.ReadInt32()))
                            });
                            break;

                        case 0x001a:
                            // MODULESTREAMNAME
                            seek(br.ReadInt32() + 2);     // seek past StreamName and Reserved
                            currentModule.StreamName = Encoding.Unicode.GetString(br.ReadBytes(br.ReadInt32()));
                            break;

                        case 0x001c:
                            // MODULEDOCSTRING - ignore since this info is already in the module itself
                            seek(br.ReadInt32() + 2); // seek past DocString and Reserved
                            seek(br.ReadInt32());     // seek past DocStringUnicode
                            break;

                        case 0x0031:
                            // MODULEOFFSET
                            seek(4);     // seek past size (always 4)
                            currentModule.Offset = br.ReadUInt32();
                            break;

                        case 0x001e:
                            // MODULEHELPCONTEXT
                            seek(8);     // seek past entire record - this information is in the module itself as well
                            break;

                        case 0x002c:
                            // MODULECOOKIE
                            seek(6);     // ignore entire record
                            break;

                        case 0x0021:
                            // MODULETYPE - procedural flag
                            seek(4);     // ignore entire record since we get information about this from the PROJECT stream
                            break;

                        case 0x0022:
                            // MODULETYPE - document, class, or designer flag
                            seek(4);     // ignore entire record since we get information about this from the PROJECT stream
                            break;

                        case 0x0025:
                            // MODULEREADONLY
                            currentModule.ReadOnly = true;
                            seek(4);     // seek past Reserved
                            break;

                        case 0x0028:
                            // MODULEPRIVATE
                            currentModule.Private = true;
                            seek(4);     // seek past Reserved
                            break;

                        case 0x002b:
                            // module terminator
                            currentModule = null;
                            seek(4);
                            break;

                        case 0x0010:
                            // global terminator
                            seek(4);
                            break;

                        default:
                            seek(-2);
                            throw new ApplicationException($"Unknown record id '0x{br.ReadInt16().ToString("X4")}'.");
                        }
                    }
                }
                using (var sr = new StreamReader(new MemoryStream(vbaProject.GetStream("PROJECT").GetData()), projEncoding)) {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        var split     = line.Split('=');
                        var breakLoop = false;
                        switch (split[0]?.ToUpperInvariant())
                        {
                        case "MODULE":
                            modules.First(m => string.Equals(m.Name, split[1], StringComparison.InvariantCultureIgnoreCase))
                            .Type = ModuleType.Standard;
                            break;

                        case "DOCUMENT":
                            var split2 = split[1].Split('/');
                            var mod    = modules.First(m => string.Equals(m.Name, split2[0], StringComparison.InvariantCultureIgnoreCase));
                            mod.Type    = ModuleType.StaticClass;
                            mod.Version = uint.Parse(split2[1].Substring(2), NumberStyles.HexNumber);
                            break;

                        case "CLASS":
                            modules.First(m => string.Equals(m.Name, split[1], StringComparison.InvariantCultureIgnoreCase))
                            .Type = ModuleType.Class;
                            break;

                        case "BASECLASS":
                            modules.First(m => string.Equals(m.Name, split[1], StringComparison.InvariantCultureIgnoreCase))
                            .Type = ModuleType.Form;
                            break;

                        default:
                            if (line.Equals("[Workspace]", StringComparison.InvariantCultureIgnoreCase))
                            {
                                breakLoop = true;     // don't output all the cruft after [Workspace]
                            }
                            else
                            {
                                projStrings.Add(line);
                            }
                            break;
                        }
                        if (breakLoop)
                        {
                            break;
                        }
                    }
                }
                DeleteBlankLinesFromEnd(projStrings);
                projStrings.Insert(0, $"Version={projVersion}");
                projStrings.Insert(0, $"SysKind={projSysKind}");
                projStrings.Insert(0, $"CodePage={projEncoding.CodePage}");
                projStrings.Add("");
                projStrings.Add("[Constants]");
                projStrings.AddRange(projConstants.Select(s => string.Join("=", s.Split('=').Select(t => t.Trim()))));
                if (modules.Any(m => m.Version > 0))
                {
                    projStrings.Add("");
                    projStrings.Add("[DocTLibVersions]");
                    projStrings.AddRange(modules.Where(m => m.Version > 0).Select(m => $"{m.Name}={m.Version}"));
                }
                foreach (var refer in references)
                {
                    projStrings.Add("");
                    projStrings.Add($"[Reference {refer.Name}]");
                    projStrings.AddRange(refer.GetConfigStrings());
                }

                File.WriteAllLines(Path.Combine(FolderPath, "Project.ini"), projStrings, projEncoding);

                ModuleTexts = new Dictionary <string, Tuple <string, ModuleType> >();
                foreach (var m in modules)
                {
                    var moduleText = projEncoding.GetString(DecompressStream(vbaProject.GetStorage("VBA").GetStream(m.StreamName), m.Offset));
                    if (compareModules.ContainsKey(m.Name))
                    {
                        moduleText = ModuleProcessing.FixCase(compareModules[m.Name], moduleText);
                    }
                    moduleText = (GetPrepend(m, vbaProject, projEncoding) + moduleText).TrimEnd('\r', '\n') + "\r\n";
                    ModuleTexts.Add(m.Name, Tuple.Create(moduleText, m.Type));
                    File.WriteAllText(Path.Combine(FolderPath, m.Name + ModuleProcessing.ExtensionFromType(m.Type)), moduleText, projEncoding);
                }

                foreach (var m in modules.Where(mod => mod.Type == ModuleType.Form))
                {
                    var cf = new CompoundFile();
                    CopyCfStreamsExcept(vbaProject.GetStorage(m.StreamName), cf.RootStorage, "\x0003VBFrame");
                    var frxPath = Path.Combine(FolderPath, m.Name + ".frx");
                    cf.Save(frxPath);
                    var bytes = File.ReadAllBytes(frxPath);
                    var size  = new FileInfo(frxPath).Length;
                    using (var bw = new BinaryWriter(new FileStream(frxPath, FileMode.Open))) {
                        bw.Write((short)0x424c);
                        bw.Write(new byte[3]);
                        bw.Write(size >> 8);
                        bw.Write(new byte[11]);
                        bw.Write(bytes);
                    }
                }
            } finally {
                fs.Dispose();
            }
        }
Exemple #5
0
        void applyButton_Click(object sender, RoutedEventArgs e)
        {
            var vm = ChangesGrid.DataContext as ChangesViewModel;

            if (vm == null)
            {
                return;
            }
            if (Session.Action == ActionType.Extract)
            {
                foreach (var p in vm.Where(p => p.Commit).ToArray())
                {
                    var fileName = p.ModuleName + ModuleProcessing.ExtensionFromType(p.ModuleType);
                    switch (p.ChangeType)
                    {
                    case ChangeType.DeleteFile:
                        File.Delete(Path.Combine(Session.FolderPath, fileName));
                        if (p.ModuleType == ModuleType.Form)
                        {
                            File.Delete(Path.Combine(Session.FolderPath, p.ModuleName + ".frx"));
                        }
                        break;

                    case ChangeType.ChangeFormControls:
                        File.Copy(Path.Combine(_evf.FolderPath, p.ModuleName + ".frx"), Path.Combine(Session.FolderPath, p.ModuleName + ".frx"), true);
                        break;

                    default:
                        File.Copy(Path.Combine(_evf.FolderPath, fileName), Path.Combine(Session.FolderPath, fileName), true);
                        if (p.ChangeType == ChangeType.AddFile && p.ModuleType == ModuleType.Form)
                        {
                            File.Copy(Path.Combine(_evf.FolderPath, p.ModuleName + ".frx"), Path.Combine(Session.FolderPath, p.ModuleName + ".frx"), true);
                        }
                        break;
                    }
                    vm.Remove(p);
                }
            }
            else
            {
                foreach (var p in vm.Where(p => p.Commit).ToArray())
                {
                    var fileName = p.ModuleName + ModuleProcessing.ExtensionFromType(p.ModuleType);
                    switch (p.ChangeType)
                    {
                    case ChangeType.DeleteFile:
                        File.Delete(Path.Combine(_evf.FolderPath, fileName));
                        if (p.ModuleType == ModuleType.Form)
                        {
                            File.Delete(Path.Combine(_evf.FolderPath, p.ModuleName + ".frx"));
                        }
                        break;

                    case ChangeType.ChangeFormControls:
                        File.Copy(Path.Combine(Session.FolderPath, p.ModuleName + ".frx"), Path.Combine(_evf.FolderPath, p.ModuleName + ".frx"), true);
                        break;

                    default:
                        File.Copy(Path.Combine(Session.FolderPath, fileName), Path.Combine(_evf.FolderPath, fileName), true);
                        if (p.ChangeType == ChangeType.AddFile && p.ModuleType == ModuleType.Form)
                        {
                            File.Copy(Path.Combine(Session.FolderPath, p.ModuleName + ".frx"), Path.Combine(_evf.FolderPath, p.ModuleName + ".frx"), true);
                        }
                        break;
                    }
                    vm.Remove(p);
                }
                _evf.Write(Session.FilePath);
            }
            UpdateIncludeAllBox();
        }