Exemplo n.º 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());
        }
Exemplo n.º 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();
                }
            }
        }