├── .gitattributes
├── .github
└── workflows
│ └── codeql-analysis.yml
├── .gitignore
├── CODE_OF_CONDUCT.md
├── EProjectFile.sln
├── EProjectFile
├── ClassInfo.cs
├── ClassPublicityInfo.cs
├── CodeDataParser.cs
├── CodeFolderInfo.cs
├── CompilationSchemeInfo.cs
├── ConstantInfo.cs
├── Context
│ ├── BlockByteifierContext.cs
│ └── BlockParserContext.cs
├── DllDeclareInfo.cs
├── ECDependencyInfo.cs
├── EProjectFile.csproj
├── EditorTabInfo
│ ├── ClassEditorTabInfo.cs
│ ├── FormDesignerTabInfo.cs
│ ├── GeneralEditorTabInfo.cs
│ ├── IEditorTabInfo.cs
│ ├── PredefinedEditorTabInfos.cs
│ └── PureTableEditorTabInfo.cs
├── Encryption
│ ├── EncryptionOptions.cs
│ ├── EplSecret.EC.cs
│ ├── EplSecret.EStd.cs
│ ├── EplSecret.cs
│ └── IEplSecretFactory.cs
├── EplDocument.cs
├── EplSystemId.cs
├── Expressions
│ ├── AccessArrayExpression.cs
│ ├── AccessMemberExpression.cs
│ ├── ArrayLiteralEnd.cs
│ ├── ArrayLiteralExpression.cs
│ ├── BoolLiteral.cs
│ ├── CallExpression.cs
│ ├── ConstantExpression.cs
│ ├── DateTimeLiteral.cs
│ ├── DefaultValueExpression.cs
│ ├── EmnuConstantExpression.cs
│ ├── Expression.cs
│ ├── In0x38Expression.cs
│ ├── MethodPtrExpression.cs
│ ├── NumberLiteral.cs
│ ├── ParamListEnd.cs
│ ├── ParamListExpression.cs
│ ├── StringLiteral.cs
│ └── VariableExpression.cs
├── FormControlInfo.cs
├── FormElementInfo.cs
├── FormInfo.cs
├── FormMenuInfo.cs
├── IDToNameMap.cs
├── IHasId.cs
├── IHasMemoryAddress.cs
├── IToTextCodeAble.cs
├── IndexedEventInfo.cs
├── Internal
│ ├── ByteArrayHexConverter.cs
│ ├── BytesUtils.cs
│ ├── CryptoECTransform.cs
│ ├── EStdCryptoTransform.cs
│ ├── EditorTabInfoJsonConverter.cs
│ ├── EncodingJsonConverter.cs
│ ├── ExtensionMethod.cs
│ ├── ImmutableByteArrayHexConverter.cs
│ ├── JsonUtils.cs
│ ├── PrefixedStream.cs
│ ├── RC4Crypto.cs
│ ├── SectionJsonConverter.cs
│ ├── StreamWithImmutableExtension.cs
│ └── TextCodeUtils.cs
├── LibraryRefInfo.cs
├── MethodCodeDataWriterArgs.cs
├── MethodInfo.cs
├── ProjectFileReader.cs
├── ProjectFileWriter.cs
├── Properties
│ └── launchSettings.json
├── RawSectionInfo.cs
├── RemovedDefinedItemInfo.cs
├── Sections
│ ├── ClassPublicitySection.cs
│ ├── CodeSection.cs
│ ├── ConditionalCompilationSection.cs
│ ├── ECDependenciesSection.cs
│ ├── EPackageInfoSection.cs
│ ├── ESystemInfoSection.cs
│ ├── EditorInfoSection.cs
│ ├── EndOfFileSection.cs
│ ├── EventIndicesSection.cs
│ ├── FolderSection.cs
│ ├── GeneralSection.cs
│ ├── ISection.cs
│ ├── InitECSection.cs
│ ├── LosableSection.cs
│ ├── PredefinedSections.cs
│ ├── ProjectConfigExSection.cs
│ ├── ProjectConfigSection.cs
│ └── ResourceSection.cs
├── Statements
│ ├── CounterStatement.cs
│ ├── DoWhileStatement.cs
│ ├── ExpressionStatement.cs
│ ├── ForStatement.cs
│ ├── IfElseStatement.cs
│ ├── IfStatement.cs
│ ├── LoopStatement.cs
│ ├── Statement.cs
│ ├── StatementBlock.cs
│ ├── SwitchStatement.cs
│ ├── UnexaminedStatement.cs
│ └── WhileStatement.cs
├── StructInfo.cs
└── VariableInfo
│ ├── AbstractVariableInfo.cs
│ ├── ClassVariableInfo.cs
│ ├── DllParameterInfo.cs
│ ├── GlobalVariableInfo.cs
│ ├── LocalVariableInfo.cs
│ ├── MethodParameterInfo.cs
│ └── StructMemberInfo.cs
├── LICENSE
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.github/workflows/codeql-analysis.yml:
--------------------------------------------------------------------------------
1 | # For most projects, this workflow file will not need changing; you simply need
2 | # to commit it to your repository.
3 | #
4 | # You may wish to alter this file to override the set of languages analyzed,
5 | # or to provide custom queries or build logic.
6 | #
7 | # ******** NOTE ********
8 | # We have attempted to detect the languages in your repository. Please check
9 | # the `language` matrix defined below to confirm you have the correct set of
10 | # supported CodeQL languages.
11 | #
12 | name: "CodeQL"
13 |
14 | on:
15 | push:
16 | branches: [ "main" ]
17 | pull_request:
18 | # The branches below must be a subset of the branches above
19 | branches: [ "main" ]
20 | schedule:
21 | - cron: '45 7 * * 6'
22 |
23 | jobs:
24 | analyze:
25 | name: Analyze
26 | runs-on: ubuntu-latest
27 | permissions:
28 | actions: read
29 | contents: read
30 | security-events: write
31 |
32 | strategy:
33 | fail-fast: false
34 | matrix:
35 | language: [ 'csharp' ]
36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
38 |
39 | steps:
40 | - name: Checkout repository
41 | uses: actions/checkout@v3
42 |
43 | # Initializes the CodeQL tools for scanning.
44 | - name: Initialize CodeQL
45 | uses: github/codeql-action/init@v2
46 | with:
47 | languages: ${{ matrix.language }}
48 | # If you wish to specify custom queries, you can do so here or in a config file.
49 | # By default, queries listed here will override any specified in a config file.
50 | # Prefix the list here with "+" to use these queries and those in the config file.
51 |
52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
53 | # queries: security-extended,security-and-quality
54 |
55 |
56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
57 | # If this step fails, then you should remove it and run the build manually (see below)
58 | - name: Autobuild
59 | uses: github/codeql-action/autobuild@v2
60 |
61 | # ℹ️ Command-line programs to run using the OS shell.
62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
63 |
64 | # If the Autobuild fails above, remove it and uncomment the following three lines.
65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
66 |
67 | # - run: |
68 | # echo "Run, Build Application using script"
69 | # ./location_of_script_within_repo/buildscript.sh
70 |
71 | - name: Perform CodeQL Analysis
72 | uses: github/codeql-action/analyze@v2
73 | with:
74 | category: "/language:${{matrix.language}}"
--------------------------------------------------------------------------------
/EProjectFile.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.2.32616.157
5 | MinimumVisualStudioVersion = 15.0.0.0
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "EProjectFile", "EProjectFile\EProjectFile.csproj", "{702755B9-2203-4D4A-A208-4AA1A6AD328B}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {702755B9-2203-4D4A-A208-4AA1A6AD328B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {702755B9-2203-4D4A-A208-4AA1A6AD328B}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {702755B9-2203-4D4A-A208-4AA1A6AD328B}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {702755B9-2203-4D4A-A208-4AA1A6AD328B}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {780DC048-A079-4BFD-B965-6DCC242083CD}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/EProjectFile/ClassInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using System;
3 | using System.IO;
4 | using System.Text;
5 | using System.Linq;
6 | using QIQI.EProjectFile.Sections;
7 | using QIQI.EProjectFile.Internal;
8 | using System.Collections.Generic;
9 |
10 | namespace QIQI.EProjectFile
11 | {
12 | public class ClassInfo : IHasId, IHasMemoryAddress, IToTextCodeAble
13 | {
14 | public int Id { get; }
15 |
16 | public ClassInfo(int id)
17 | {
18 | this.Id = id;
19 | }
20 |
21 | public int MemoryAddress { get; set; }
22 | ///
23 | /// 窗口程序集 中指定关联窗口的
24 | ///
25 | ///
26 | public int Form { get; set; }
27 | public int BaseClass { get; set; }
28 | public string Name { get; set; }
29 | public string Comment { get; set; }
30 | public List Methods { get; set; }
31 | public List Variables { get; set; }
32 |
33 | public static List ReadClasses(BinaryReader r, Encoding encoding)
34 | {
35 | return r.ReadBlocksWithIdAndMemoryAddress((reader, id, memoryAddress) => new ClassInfo(id)
36 | {
37 | MemoryAddress = memoryAddress,
38 | Form = reader.ReadInt32(),
39 | BaseClass = reader.ReadInt32(),
40 | Name = reader.ReadStringWithLengthPrefix(encoding),
41 | Comment = reader.ReadStringWithLengthPrefix(encoding),
42 | Methods = reader.ReadInt32sListWithFixedLength(reader.ReadInt32() / 4),
43 | Variables = AbstractVariableInfo.ReadVariables(reader, encoding, x => new ClassVariableInfo(x))
44 | });
45 | }
46 | public static void WriteClasses(BinaryWriter w, Encoding encoding, List classes)
47 | {
48 | w.WriteBlocksWithIdAndMemoryAddress(classes, (writer, elem) =>
49 | {
50 | writer.Write(elem.Form);
51 | writer.Write(elem.BaseClass);
52 | writer.WriteStringWithLengthPrefix(encoding, elem.Name);
53 | writer.WriteStringWithLengthPrefix(encoding, elem.Comment);
54 | if (elem.Methods == null)
55 | {
56 | writer.Write(0);
57 | }
58 | else
59 | {
60 | writer.Write(elem.Methods.Count * 4);
61 | foreach (var x in elem.Methods) writer.Write(x);
62 | }
63 | AbstractVariableInfo.WriteVariables(writer, encoding, elem.Variables);
64 | });
65 | }
66 | public override string ToString()
67 | {
68 | return JsonSerializer.Serialize(this, JsonUtils.Options);
69 | }
70 | ///
71 | /// 到文本代码(结尾无换行)
72 | ///
73 | /// 命名映射器
74 | /// 输出目标
75 | /// 起始缩进
76 | /// 若为null,不写出下属方法
77 | /// 是否输出子程序代码
78 | public void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent, CodeSection codeSection, bool writeCode = true)
79 | {
80 | TextCodeUtils.WriteDefinitionCode(writer, indent, "程序集", nameMap.GetUserDefinedName(Id), BaseClass == 0 || BaseClass == -1 ? "" : nameMap.GetUserDefinedName(BaseClass), "", Comment);
81 | writer.WriteLine();
82 | TextCodeUtils.JoinAndWriteCode(Variables, Environment.NewLine, nameMap, writer, indent);
83 | if (codeSection != null)
84 | {
85 | writer.WriteLine();
86 | writer.WriteLine();
87 | var methodId = Methods.ToDictionary(x => x);
88 | TextCodeUtils.JoinAndWriteCode(codeSection.Methods.Where(x => methodId.ContainsKey(x.Id)), Environment.NewLine + Environment.NewLine, nameMap, writer, indent, writeCode);
89 | }
90 | }
91 | public void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent)
92 | {
93 | ToTextCode(nameMap, writer, indent, null);
94 | }
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/EProjectFile/ClassPublicityInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Text;
5 | using System.Text.Json;
6 |
7 | namespace QIQI.EProjectFile
8 | {
9 | public class ClassPublicityInfo
10 | {
11 | public int Class { get; set; }
12 | public int Flags { get; set; }
13 | public bool Public { get => (Flags & 0x1) != 0; set => Flags = (Flags & ~0x1) | (value ? 0x1 : 0); }
14 | public bool Hidden { get => (Flags & 0x2) != 0; set => Flags = (Flags & ~0x2) | (value ? 0x2 : 0); }
15 |
16 | public override string ToString()
17 | {
18 | return JsonSerializer.Serialize(this, JsonUtils.Options);
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/EProjectFile/CodeFolderInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System.IO;
3 | using System.Text;
4 | using System.Text.Json;
5 |
6 | namespace QIQI.EProjectFile
7 | {
8 | public class CodeFolderInfo
9 | {
10 | public bool Expand { get; set; }
11 | public int Key { get; }
12 | public int ParentKey { get; set; }
13 | public string Name { get; set; }
14 | public int[] Children { get; set; }
15 | public CodeFolderInfo(int key)
16 | {
17 | this.Key = key;
18 | }
19 |
20 | public override string ToString()
21 | {
22 | return JsonSerializer.Serialize(this, JsonUtils.Options);
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/EProjectFile/CompilationSchemeInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile
6 | {
7 | public class CompilationSchemeInfo
8 | {
9 | public string Name { get; set; }
10 | public string Features { get; set; }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/EProjectFile/Context/BlockByteifierContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace QIQI.EProjectFile.Context
7 | {
8 | public struct BlockByteifierContext
9 | {
10 | public BlockByteifierContext(Encoding encoding, bool cryptEC)
11 | {
12 | this.Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
13 | this.CryptEC = cryptEC;
14 | }
15 |
16 | public Encoding Encoding;
17 | public bool CryptEC;
18 |
19 | public byte[] Collect(Action writeTo)
20 | {
21 | byte[] data;
22 | using (var writer = new BinaryWriter(new MemoryStream(), Encoding))
23 | {
24 | writeTo(writer);
25 | writer.Flush();
26 | data = ((MemoryStream)writer.BaseStream).ToArray();
27 | }
28 | return data;
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/EProjectFile/Context/BlockParserContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 |
6 | namespace QIQI.EProjectFile.Context
7 | {
8 | public struct BlockParserContext
9 | {
10 | public BlockParserContext(byte[] data, Encoding encoding, bool cryptEC)
11 | {
12 | Data = data ?? throw new ArgumentNullException(nameof(data));
13 | Encoding = encoding ?? throw new ArgumentNullException(nameof(encoding));
14 | CryptEC = cryptEC;
15 | }
16 |
17 | private readonly byte[] Data;
18 | public int DataLength => Data.Length;
19 | public readonly Encoding Encoding;
20 | public readonly bool CryptEC;
21 |
22 | public TResult Consume(Func consumer)
23 | {
24 | using var reader = new BinaryReader(new MemoryStream(Data, false));
25 | return consumer(reader);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/EProjectFile/DllDeclareInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using QIQI.EProjectFile.Internal;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Text;
7 |
8 | namespace QIQI.EProjectFile
9 | {
10 | public class DllDeclareInfo : IHasId, IHasMemoryAddress, IToTextCodeAble
11 | {
12 | public int Id { get; }
13 |
14 | public DllDeclareInfo(int id)
15 | {
16 | this.Id = id;
17 | }
18 |
19 | public int MemoryAddress { get; set; }
20 | public int Flags { get; set; }
21 | public bool Public { get => (Flags & 0x2) != 0; set => Flags = (Flags & ~0x2) | (value ? 0x2 : 0); }
22 | public bool Hidden { get => (Flags & 0x4) != 0; set => Flags = (Flags & ~0x4) | (value ? 0x4 : 0); }
23 | public int ReturnDataType { get; set; }
24 | public string Name { get; set; }
25 | public string Comment { get; set; }
26 | public string EntryPoint { get; set; }
27 | public string LibraryName { get; set; }
28 | public List Parameters { get; set; }
29 | public static List ReadDllDeclares(BinaryReader r, Encoding encoding)
30 | {
31 | return r.ReadBlocksWithIdAndMemoryAddress((reader, id, memoryAddress) => new DllDeclareInfo(id)
32 | {
33 | MemoryAddress = memoryAddress,
34 | Flags = reader.ReadInt32(),
35 | ReturnDataType = reader.ReadInt32(),
36 | Name = reader.ReadStringWithLengthPrefix(encoding),
37 | Comment = reader.ReadStringWithLengthPrefix(encoding),
38 | LibraryName = reader.ReadStringWithLengthPrefix(encoding),
39 | EntryPoint = reader.ReadStringWithLengthPrefix(encoding),
40 | Parameters = AbstractVariableInfo.ReadVariables(reader, encoding, x => new DllParameterInfo(x))
41 | });
42 | }
43 | public static void WriteDllDeclares(BinaryWriter w, Encoding encoding, List dllDeclares)
44 | {
45 | w.WriteBlocksWithIdAndMemoryAddress(dllDeclares, (writer, elem) =>
46 | {
47 | writer.Write(elem.Flags);
48 | writer.Write(elem.ReturnDataType);
49 | writer.WriteStringWithLengthPrefix(encoding, elem.Name);
50 | writer.WriteStringWithLengthPrefix(encoding, elem.Comment);
51 | writer.WriteStringWithLengthPrefix(encoding, elem.LibraryName);
52 | writer.WriteStringWithLengthPrefix(encoding, elem.EntryPoint);
53 | AbstractVariableInfo.WriteVariables(writer, encoding, elem.Parameters);
54 | });
55 | }
56 | public void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent)
57 | {
58 | TextCodeUtils.WriteDefinitionCode(writer, indent, "DLL命令", nameMap.GetUserDefinedName(Id), nameMap.GetDataTypeName(ReturnDataType), LibraryName, EntryPoint, Public ? "公开" : "", Comment);
59 | writer.WriteLine();
60 | TextCodeUtils.JoinAndWriteCode(Parameters, Environment.NewLine, nameMap, writer, indent + 1);
61 | }
62 | public override string ToString()
63 | {
64 | return JsonSerializer.Serialize(this, JsonUtils.Options);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/EProjectFile/ECDependencyInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.ComponentModel;
5 | using System.Text;
6 | using System.Text.Json;
7 | using System.Text.Json.Serialization;
8 |
9 | namespace QIQI.EProjectFile
10 | {
11 | public class ECDependencyInfo
12 | {
13 | public struct PackedIds
14 | {
15 | [JsonInclude]
16 | public int Start;
17 | [JsonInclude]
18 | public int Count;
19 |
20 | public override string ToString()
21 | {
22 | return JsonSerializer.Serialize(this, JsonUtils.Options);
23 | }
24 | }
25 |
26 | [DefaultValue(2)]
27 | public int InfoVersion { get; set; } = 2;
28 | public int FileSize { get; set; }
29 | public DateTime FileLastModifiedDate { get; set; } = DateTime.FromFileTime(0);
30 | public bool ReExport { get; set; }
31 | public string Name { get; set; }
32 | public string Path { get; set; }
33 | public List DefinedIds { get; set; }
34 |
35 | public override string ToString()
36 | {
37 | return JsonSerializer.Serialize(this, JsonUtils.Options);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/EProjectFile/EProjectFile.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | netstandard2.0
6 | true
7 | true
8 | true
9 | snupkg
10 | Epl Project Editor
11 | Epl Project Editor
12 | OpenEpl
13 | A free and unencumbered software released into the public domain (https://unlicense.org/)
14 | false
15 | true
16 | QIQI.EProjectFile
17 | EPL
18 | OpenEpl
19 | https://github.com/OpenEpl/EProjectFile
20 | QIQI.EProjectFile
21 | 1.9.4
22 | false
23 | Unlicense
24 | True
25 | 1591;1701;1702
26 | docs/README.md
27 | 8.0
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | all
37 | runtime; build; native; contentfiles; analyzers
38 |
39 |
40 | build; analyzers
41 |
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/EProjectFile/EditorTabInfo/ClassEditorTabInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Context;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace QIQI.EProjectFile.EditorTabInfo
8 | {
9 | public class ClassEditorTabInfo : IEditorTabInfo
10 | {
11 | private class KeyImpl : IEditorTabInfoKey
12 | {
13 | public byte TypeId => 1;
14 |
15 | public ClassEditorTabInfo Parse(BlockParserContext context)
16 | {
17 | return context.Consume(reader =>
18 | {
19 | if (reader.ReadByte() != TypeId)
20 | {
21 | throw new Exception($"Mismatched type for {nameof(ClassEditorTabInfo)}");
22 | }
23 | var that = new ClassEditorTabInfo()
24 | {
25 | ClassId = reader.ReadInt32(),
26 | ElemId = reader.ReadInt16(),
27 | Offset = reader.ReadInt32() & 0x7FFFFFFF,
28 | ColumnInTable = reader.ReadByte(),
29 | SelectionStart = reader.ReadInt32(),
30 | SelectionCurrent = reader.ReadInt32(),
31 | SelectionEndpoints = new List()
32 | };
33 | while (reader.BaseStream.Position < reader.BaseStream.Length)
34 | {
35 | var elemId = reader.ReadInt16();
36 | var offset = reader.ReadInt32();
37 | that.SelectionEndpoints.Add(new ClassEditorEndpoint()
38 | {
39 | ElemId = elemId,
40 | Offset = offset
41 | });
42 | }
43 | return that;
44 | });
45 | }
46 | }
47 | public static readonly IEditorTabInfoKey Key = new KeyImpl();
48 | public byte TypeId => Key.TypeId;
49 |
50 | ///
51 | /// 对于表格元素为行索引,对于代码元素为所在行的代码数据位置(字节)
52 | ///
53 | ///
54 | public int Offset { get; set; }
55 |
56 | ///
57 | /// 对于表格元素为列索引,对于代码元素为0
58 | ///
59 | public byte ColumnInTable { get; set; }
60 |
61 | ///
62 | /// 使选择方向不同,可能大于 也可能小于,若两者相等表示无行内选区(可能有多行选择存在)
63 | ///
64 | /// 多行选择时此值与 相等,选择点以 为准
65 | public int SelectionStart { get; set; }
66 |
67 | ///
68 | /// 当前光标位置
69 | ///
70 | /// 多行选择时此值与 相等,选择点以 为准
71 | public int SelectionCurrent { get; set; }
72 |
73 | public int ClassId { get; set; }
74 |
75 | ///
76 | /// -N 表示第 N 个表格,自然数表示对应的子程序索引(从0开始)
77 | ///
78 | ///
79 | public short ElemId { get; set; }
80 |
81 | ///
82 | /// 标记一个选择点,以开始、结束交叉出现,可以存在多个不连续的选择区
83 | ///
84 | public List SelectionEndpoints { get; set; }
85 |
86 | public void WriteTo(BinaryWriter writer, Encoding encoding)
87 | {
88 | writer.Write(20 + (SelectionEndpoints?.Count ?? 0) * 6);
89 | writer.Write(TypeId);
90 | writer.Write(ClassId);
91 | writer.Write(ElemId);
92 | writer.Write(Offset | unchecked((int)0x80000000));
93 | writer.Write(ColumnInTable);
94 | writer.Write(SelectionStart);
95 | writer.Write(SelectionCurrent);
96 | if (SelectionEndpoints != null)
97 | {
98 | foreach (var item in SelectionEndpoints)
99 | {
100 | writer.Write(item.ElemId);
101 | writer.Write(item.Offset);
102 | }
103 | }
104 | }
105 | }
106 | public struct ClassEditorEndpoint
107 | {
108 | ///
109 | /// -N 表示第 N 个表格,自然数表示对应的子程序索引(从0开始)
110 | ///
111 | ///
112 | public short ElemId { get; set; }
113 |
114 | ///
115 | /// 对于表格元素为行索引,对于代码元素为所在行的代码数据位置(字节)
116 | ///
117 | ///
118 | public int Offset { get; set; }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/EProjectFile/EditorTabInfo/FormDesignerTabInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Context;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace QIQI.EProjectFile.EditorTabInfo
8 | {
9 | public class FormDesignerTabInfo : IEditorTabInfo
10 | {
11 | private class KeyImpl : IEditorTabInfoKey
12 | {
13 | public byte TypeId => 5;
14 |
15 | public FormDesignerTabInfo Parse(BlockParserContext context)
16 | {
17 | return context.Consume(reader =>
18 | {
19 | if (reader.ReadByte() != TypeId)
20 | {
21 | throw new Exception($"Mismatched type for {nameof(FormDesignerTabInfo)}");
22 | }
23 | var that = new FormDesignerTabInfo()
24 | {
25 | FormId = reader.ReadInt32(),
26 | UnitIds = new List()
27 | };
28 |
29 | while (reader.BaseStream.Position < reader.BaseStream.Length)
30 | {
31 | var unitId = reader.ReadInt32();
32 | that.UnitIds.Add(unitId);
33 | }
34 | return that;
35 | });
36 | }
37 | }
38 | public static readonly IEditorTabInfoKey Key = new KeyImpl();
39 | public byte TypeId => Key.TypeId;
40 | public int FormId { get; set; }
41 | public List UnitIds { get; set; }
42 |
43 | public void WriteTo(BinaryWriter writer, Encoding encoding)
44 | {
45 | writer.Write(5 + (UnitIds?.Count ?? 0) * 4);
46 | writer.Write(TypeId);
47 | writer.Write(FormId);
48 | if (UnitIds != null)
49 | {
50 | foreach (var unitId in UnitIds)
51 | {
52 | writer.Write(unitId);
53 | }
54 | }
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/EProjectFile/EditorTabInfo/GeneralEditorTabInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System.IO;
3 | using System.Text;
4 | using System.Text.Json.Serialization;
5 |
6 | namespace QIQI.EProjectFile.EditorTabInfo
7 | {
8 | public class GeneralEditorTabInfo : IEditorTabInfo
9 | {
10 | [JsonConstructor]
11 | public GeneralEditorTabInfo(byte type, byte[] data)
12 | {
13 | TypeId = type;
14 | Data = data;
15 | }
16 |
17 | public byte TypeId { get; }
18 |
19 | [JsonConverter(typeof(ByteArrayHexConverter))]
20 | public byte[] Data { get; set; }
21 |
22 | public void WriteTo(BinaryWriter writer, Encoding encoding)
23 | {
24 | if (Data is null)
25 | {
26 | writer.Write(1);
27 | writer.Write(TypeId);
28 | return;
29 | }
30 | writer.Write(1 + Data.Length);
31 | writer.Write(TypeId);
32 | writer.Write(Data);
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/EProjectFile/EditorTabInfo/IEditorTabInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Context;
2 | using QIQI.EProjectFile.Internal;
3 | using System.IO;
4 | using System.Text;
5 | using System.Text.Json.Serialization;
6 |
7 | namespace QIQI.EProjectFile.EditorTabInfo
8 | {
9 | public interface IEditorTabInfoKey where TEditorTabInfo : IEditorTabInfo
10 | {
11 | public byte TypeId { get; }
12 | TEditorTabInfo Parse(BlockParserContext context);
13 | }
14 | [JsonConverter(typeof(EditorTabInfoJsonConverter))]
15 | public interface IEditorTabInfo
16 | {
17 | public byte TypeId { get; }
18 | public void WriteTo(BinaryWriter writer, Encoding encoding);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/EProjectFile/EditorTabInfo/PredefinedEditorTabInfos.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Linq;
3 |
4 | namespace QIQI.EProjectFile.EditorTabInfo
5 | {
6 | public class PredefinedEditorTabInfos
7 | {
8 | public static Dictionary> Keys { get; } = new IEditorTabInfoKey[]{
9 | ClassEditorTabInfo.Key,
10 | StructEditorTabInfo.Key,
11 | GlobalVariableEditorTabInfo.Key,
12 | DllDeclareEditorTabInfo.Key,
13 | FormDesignerTabInfo.Key,
14 | ConstantEditorTabInfo.Key,
15 | ImageResourceEditorTabInfo.Key,
16 | SoundResourceEditorTabInfo.Key,
17 | }.ToDictionary(x => x.TypeId);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/EProjectFile/EditorTabInfo/PureTableEditorTabInfo.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Context;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace QIQI.EProjectFile.EditorTabInfo
8 | {
9 | public abstract class PureTableEditorTabInfo : IEditorTabInfo
10 | {
11 | protected class KeyImplForPureTable : IEditorTabInfoKey where TEditorTabInfo : PureTableEditorTabInfo, new()
12 | {
13 | public KeyImplForPureTable(byte type)
14 | {
15 | TypeId = type;
16 | }
17 |
18 | public byte TypeId { get; }
19 |
20 | public TEditorTabInfo Parse(BlockParserContext context)
21 | {
22 | return context.Consume(reader =>
23 | {
24 | if (reader.ReadByte() != TypeId)
25 | {
26 | throw new Exception($"Mismatched type for {typeof(TEditorTabInfo).Name}");
27 | }
28 | var that = new TEditorTabInfo()
29 | {
30 | Offset = reader.ReadInt32() & 0x7FFFFFFF,
31 | ColumnInTable = reader.ReadByte(),
32 | SelectionStart = reader.ReadInt32(),
33 | SelectionCurrent = reader.ReadInt32(),
34 | SelectionEndpoints = new List()
35 | };
36 | while (reader.BaseStream.Position < reader.BaseStream.Length)
37 | {
38 | that.SelectionEndpoints.Add(reader.ReadInt32());
39 | }
40 | return that;
41 | });
42 | }
43 | }
44 |
45 | public abstract byte TypeId { get; }
46 |
47 | ///
48 | /// 对于表格元素为行索引
49 | ///
50 | public int Offset { get; set; }
51 |
52 | ///
53 | /// 对于表格元素为列索引
54 | ///
55 | public byte ColumnInTable { get; set; }
56 |
57 | ///
58 | /// 使选择方向不同,可能大于 也可能小于,若两者相等表示无行内选区(可能有多行选择存在)
59 | ///
60 | /// 多行选择时此值与 相等,选择点以 为准
61 | public int SelectionStart { get; set; }
62 |
63 | ///
64 | /// 当前光标位置
65 | ///
66 | /// 多行选择时此值与 相等,选择点以 为准
67 | public int SelectionCurrent { get; set; }
68 |
69 | ///
70 | /// 标记一个选择点,以开始、结束交叉出现,可以存在多个不连续的选择区
71 | ///
72 | ///
73 | public List SelectionEndpoints { get; set; }
74 |
75 | public void WriteTo(BinaryWriter writer, Encoding encoding)
76 | {
77 | writer.Write(14 + (SelectionEndpoints?.Count ?? 0) * 4);
78 | writer.Write(TypeId);
79 | writer.Write(Offset | unchecked((int)0x80000000));
80 | writer.Write(ColumnInTable);
81 | writer.Write(SelectionStart);
82 | writer.Write(SelectionCurrent);
83 | if (SelectionEndpoints != null)
84 | {
85 | foreach (var item in SelectionEndpoints)
86 | {
87 | writer.Write(item);
88 | }
89 | }
90 | }
91 | }
92 | public class StructEditorTabInfo : PureTableEditorTabInfo
93 | {
94 | public static readonly IEditorTabInfoKey Key = new KeyImplForPureTable(2);
95 | public override byte TypeId => Key.TypeId;
96 | }
97 | public class GlobalVariableEditorTabInfo : PureTableEditorTabInfo
98 | {
99 | public static readonly IEditorTabInfoKey Key = new KeyImplForPureTable(3);
100 | public override byte TypeId => Key.TypeId;
101 | }
102 | public class DllDeclareEditorTabInfo : PureTableEditorTabInfo
103 | {
104 | public static readonly IEditorTabInfoKey Key = new KeyImplForPureTable(4);
105 | public override byte TypeId => Key.TypeId;
106 | }
107 | public class ConstantEditorTabInfo : PureTableEditorTabInfo
108 | {
109 | public static readonly IEditorTabInfoKey Key = new KeyImplForPureTable(6);
110 | public override byte TypeId => Key.TypeId;
111 | }
112 | public class ImageResourceEditorTabInfo : PureTableEditorTabInfo
113 | {
114 | public static readonly IEditorTabInfoKey Key = new KeyImplForPureTable(7);
115 | public override byte TypeId => Key.TypeId;
116 | }
117 | public class SoundResourceEditorTabInfo : PureTableEditorTabInfo
118 | {
119 | public static readonly IEditorTabInfoKey Key = new KeyImplForPureTable(8);
120 | public override byte TypeId => Key.TypeId;
121 | }
122 | }
123 |
--------------------------------------------------------------------------------
/EProjectFile/Encryption/EncryptionOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Encryption
6 | {
7 | public abstract class EplEncryptionOptions
8 | {
9 | public sealed class EStd : EplEncryptionOptions, IEquatable
10 | {
11 | public EplSecret.EStd Password;
12 |
13 | public override bool Equals(object obj)
14 | {
15 | return Equals(obj as EStd);
16 | }
17 |
18 | public bool Equals(EStd other)
19 | {
20 | return !(other is null) &&
21 | EqualityComparer.Default.Equals(Password, other.Password);
22 | }
23 |
24 | public override int GetHashCode()
25 | {
26 | return -1081153288 + EqualityComparer.Default.GetHashCode(Password);
27 | }
28 |
29 | public static bool operator ==(EStd left, EStd right)
30 | {
31 | return EqualityComparer.Default.Equals(left, right);
32 | }
33 |
34 | public static bool operator !=(EStd left, EStd right)
35 | {
36 | return !(left == right);
37 | }
38 | }
39 | public sealed class EC : EplEncryptionOptions, IEquatable
40 | {
41 | public EplSecret.EC Password;
42 | public string PasswordHint;
43 |
44 | public override bool Equals(object obj)
45 | {
46 | return Equals(obj as EC);
47 | }
48 |
49 | public bool Equals(EC other)
50 | {
51 | return !(other is null) &&
52 | EqualityComparer.Default.Equals(Password, other.Password) &&
53 | PasswordHint == other.PasswordHint;
54 | }
55 |
56 | public override int GetHashCode()
57 | {
58 | int hashCode = 1281113049;
59 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(Password);
60 | hashCode = hashCode * -1521134295 + EqualityComparer.Default.GetHashCode(PasswordHint);
61 | return hashCode;
62 | }
63 |
64 | public static bool operator ==(EC left, EC right)
65 | {
66 | return EqualityComparer.Default.Equals(left, right);
67 | }
68 |
69 | public static bool operator !=(EC left, EC right)
70 | {
71 | return !(left == right);
72 | }
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/EProjectFile/Encryption/EplSecret.EStd.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Collections.Immutable;
5 | using System.Runtime.CompilerServices;
6 | using System.Security.Cryptography;
7 | using System.Text;
8 |
9 | namespace QIQI.EProjectFile.Encryption
10 | {
11 | public abstract partial class EplSecret
12 | {
13 | public sealed class EStd: EplSecret, IEquatable
14 | {
15 | private class FactoryImpl : IEplSecretFactory
16 | {
17 | public EStd Create(byte[] key)
18 | {
19 | var status = new RC4Crypto(key, 256).UnsafeGetStatus();
20 | return new EStd(CalculateSecretID(key), Unsafe.As>(ref status));
21 | }
22 |
23 | public EStd Create(string key)
24 | {
25 | return Create(Encoding.GetEncoding("gbk").GetBytes(key));
26 | }
27 |
28 | private static ImmutableArray CalculateSecretID(byte[] key)
29 | {
30 | byte[] hash = MD5.Create().ComputeHash(key);
31 | StringBuilder stringBuilder = new StringBuilder();
32 | for (int i = hash.Length - 1; i >= 0; i--)
33 | {
34 | stringBuilder.Append(hash[i].ToString("x2"));
35 | }
36 |
37 | var bytes = Encoding.ASCII.GetBytes(stringBuilder.ToString());
38 | return Unsafe.As>(ref bytes);
39 | }
40 | }
41 |
42 | public static readonly IEplSecretFactory Factory = new FactoryImpl();
43 |
44 | public override ImmutableArray SecretId { get; }
45 | public override ImmutableArray IV { get; }
46 |
47 | public EStd(ImmutableArray secretId, ImmutableArray iv)
48 | {
49 | SecretId = secretId;
50 | IV = iv;
51 | }
52 |
53 | public override bool Equals(object obj)
54 | {
55 | return Equals(obj as EStd);
56 | }
57 |
58 | public bool Equals(EStd other)
59 | {
60 | return !(other is null) &&
61 | SecretId.Equals(other.SecretId) &&
62 | IV.Equals(other.IV);
63 | }
64 |
65 | public override int GetHashCode()
66 | {
67 | int hashCode = -1032396774;
68 | hashCode = hashCode * -1521134295 + SecretId.GetHashCode();
69 | hashCode = hashCode * -1521134295 + IV.GetHashCode();
70 | return hashCode;
71 | }
72 |
73 | public static bool operator ==(EStd left, EStd right)
74 | {
75 | return EqualityComparer.Default.Equals(left, right);
76 | }
77 |
78 | public static bool operator !=(EStd left, EStd right)
79 | {
80 | return !(left == right);
81 | }
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/EProjectFile/Encryption/EplSecret.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Immutable;
2 |
3 | namespace QIQI.EProjectFile.Encryption
4 | {
5 | public abstract partial class EplSecret
6 | {
7 | public abstract ImmutableArray SecretId { get; }
8 | public abstract ImmutableArray IV { get; }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/EProjectFile/Encryption/IEplSecretFactory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Encryption
6 | {
7 | public interface IEplSecretFactory where T : EplSecret
8 | {
9 | public T Create(byte[] key);
10 | public T Create(string key);
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/EProjectFile/EplDocument.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Context;
2 | using QIQI.EProjectFile.Encryption;
3 | using QIQI.EProjectFile.Sections;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Text;
9 |
10 | namespace QIQI.EProjectFile
11 | {
12 | public class EplDocument
13 | {
14 | public List Sections { get; } = new List();
15 | public Encoding DetermineEncoding()
16 | {
17 | return GetOrNull(ESystemInfoSection.Key)?.DetermineEncoding() ?? Encoding.GetEncoding("gbk");
18 | }
19 |
20 | public TSection GetOrNull(ISectionKey key) where TSection : ISection
21 | {
22 | if (Sections.FirstOrDefault(x => x.SectionKey == key.SectionKey) is TSection it)
23 | {
24 | return it;
25 | }
26 | else
27 | {
28 | return default;
29 | }
30 | }
31 |
32 | public TSection Get(ISectionKey key) where TSection : ISection
33 | {
34 | return (TSection)Sections.First(x => x.SectionKey == key.SectionKey);
35 | }
36 |
37 | public void Load(Stream stream, ProjectFileReader.OnInputPassword inputPassword = null)
38 | {
39 | var encoding = Encoding.GetEncoding("gbk");
40 | Sections.Clear();
41 | using (var reader = new ProjectFileReader(stream, inputPassword))
42 | {
43 | while (!reader.IsFinish)
44 | {
45 | var rawSection = reader.ReadSection();
46 | ISection section;
47 | if (PredefinedSections.Keys.TryGetValue(rawSection.Key, out var sectionKey))
48 | {
49 | section = sectionKey.Parse(new BlockParserContext(rawSection.Data, encoding, reader.CryptEC));
50 | }
51 | else
52 | {
53 | section = new GeneralSection(rawSection);
54 | }
55 | if (section is ESystemInfoSection systemInfo)
56 | {
57 | encoding = systemInfo.DetermineEncoding();
58 | }
59 | if (!(section is EndOfFileSection))
60 | {
61 | Sections.Add(section);
62 | }
63 | }
64 | }
65 | }
66 | public void Save(Stream stream) => Save(stream, null);
67 | public void Save(Stream stream, EplEncryptionOptions encryptionOptions)
68 | {
69 | var encoding = Encoding.GetEncoding("gbk");
70 | using (var writer = new ProjectFileWriter(stream, encryptionOptions))
71 | {
72 | var context = new BlockByteifierContext(encoding, writer.CryptEC);
73 | foreach (var section in Sections)
74 | {
75 | if (section is ESystemInfoSection systemInfo)
76 | {
77 | encoding = systemInfo.DetermineEncoding();
78 | }
79 | writer.WriteSection(new RawSectionInfo(section.SectionKey, section.SectionName, section.IsOptional, section.ToBytes(context)));
80 | }
81 | {
82 | var section = EndOfFileSection.Instance;
83 | writer.WriteSection(new RawSectionInfo(section.SectionKey, section.SectionName, section.IsOptional, section.ToBytes(context)));
84 | }
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/EProjectFile/EplSystemId.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace QIQI.EProjectFile
4 | {
5 | public class EplSystemId
6 | {
7 | ///
8 | /// Not a Variable
9 | ///
10 | ///
11 | ///
12 | internal const int Id_NaV = 0x0500FFFE;
13 |
14 | public const int Type_Method = 0x04000000;
15 | public const int Type_Global = 0x05000000;
16 | ///
17 | /// 普通程序集(非窗口程序集、类模块)
18 | ///
19 | public const int Type_StaticClass = 0x09000000;
20 | public const int Type_Dll = 0x0A000000;
21 | ///
22 | /// 程序集变量 或 类模块成员
23 | ///
24 | public const int Type_ClassMember = 0x15000000;
25 | public const int Type_Constant = 0x18000000;
26 | ///
27 | /// 窗口程序集
28 | ///
29 | public const int Type_FormClass = 0x19000000;
30 | ///
31 | /// 局部变量 或 子程序参数(非DLL命令)
32 | ///
33 | public const int Type_Local = 0x25000000;
34 | public const int Type_ImageResource = 0x28000000;
35 | public const int Type_StructMember = 0x35000000;
36 | public const int Type_SoundResource = 0x38000000;
37 | public const int Type_Struct = 0x41000000;
38 | public const int Type_DllParameter = 0x45000000;
39 | public const int Type_Class = 0x49000000;
40 | public const int Type_Form = 0x52000000;
41 | public const int Type_FormSelf = 0x06000000;
42 | public const int Type_FormControl = 0x16000000;
43 | public const int Type_FormMenu = 0x26000000;
44 |
45 | public const int Mask_Num = 0x00FFFFFF;
46 | public const int Mask_Type = unchecked((int)0xFF000000);
47 |
48 | ///
49 | /// 只用于用户定义Id
50 | ///
51 | /// 欲获取类型的Id
52 | /// 指定Id所属类型,参考EplSystemId.Type_*
53 | public static int GetType(int id) => id & Mask_Type;
54 |
55 | ///
56 | /// 无类型(如 某子程序无返回值)
57 | ///
58 | public const int DataType_Void = unchecked((int)0x00000000);
59 | ///
60 | /// 通用型
61 | ///
62 | public const int DataType_Any = unchecked((int)0x80000000);
63 | public const int DataType_Byte = unchecked((int)0x80000101);
64 | public const int DataType_Short = unchecked((int)0x80000201);
65 | public const int DataType_Int = unchecked((int)0x80000301);
66 | public const int DataType_Long = unchecked((int)0x80000401);
67 | public const int DataType_Float = unchecked((int)0x80000501);
68 | public const int DataType_Double = unchecked((int)0x80000601);
69 | public const int DataType_Bool = unchecked((int)0x80000002);
70 | public const int DataType_DateTime = unchecked((int)0x80000003);
71 | public const int DataType_String = unchecked((int)0x80000004);
72 | public const int DataType_Bin = unchecked((int)0x80000005);
73 | public const int DataType_MethodPtr = unchecked((int)0x80000006);
74 | ///
75 | /// 条件语句型(SDT_STATMENT),通常只用于支持库命令的参数,如 核心库 的 查找 命令
76 | ///
77 | public const int DataType_Lambda = unchecked((int)0x80000008);
78 |
79 | public static int MakeSureIsSpecifiedType(int id, params int[] type) => Array.IndexOf(type, GetType(id)) >= 0 ? id : throw new Exception("不是指定类型的Id");
80 |
81 | public static bool IsLibDataType(int id) => (id & 0xFF000000) == 0 && id != DataType_Void;
82 |
83 | ///
84 | /// 合成库类型Id
85 | ///
86 | /// 索引从0开始(CStyle)
87 | /// 索引从0开始(CStyle)
88 | ///
89 | public static int MakeLibDataTypeId(short lib, short type) => ((int)(lib + 1) << 16) | (int)(type + 1);
90 | ///
91 | /// 分解库类型Id
92 | ///
93 | ///
94 | /// 索引从0开始(CStyle)
95 | /// 索引从0开始(CStyle)
96 | public static void DecomposeLibDataTypeId(int id, out short lib, out short type)
97 | {
98 | if (!IsLibDataType(id)) throw new Exception("DecomposeLibDataTypeId只能处理库类型Id");
99 | unchecked
100 | {
101 | lib = (short)(id >> 16);
102 | lib--;
103 | type = (short)id;
104 | type--;
105 | }
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/AccessArrayExpression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Linq;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | ///
8 | /// 访问数组成员表达式,多维数组通过多个AccessArrayExpression嵌套表示
9 | ///
10 | public class AccessArrayExpression : In0x38Expression
11 | {
12 | public readonly Expression Target;
13 | public readonly Expression Index;
14 | public AccessArrayExpression(Expression target, Expression index)
15 | {
16 | this.Target = target;
17 | this.Index = index;
18 | }
19 |
20 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
21 | {
22 | Target.ToTextCode(nameMap, writer, indent);
23 | writer.Write("[");
24 | Index.ToTextCode(nameMap, writer, indent);
25 | writer.Write("]");
26 | }
27 |
28 | internal override void WriteTo(MethodCodeDataWriterArgs a, bool need0x1DAnd0x37)
29 | {
30 | if (need0x1DAnd0x37)
31 | {
32 | a.VariableReference.Write(a.Offest);
33 | a.ExpressionData.Write((byte)0x1D);
34 | a.ExpressionData.Write((byte)0x38);
35 | }
36 | if (Target is In0x38Expression)
37 | {
38 | ((In0x38Expression)Target).WriteTo(a, false);
39 | }
40 | else
41 | {
42 | a.ExpressionData.Write(EplSystemId.Id_NaV);
43 | a.ExpressionData.Write((byte)0x3A);
44 | Target.WriteTo(a);
45 | }
46 | a.ExpressionData.Write((byte)0x3A);
47 | if (Index is NumberLiteral)
48 | {
49 | a.ExpressionData.Write((byte)0x3B);
50 | a.ExpressionData.Write((int)((NumberLiteral)Index).Value);
51 | }
52 | else if (Index is In0x38Expression)
53 | {
54 | a.ExpressionData.Write((byte)0x38);
55 | ((In0x38Expression)Index).WriteTo(a, false);
56 | a.ExpressionData.Write((byte)0x37);
57 | }
58 | else
59 | {
60 | Index.WriteTo(a);
61 | }
62 | if (need0x1DAnd0x37) a.ExpressionData.Write((byte)0x37);
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/AccessMemberExpression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 访问对象成员表达式
8 | ///
9 | public class AccessMemberExpression : In0x38Expression
10 | {
11 | public readonly Expression Target;
12 | public readonly short LibraryId;
13 | public readonly int StructId;
14 | public readonly int MemberId;
15 | public AccessMemberExpression(Expression target, int structId, int memberId)
16 | {
17 | Target = target;
18 | LibraryId = -2;
19 | StructId = structId;
20 | MemberId = memberId;
21 | }
22 | public AccessMemberExpression(Expression target, short libraryId, int structId, int memberId)
23 | {
24 | Target = target;
25 | LibraryId = libraryId;
26 | StructId = structId;
27 | MemberId = memberId;
28 | }
29 |
30 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
31 | {
32 | if (Target is VariableExpression varExpr
33 | && EplSystemId.GetType(varExpr.Id) == EplSystemId.Type_FormSelf)
34 | {
35 | // 在窗口程序集直接访问窗口系统属性的情况
36 | // Do nothing
37 | }
38 | else
39 | {
40 | Target.ToTextCode(nameMap, writer, indent);
41 | writer.Write(".");
42 | }
43 | if (LibraryId == -2)
44 | {
45 | // 当出现 窗口名.xxx 访问模式
46 | // 既有可能为 窗口.系统属性 也有可能为 窗口.用户窗口组件名
47 | if (EplSystemId.GetType(StructId) == EplSystemId.Type_Form
48 | && (MemberId & 0xFF000000) == 0)
49 | {
50 | writer.Write(nameMap.GetLibTypeMemberName(0, 0, MemberId - 1));
51 | }
52 | else
53 | {
54 | writer.Write(nameMap.GetUserDefinedName(MemberId));
55 | }
56 | }
57 | else
58 | {
59 | writer.Write(nameMap.GetLibTypeMemberName(LibraryId, StructId, MemberId));
60 | }
61 | }
62 |
63 | internal override void WriteTo(MethodCodeDataWriterArgs a, bool need0x1DAnd0x37)
64 | {
65 | if (need0x1DAnd0x37)
66 | {
67 | a.VariableReference.Write(a.Offest);
68 | a.ExpressionData.Write((byte)0x1D);
69 | a.ExpressionData.Write((byte)0x38);
70 | }
71 | if (Target is In0x38Expression)
72 | {
73 | ((In0x38Expression)Target).WriteTo(a, false);
74 | }
75 | else
76 | {
77 | a.ExpressionData.Write(EplSystemId.Id_NaV);
78 | a.ExpressionData.Write((byte)0x3A);
79 | Target.WriteTo(a);
80 | }
81 | a.ExpressionData.Write((byte)0x39);
82 | if (LibraryId == -2)
83 | {
84 | a.ExpressionData.Write(MemberId);
85 | a.ExpressionData.Write(StructId);
86 | }
87 | else
88 | {
89 | a.ExpressionData.Write(MemberId + 1);
90 | a.ExpressionData.Write((StructId + 1) & 0xFFFF | (LibraryId + 1) << 16);
91 | }
92 | if (need0x1DAnd0x37) a.ExpressionData.Write((byte)0x37);
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/ArrayLiteralEnd.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | ///
8 | /// 解析时临时标记(数组字面量结束标识)
9 | ///
10 | internal class ArrayLiteralEnd : Expression
11 | {
12 | public static readonly ArrayLiteralEnd Instance = new ArrayLiteralEnd();
13 | private ArrayLiteralEnd()
14 | {
15 | if (Instance != null) throw new NotSupportedException();
16 | }
17 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0) => throw new NotImplementedException();
18 |
19 | internal override void WriteTo(MethodCodeDataWriterArgs a) => a.ExpressionData.Write((byte)0x20);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/ArrayLiteralExpression.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace QIQI.EProjectFile.Expressions
8 | {
9 | ///
10 | /// 数组字面量(常量集),包括各种类型数组、字节集等
11 | ///
12 | public class ArrayLiteralExpression : Expression, IList
13 | {
14 | private readonly List items = new List();
15 |
16 | public Expression this[int index] { get => items[index]; set => items[index] = value; }
17 |
18 | public int Count => items.Count;
19 |
20 | public bool IsReadOnly => ((IList)items).IsReadOnly;
21 |
22 | public void Add(Expression item)
23 | {
24 | items.Add(item);
25 | }
26 |
27 | public void Clear()
28 | {
29 | items.Clear();
30 | }
31 |
32 | public bool Contains(Expression item)
33 | {
34 | return items.Contains(item);
35 | }
36 |
37 | public void CopyTo(Expression[] array, int arrayIndex)
38 | {
39 | items.CopyTo(array, arrayIndex);
40 | }
41 |
42 | public IEnumerator GetEnumerator()
43 | {
44 | return ((IList)items).GetEnumerator();
45 | }
46 |
47 | public int IndexOf(Expression item)
48 | {
49 | return items.IndexOf(item);
50 | }
51 |
52 | public void Insert(int index, Expression item)
53 | {
54 | items.Insert(index, item);
55 | }
56 |
57 | public bool Remove(Expression item)
58 | {
59 | return items.Remove(item);
60 | }
61 |
62 | public void RemoveAt(int index)
63 | {
64 | items.RemoveAt(index);
65 | }
66 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
67 | {
68 | writer.Write("{");
69 | TextCodeUtils.JoinAndWriteCode(this, ", ", nameMap, writer, indent);
70 | writer.Write("}");
71 | }
72 | internal override void WriteTo(MethodCodeDataWriterArgs a)
73 | {
74 | a.ExpressionData.Write((byte)0x1F);
75 | items.ForEach(x => x.WriteTo(a));
76 | ArrayLiteralEnd.Instance.WriteTo(a);
77 | }
78 |
79 | IEnumerator IEnumerable.GetEnumerator()
80 | {
81 | return ((IList)items).GetEnumerator();
82 | }
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/BoolLiteral.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | ///
8 | /// 逻辑型字面量
9 | ///
10 | public class BoolLiteral : Expression
11 | {
12 | #pragma warning disable CS0612 // 类型或成员已过时
13 | public static readonly BoolLiteral True = new BoolLiteral(true);
14 | public static readonly BoolLiteral False = new BoolLiteral(false);
15 | #pragma warning restore CS0612 // 类型或成员已过时
16 | public static BoolLiteral ValueOf(bool x) => x ? True : False;
17 | public readonly bool Value;
18 | [Obsolete]
19 | public BoolLiteral(bool value)
20 | {
21 | this.Value = value;
22 | }
23 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
24 | {
25 | writer.Write(Value ? "真" : "假");
26 | }
27 | internal override void WriteTo(MethodCodeDataWriterArgs a)
28 | {
29 | a.ExpressionData.Write((byte)0x18);
30 | a.ExpressionData.Write((short)(Value ? -1 : 0));
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/ConstantExpression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 访问常量
8 | ///
9 | public class ConstantExpression : Expression
10 | {
11 | public readonly short LibraryId;
12 | public readonly int ConstantId;
13 | public ConstantExpression(short libraryId, int constantId)
14 | {
15 | this.LibraryId = libraryId;
16 | this.ConstantId = constantId;
17 | }
18 | public ConstantExpression(int constantId) : this(-2, constantId)
19 | {
20 | }
21 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
22 | {
23 | writer.Write("#");
24 | writer.Write(LibraryId == -2 ? nameMap.GetUserDefinedName(ConstantId) : nameMap.GetLibConstantName(LibraryId, ConstantId));
25 | }
26 | internal override void WriteTo(MethodCodeDataWriterArgs a)
27 | {
28 | if (LibraryId == -2)
29 | {
30 | a.ConstantReference.Write(a.Offest);
31 | a.ExpressionData.Write((byte)0x1B);
32 | a.ExpressionData.Write(ConstantId);
33 | }
34 | else
35 | {
36 | a.ExpressionData.Write((byte)0x1C);
37 | a.ExpressionData.Write((short)(LibraryId + 1));
38 | a.ExpressionData.Write((short)(ConstantId + 1));
39 | }
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/DateTimeLiteral.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | ///
8 | /// 日期时间型字面量
9 | ///
10 | public class DateTimeLiteral : Expression
11 | {
12 | public readonly DateTime Value;
13 |
14 | public DateTimeLiteral(DateTime value)
15 | {
16 | this.Value = value;
17 | }
18 |
19 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
20 | {
21 | writer.Write("[");
22 | if (Value != null)
23 | {
24 | if (Value.TimeOfDay.TotalSeconds == 0)
25 | writer.Write(Value.ToString("yyyy年MM月dd日"));
26 | else
27 | writer.Write(Value.ToString("yyyy年MM月dd日HH时mm分ss秒"));
28 | }
29 | writer.Write("]");
30 |
31 | }
32 | internal override void WriteTo(MethodCodeDataWriterArgs a)
33 | {
34 | a.ExpressionData.Write((byte)0x19);
35 | a.ExpressionData.Write(Value.ToOADate());
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/DefaultValueExpression.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | public class DefaultValueExpression : Expression
8 | {
9 | public static readonly DefaultValueExpression Instance = new DefaultValueExpression();
10 | private DefaultValueExpression()
11 | {
12 | if (Instance != null) throw new NotSupportedException();
13 | }
14 | internal override void WriteTo(MethodCodeDataWriterArgs a) => a.ExpressionData.Write((byte)0x16);
15 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
16 | {
17 | // Nothing need doing.
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/EmnuConstantExpression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 访问枚举(支持库)
8 | ///
9 | public class EmnuConstantExpression : Expression
10 | {
11 | public readonly short LibraryId;
12 | public readonly short StructId;
13 | public readonly int MemberId;
14 | public EmnuConstantExpression(short structId, short libraryId, int memberId)
15 | {
16 | this.StructId = structId;
17 | this.LibraryId = libraryId;
18 | this.MemberId = memberId;
19 | }
20 | internal override void WriteTo(MethodCodeDataWriterArgs a)
21 | {
22 | a.ExpressionData.Write((byte)0x23);
23 | a.ExpressionData.Write((short)(StructId + 1));
24 | a.ExpressionData.Write((short)(LibraryId + 1));
25 | a.ExpressionData.Write(MemberId + 1);
26 | }
27 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
28 | {
29 | writer.Write("#");
30 | writer.Write(nameMap.GetLibTypeName(LibraryId, StructId));
31 | writer.Write(".");
32 | writer.Write(nameMap.GetLibTypeMemberName(LibraryId, StructId, MemberId));
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/Expression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 表达式 基类
8 | ///
9 | public abstract class Expression : IToTextCodeAble
10 | {
11 | internal abstract void WriteTo(MethodCodeDataWriterArgs a);
12 | public sealed override string ToString() => this.ToTextCode(IdToNameMap.Empty);
13 | public abstract void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/In0x38Expression.cs:
--------------------------------------------------------------------------------
1 | namespace QIQI.EProjectFile.Expressions
2 | {
3 | public abstract class In0x38Expression : Expression
4 | {
5 | internal abstract void WriteTo(MethodCodeDataWriterArgs a, bool need0x1DAnd0x37);
6 | internal override void WriteTo(MethodCodeDataWriterArgs a)
7 | {
8 | WriteTo(a, true);
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/MethodPtrExpression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 子程序取址
8 | ///
9 | public class MethodPtrExpression : Expression
10 | {
11 | public readonly int MethodId;
12 | public MethodPtrExpression(int methodId)
13 | {
14 | this.MethodId = methodId;
15 | }
16 |
17 | internal override void WriteTo(MethodCodeDataWriterArgs a)
18 | {
19 | a.MethodReference.Write(a.Offest);
20 | a.ExpressionData.Write((byte)0x1E);
21 | a.ExpressionData.Write(MethodId);
22 | }
23 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
24 | {
25 | writer.Write("&");
26 | writer.Write(nameMap.GetUserDefinedName(MethodId));
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/NumberLiteral.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 数值型字面量(易语言内部统一按double处理)
8 | ///
9 | public class NumberLiteral : Expression
10 | {
11 | public readonly double Value;
12 | public NumberLiteral(double value)
13 | {
14 | this.Value = value;
15 | }
16 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
17 | {
18 | writer.Write(Value);
19 | }
20 | internal override void WriteTo(MethodCodeDataWriterArgs a)
21 | {
22 | a.ExpressionData.Write((byte)0x17);
23 | a.ExpressionData.Write(Value);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/ParamListEnd.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | ///
8 | /// 解析时临时标记(参数列表结束标识)
9 | ///
10 | internal class ParamListEnd : Expression
11 | {
12 | public static readonly ParamListEnd Instance = new ParamListEnd();
13 | private ParamListEnd()
14 | {
15 | if (Instance != null) throw new NotSupportedException();
16 | }
17 |
18 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0) => throw new NotImplementedException();
19 |
20 | internal override void WriteTo(MethodCodeDataWriterArgs a) => a.ExpressionData.Write((byte)0x01);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/ParamListExpression.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.IO;
5 | using System.Text;
6 |
7 | namespace QIQI.EProjectFile.Expressions
8 | {
9 | ///
10 | /// 参数列表,配合CallExpression用
11 | ///
12 | public class ParamListExpression : Expression, IList
13 | {
14 | private readonly List parameters = new List();
15 |
16 | public int Count => parameters.Count;
17 |
18 | public bool IsReadOnly => ((IList)parameters).IsReadOnly;
19 |
20 | public Expression this[int index] { get => parameters[index]; set => this.parameters[index] = value; }
21 |
22 | public void Add(Expression item)
23 | {
24 | parameters.Add(item ?? DefaultValueExpression.Instance);
25 | }
26 | internal override void WriteTo(MethodCodeDataWriterArgs a)
27 | {
28 | parameters.ForEach(x => x.WriteTo(a));
29 | ParamListEnd.Instance.WriteTo(a);
30 | }
31 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
32 | {
33 | writer.Write("(");
34 | TextCodeUtils.JoinAndWriteCode(this, ", ", nameMap, writer, indent);
35 | writer.Write(")");
36 | }
37 |
38 | public IEnumerator GetEnumerator() => ((IEnumerable)parameters).GetEnumerator();
39 | IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)parameters).GetEnumerator();
40 |
41 | public int IndexOf(Expression item)
42 | {
43 | return parameters.IndexOf(item ?? DefaultValueExpression.Instance);
44 | }
45 |
46 | public void Insert(int index, Expression item)
47 | {
48 | parameters.Insert(index, item ?? DefaultValueExpression.Instance);
49 | }
50 |
51 | public void RemoveAt(int index)
52 | {
53 | parameters.RemoveAt(index);
54 | }
55 |
56 | public void Clear()
57 | {
58 | parameters.Clear();
59 | }
60 |
61 | public bool Contains(Expression item)
62 | {
63 | return parameters.Contains(item ?? DefaultValueExpression.Instance);
64 | }
65 |
66 | public void CopyTo(Expression[] array, int arrayIndex)
67 | {
68 | parameters.CopyTo(array, arrayIndex);
69 | }
70 |
71 | public bool Remove(Expression item)
72 | {
73 | return parameters.Remove(item ?? DefaultValueExpression.Instance);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/StringLiteral.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Internal;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Expressions
6 | {
7 | ///
8 | /// 文本型字面量
9 | ///
10 | public class StringLiteral : Expression
11 | {
12 | public readonly string Value;
13 | public StringLiteral(string value)
14 | {
15 | this.Value = value;
16 | }
17 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
18 | {
19 | writer.Write("“");
20 | writer.Write(Value ?? "");
21 | writer.Write("”");
22 | }
23 | internal override void WriteTo(MethodCodeDataWriterArgs a)
24 | {
25 | a.ExpressionData.Write((byte)0x1A);
26 | a.ExpressionData.WriteBStr(a.Encoding, Value ?? "");
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/EProjectFile/Expressions/VariableExpression.cs:
--------------------------------------------------------------------------------
1 | using System.IO;
2 | using System.Text;
3 |
4 | namespace QIQI.EProjectFile.Expressions
5 | {
6 | ///
7 | /// 访问变量表达式
8 | ///
9 | public class VariableExpression : In0x38Expression
10 | {
11 | public readonly int Id;
12 | public VariableExpression(int id)
13 | {
14 | this.Id = id;
15 | }
16 |
17 | public override void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0)
18 | {
19 | writer.Write(nameMap.GetUserDefinedName(Id));
20 | }
21 | internal override void WriteTo(MethodCodeDataWriterArgs a, bool need0x1DAnd0x37)
22 | {
23 | if (need0x1DAnd0x37)
24 | {
25 | a.VariableReference.Write(a.Offest);
26 | a.ExpressionData.Write((byte)0x1D);
27 | a.ExpressionData.Write((byte)0x38);
28 | }
29 | a.ExpressionData.Write(Id);
30 | if (need0x1DAnd0x37) a.ExpressionData.Write((byte)0x37);
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/EProjectFile/FormElementInfo.cs:
--------------------------------------------------------------------------------
1 | using OpenEpl.ELibInfo;
2 | using QIQI.EProjectFile.Internal;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Text;
7 | using System.Text.Json.Serialization;
8 | using System.Text.Json;
9 |
10 | namespace QIQI.EProjectFile
11 | {
12 | [JsonConverter(typeof(FormElementInfoJsonConverter))]
13 | public abstract class FormElementInfo : IHasId
14 | {
15 | private const int DataType_Menu = 65539;
16 |
17 | private class FormElementInfoJsonConverter : JsonConverter
18 | {
19 | public override FormElementInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
20 | {
21 | var element = JsonElement.ParseValue(ref reader);
22 | if (!element.TryGetProperty("DataType", out var jsonElement))
23 | {
24 | throw new Exception($"Missing {nameof(FormElementInfo)}.{nameof(FormElementInfo.DataType)}");
25 | }
26 | if (!jsonElement.TryGetInt32(out var dataType))
27 | {
28 | throw new Exception($"Unsupported {nameof(FormElementInfo)}.{nameof(FormElementInfo.DataType)} = {jsonElement}");
29 | }
30 | return dataType switch
31 | {
32 | DataType_Menu => element.Deserialize(options),
33 | _ => element.Deserialize(options),
34 | };
35 | }
36 |
37 | public override void Write(
38 | Utf8JsonWriter writer,
39 | FormElementInfo value,
40 | JsonSerializerOptions options)
41 | {
42 | switch (value)
43 | {
44 | case FormMenuInfo menu:
45 | JsonSerializer.Serialize(writer, menu, options);
46 | break;
47 | case FormControlInfo control:
48 | JsonSerializer.Serialize(writer, control, options);
49 | break;
50 | default:
51 | throw new Exception($"Unknown sub class of {nameof(FormElementInfo)}");
52 | }
53 | }
54 | }
55 |
56 | public abstract int Id { get; }
57 | public int DataType { get; set; }
58 | public string Name { get; set; }
59 | public bool Visible { get; set; }
60 | public bool Disable { get; set; }
61 |
62 | public static List ReadFormElements(BinaryReader r, Encoding encoding)
63 | {
64 | return r.ReadBlocksWithIdAndOffest((reader, id, length) =>
65 | {
66 | var dataType = reader.ReadInt32();
67 | FormElementInfo elem;
68 | if (dataType == DataType_Menu)
69 | {
70 | elem = FormMenuInfo.ReadWithoutDataType(r, encoding, id, length - 4);
71 | }
72 | else
73 | {
74 | elem = FormControlInfo.ReadWithoutDataType(r, encoding, id, length - 4);
75 | }
76 | elem.DataType = dataType;
77 | return elem;
78 | });
79 | }
80 | public static void WriteFormElements(BinaryWriter w, Encoding encoding, List formElements)
81 | {
82 | w.WriteBlocksWithIdAndOffest(
83 | encoding,
84 | formElements,
85 | (writer, elem) =>
86 | {
87 | elem.WriteWithoutId(writer, encoding);
88 | });
89 | }
90 |
91 | protected abstract void WriteWithoutId(BinaryWriter writer, Encoding encoding);
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/EProjectFile/FormInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Text;
5 | using System.Text.Json;
6 | using QIQI.EProjectFile.Internal;
7 |
8 | namespace QIQI.EProjectFile
9 | {
10 | public class FormInfo: IHasId, IHasMemoryAddress
11 | {
12 | public int Id { get; }
13 |
14 | public FormInfo(int id)
15 | {
16 | this.Id = id;
17 | }
18 |
19 | public int MemoryAddress { get; set; }
20 | public int UnknownBeforeClass { get; set; }
21 | ///
22 | /// 对应的窗口程序集
23 | ///
24 | public int Class { get; set; }
25 | public string Name { get; set; }
26 | public string Comment { get; set; }
27 | public List Elements { get; set; }
28 | public static List ReadForms(BinaryReader r, Encoding encoding)
29 | {
30 | return r.ReadBlocksWithIdAndMemoryAddress((reader, id, memoryAddress) => new FormInfo(id)
31 | {
32 | MemoryAddress = memoryAddress,
33 | UnknownBeforeClass = reader.ReadInt32(),
34 | Class = reader.ReadInt32(),
35 | Name = reader.ReadStringWithLengthPrefix(encoding),
36 | Comment = reader.ReadStringWithLengthPrefix(encoding),
37 | Elements = FormElementInfo.ReadFormElements(reader, encoding)
38 | });
39 | }
40 |
41 | public static void WriteForms(BinaryWriter w, Encoding encoding, List forms)
42 | {
43 | w.WriteBlocksWithIdAndMemoryAddress(forms, (writer, elem) =>
44 | {
45 | writer.Write(elem.UnknownBeforeClass);
46 | writer.Write(elem.Class);
47 | writer.WriteStringWithLengthPrefix(encoding, elem.Name);
48 | writer.WriteStringWithLengthPrefix(encoding, elem.Comment);
49 | FormElementInfo.WriteFormElements(writer, encoding, elem.Elements);
50 | });
51 | }
52 |
53 | public override string ToString()
54 | {
55 | return JsonSerializer.Serialize(this, JsonUtils.Options);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/EProjectFile/FormMenuInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Text.Json;
2 | using QIQI.EProjectFile.Internal;
3 | using System;
4 | using System.Collections.Immutable;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Text.Json.Serialization;
9 |
10 | namespace QIQI.EProjectFile
11 | {
12 | public class FormMenuInfo : FormElementInfo
13 | {
14 | private static readonly ImmutableArray Zero16Bytes = ImmutableArray.Create(new byte[16]);
15 | private static readonly ImmutableArray Zero20Bytes = ImmutableArray.Create(new byte[20]);
16 |
17 | public override int Id { get; }
18 |
19 | public FormMenuInfo(int id)
20 | {
21 | this.Id = id;
22 | }
23 |
24 | [JsonIgnore]
25 | public ImmutableArray UnknownBeforeName { get; set; } = Zero20Bytes;
26 | public int HotKey { get; set; }
27 | public int Level { get; set; }
28 | public bool Selected { get; set; }
29 | public string Text { get; set; }
30 | ///
31 | /// 仅EC有效
32 | ///
33 | public int ClickEvent { get; set; }
34 | [JsonIgnore]
35 | public ImmutableArray UnknownAfterClickEvent { get; set; } = Zero16Bytes;
36 | internal static FormMenuInfo ReadWithoutDataType(BinaryReader reader, Encoding encoding, int id, int length)
37 | {
38 | var startPosition = reader.BaseStream.Position;
39 | var elem = new FormMenuInfo(id);
40 | elem.UnknownBeforeName = reader.ReadImmutableBytes(20) switch
41 | {
42 | var x when x.SequenceEqual(Zero20Bytes) => Zero20Bytes,
43 | var x => x
44 | };
45 | elem.Name = reader.ReadCStyleString(encoding);
46 | reader.ReadCStyleString(encoding); // 菜单没有Comment
47 | elem.HotKey = reader.ReadInt32();
48 | elem.Level = reader.ReadInt32();
49 | {
50 | int showStatus = reader.ReadInt32();
51 | elem.Visible = (showStatus & 0x1) == 0;
52 | elem.Disable = (showStatus & 0x2) != 0;
53 | elem.Selected = (showStatus & 0x4) != 0;
54 | if ((showStatus & 0xFFFFFFF8) != 0)
55 | {
56 | throw new Exception($"Unknown flag for show status of the menu is found, value = 0x{showStatus:X8}");
57 | }
58 | }
59 | elem.Text = reader.ReadCStyleString(encoding);
60 | elem.ClickEvent = reader.ReadInt32();
61 | elem.UnknownAfterClickEvent = reader.ReadImmutableBytes(length - (int)(reader.BaseStream.Position - startPosition)) switch
62 | {
63 | var x when x.SequenceEqual(Zero16Bytes) => Zero16Bytes,
64 | var x => x
65 | }; ;
66 | return elem;
67 | }
68 | protected override void WriteWithoutId(BinaryWriter writer, Encoding encoding)
69 | {
70 | writer.Write(DataType);
71 | writer.Write(UnknownBeforeName);
72 | writer.WriteCStyleString(encoding, Name);
73 | writer.WriteCStyleString(encoding, "");
74 | writer.Write(HotKey);
75 | writer.Write(Level);
76 | writer.Write((Visible ? 0 : 0x1) | (Disable ? 0x2 : 0) | (Selected ? 0x4 : 0));
77 | writer.WriteCStyleString(encoding, Text);
78 | writer.Write(ClickEvent);
79 | writer.Write(UnknownAfterClickEvent);
80 | }
81 | public override string ToString()
82 | {
83 | return JsonSerializer.Serialize(this, JsonUtils.Options);
84 | }
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/EProjectFile/IHasId.cs:
--------------------------------------------------------------------------------
1 | namespace QIQI.EProjectFile
2 | {
3 | public interface IHasId
4 | {
5 | int Id { get; }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/EProjectFile/IHasMemoryAddress.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile
6 | {
7 | public interface IHasMemoryAddress
8 | {
9 | ///
10 | /// 最后一次保存时易语言 IDE 储存相关结构使用的内存地址
11 | /// 在用于编辑文件的场景下,意义不大
12 | ///
13 | int MemoryAddress { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/EProjectFile/IToTextCodeAble.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.IO;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile
6 | {
7 | public interface IToTextCodeAble
8 | {
9 | ///
10 | /// 开头含缩进,结尾不含换行
11 | ///
12 | ///
13 | ///
14 | ///
15 | void ToTextCode(IdToNameMap nameMap, TextWriter writer, int indent = 0);
16 | }
17 | public static class ExtensionForIToTextCodeAble
18 | {
19 | public static string ToTextCode(this IToTextCodeAble target, IdToNameMap nameMap, int indent = 0)
20 | {
21 | var writer = new StringWriter();
22 | target.ToTextCode(nameMap, writer, indent);
23 | return writer.ToString();
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/EProjectFile/IndexedEventInfo.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile
6 | {
7 | public class IndexedEventInfo
8 | {
9 | public int FormId { get; set; }
10 | public int UnitId { get; set; }
11 | public int EventId { get; set; }
12 | public int MethodId { get; set; }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/EProjectFile/Internal/ByteArrayHexConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.Text.Json;
5 | using System.Globalization;
6 | using System.Linq;
7 | using System.Text.Json.Serialization;
8 |
9 | namespace QIQI.EProjectFile.Internal
10 | {
11 | internal class ByteArrayHexConverter : JsonConverter
12 | {
13 | public override byte[] Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
14 | {
15 | return BytesUtils.HexToBytes(reader.GetString());
16 | }
17 |
18 | public override void Write(Utf8JsonWriter writer, byte[] value, JsonSerializerOptions options)
19 | {
20 | writer.WriteStringValue(BytesUtils.BytesToHex(value));
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/EProjectFile/Internal/BytesUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 |
5 | namespace QIQI.EProjectFile.Internal
6 | {
7 | internal static class BytesUtils
8 | {
9 | public static byte[] HexToBytes(string src)
10 | {
11 | byte[] result = new byte[src.Length / 2];
12 | for (int i = 0, c = 0; i < src.Length; i += 2, c++)
13 | {
14 | result[c] = Convert.ToByte(src.Substring(i, 2), 16);
15 | }
16 | return result;
17 | }
18 |
19 | public static string BytesToHex(byte[] data)
20 | {
21 | var sb = new StringBuilder(data.Length * 2);
22 | if (data != null)
23 | {
24 | for (int i = 0; i < data.Length; i++)
25 | {
26 | sb.Append(data[i].ToString("X2"));
27 | }
28 | }
29 | return sb.ToString();
30 | }
31 |
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/EProjectFile/Internal/CryptoECTransform.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Encryption;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 |
7 | namespace QIQI.EProjectFile.Internal
8 | {
9 | sealed class CryptoECTransform : EStdCryptoTransform
10 | {
11 | public CryptoECTransform(EplSecret.EC secret, int lengthOfOvert = 0): base(secret, lengthOfOvert)
12 | {
13 | }
14 |
15 | protected override RC4Crypto NextBlockCrypto()
16 | {
17 | byte[] blockKey = new byte[40];
18 | keyTable.Decode(blockKey, 0, 8);
19 | SecretId.CopyTo(0, blockKey, 8, 32);
20 | return new RC4Crypto(blockKey, EplSecret.EC.DefaultInitialStatus);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/EProjectFile/Internal/EStdCryptoTransform.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.Encryption;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Collections.Immutable;
5 | using System.Security.Cryptography;
6 | using System.Text;
7 |
8 | namespace QIQI.EProjectFile.Internal
9 | {
10 | internal class EStdCryptoTransform : ICryptoTransform
11 | {
12 | private const int BlockLength = 4096;
13 | protected readonly RC4Crypto keyTable;
14 |
15 | public ImmutableArray SecretId { get; }
16 | private int lengthOfRemainedOvert = 0;
17 |
18 | public EStdCryptoTransform(EplSecret.EStd secret, int lengthOfOvert = 0): this((EplSecret)secret, lengthOfOvert)
19 | {
20 | }
21 |
22 | protected EStdCryptoTransform(EplSecret secret, int lengthOfOvert = 0)
23 | {
24 | if (secret is null)
25 | {
26 | throw new ArgumentNullException(nameof(secret));
27 | }
28 | if (lengthOfOvert < 0)
29 | {
30 | throw new ArgumentException(nameof(lengthOfOvert));
31 | }
32 | keyTable = new RC4Crypto(default, secret.IV);
33 | SecretId = secret.SecretId;
34 | lengthOfRemainedOvert = lengthOfOvert;
35 | }
36 |
37 | public bool CanReuseTransform => false;
38 |
39 | public bool CanTransformMultipleBlocks => false;
40 |
41 | public int InputBlockSize => BlockLength;
42 |
43 | public int OutputBlockSize => BlockLength;
44 |
45 | private int blockIndex = 0;
46 |
47 | public void Dispose()
48 | {
49 | }
50 |
51 | public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset)
52 | {
53 | Array.Copy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
54 | var crpyto = NextBlockCrypto();
55 | if (inputCount > lengthOfRemainedOvert)
56 | {
57 | crpyto.Skip(lengthOfRemainedOvert);
58 | crpyto.Decode(outputBuffer, outputOffset + lengthOfRemainedOvert, inputCount - lengthOfRemainedOvert);
59 | lengthOfRemainedOvert = 0;
60 | }
61 | else
62 | {
63 | lengthOfRemainedOvert -= inputCount;
64 | }
65 | return inputCount;
66 | }
67 |
68 | protected virtual RC4Crypto NextBlockCrypto()
69 | {
70 | byte[] blockKey = new byte[40];
71 | keyTable.Decode(blockKey, 0, 4);
72 | var nPrefix = blockKey[0] + (blockKey[1] << 8) + (blockKey[2] << 16) + (blockKey[3] << 24);
73 | var nSuffix = blockIndex ^ nPrefix;
74 | blockIndex++;
75 | SecretId.CopyTo(0, blockKey, 4, 32);
76 | blockKey[36] = unchecked((byte)(nSuffix & 0xFF));
77 | blockKey[37] = unchecked((byte)((nSuffix >> 8) & 0xFF));
78 | blockKey[38] = unchecked((byte)((nSuffix >> 16) & 0xFF));
79 | blockKey[39] = unchecked((byte)((nSuffix >> 24) & 0xFF));
80 | var crypto = new RC4Crypto(blockKey, 256);
81 | crypto.Skip(36); // Magic
82 | return crypto;
83 | }
84 |
85 | public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount)
86 | {
87 | var buf = new byte[inputCount];
88 | TransformBlock(inputBuffer, inputOffset, inputCount, buf, 0);
89 | return buf;
90 | }
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/EProjectFile/Internal/EditorTabInfoJsonConverter.cs:
--------------------------------------------------------------------------------
1 | using QIQI.EProjectFile.EditorTabInfo;
2 | using System;
3 | using System.Linq;
4 | using System.Text.Json;
5 | using System.Text.Json.Nodes;
6 | using System.Text.Json.Serialization;
7 |
8 | namespace QIQI.EProjectFile.Internal
9 | {
10 | internal class EditorTabInfoJsonConverter : JsonConverter
11 | {
12 | public override IEditorTabInfo Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
13 | {
14 | var root = JsonNode.Parse(ref reader).AsObject();
15 | if (!root.TryGetPropertyValue(nameof(IEditorTabInfo.TypeId), out var typeIdNode))
16 | {
17 | throw new Exception($"Missing {nameof(IEditorTabInfo.TypeId)}");
18 | }
19 | var typeId = (byte)typeIdNode;
20 | if (PredefinedEditorTabInfos.Keys.TryGetValue(typeId, out var etik))
21 | {
22 | var editorTabInfoType = etik.GetType()
23 | .GetInterfaces()
24 | .First(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEditorTabInfoKey<>))
25 | .GetGenericArguments()
26 | .Single();
27 | return (IEditorTabInfo)JsonSerializer.Deserialize(root, editorTabInfoType, options);
28 | }
29 | else if (root.ContainsKey("Data"))
30 | {
31 | return JsonSerializer.Deserialize(root, options);
32 | }
33 | else
34 | {
35 | throw new Exception($"Failed to find a suitable JSON Deserializer of {nameof(IEditorTabInfo)} for Unknown[0x{typeId:X2}]");
36 | }
37 | }
38 |
39 | public override void Write(Utf8JsonWriter writer, IEditorTabInfo value, JsonSerializerOptions options)
40 | {
41 | JsonSerializer.Serialize