parent
4e84921b75
commit
2839880514
@ -0,0 +1 @@
|
||||
BasedOnStyle: LLVM
|
@ -0,0 +1,3 @@
|
||||
[submodule "tool/gui/QDarkStyleSheet"]
|
||||
path = tool/gui/QDarkStyleSheet
|
||||
url = https://github.com/gmh5225/QDarkStyleSheet
|
@ -0,0 +1,52 @@
|
||||
project(UnknownField-project)
|
||||
|
||||
find_package(LLVM REQUIRED CONFIG)
|
||||
include_directories(${LLVM_INCLUDE_DIRS})
|
||||
link_directories(${LLVM_LIBRARY_DIRS})
|
||||
add_definitions(${LLVM_DEFINITIONS})
|
||||
|
||||
find_package(Clang REQUIRED CONFIG)
|
||||
include_directories(${CLANG_INCLUDE_DIRS})
|
||||
link_directories(${CLANG_LIBRARY_DIRS})
|
||||
add_definitions(${CLANG_DEFINITIONS})
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${LLVM_CMAKE_DIR})
|
||||
include(AddLLVM)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CLANG_CMAKE_DIR})
|
||||
include(AddClang)
|
||||
|
||||
if(DEBUG_MODE)
|
||||
add_definitions(-DDEBUG_MODE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MT")
|
||||
|
||||
add_library(UnknownField-lib STATIC
|
||||
sdk/UnknownFieldSDK.h
|
||||
ObfuscateField.h
|
||||
ObfuscateField.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(UnknownField-lib
|
||||
PRIVATE
|
||||
clangAST
|
||||
clangASTMatchers
|
||||
clangBasic
|
||||
clangDynamicASTMatchers
|
||||
clangFrontend
|
||||
clangTooling
|
||||
clangSerialization
|
||||
LLVMLineEditor
|
||||
LLVMSupport
|
||||
LLVMFrontendOpenMP
|
||||
)
|
||||
|
||||
add_subdirectory(tool)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,9 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
Copyright (c) 2022 gmh
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
@ -0,0 +1,13 @@
|
||||
#include "ObfuscateField.h"
|
||||
|
||||
std::map<std::string, std::vector<const clang::FieldDecl *>>
|
||||
GlobalFieldNodeVectorMap;
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
GlobalClassFieldDeclStringVectorMap;
|
||||
std::map<std::string, bool> GlobalSDKUnknownFieldProtectionEnabledMap;
|
||||
|
||||
llvm::cl::OptionCategory
|
||||
UnknownFieldOptionCategory("UnknownField OptionCategory");
|
||||
|
||||
cl::opt<bool> GlobalObfucated{"g", cl::desc("Enable global obfucation"), cl::init(false),
|
||||
cl::cat(UnknownFieldOptionCategory)};
|
@ -0,0 +1,220 @@
|
||||
#ifndef _OBFUSCATE_FIELD_H
|
||||
#define _OBFUSCATE_FIELD_H
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <random>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "clang/AST/AST.h"
|
||||
#include "clang/AST/ASTConsumer.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Frontend/CompilerInstance.h"
|
||||
#include "clang/Frontend/FrontendActions.h"
|
||||
#include "clang/Lex/MacroArgs.h"
|
||||
#include "clang/Rewrite/Core/Rewriter.h"
|
||||
#include "clang/Tooling/CommonOptionsParser.h"
|
||||
#include "clang/Tooling/Refactoring.h"
|
||||
#include "clang/Tooling/Tooling.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
using namespace clang;
|
||||
using namespace clang::ast_matchers;
|
||||
using namespace clang::driver;
|
||||
using namespace clang::tooling;
|
||||
|
||||
#define UnknownFieldProtectionTagName "UnknownFieldProtection"
|
||||
|
||||
extern std::map<std::string, std::vector<const clang::FieldDecl *>>
|
||||
GlobalFieldNodeVectorMap;
|
||||
extern std::map<std::string, std::vector<std::string>>
|
||||
GlobalClassFieldDeclStringVectorMap;
|
||||
extern std::map<std::string, bool> GlobalSDKUnknownFieldProtectionEnabledMap;
|
||||
|
||||
extern llvm::cl::OptionCategory UnknownFieldOptionCategory;
|
||||
extern cl::opt<bool> GlobalObfucated;
|
||||
|
||||
class ObfuscateFieldDeclHandler : public MatchFinder::MatchCallback {
|
||||
public:
|
||||
ObfuscateFieldDeclHandler(Rewriter &Rewrite) : Rewrite(Rewrite) {}
|
||||
|
||||
virtual void run(const MatchFinder::MatchResult &Result) {
|
||||
if (auto FDNode =
|
||||
Result.Nodes.getNodeAs<clang::FieldDecl>("ObfuscateField")) {
|
||||
auto FieldStr = Rewrite.getRewrittenText(FDNode->getSourceRange());
|
||||
if (FieldStr.empty()) {
|
||||
// Empty strings are not required
|
||||
return;
|
||||
}
|
||||
|
||||
auto QualifiedNameStr = FDNode->getQualifiedNameAsString();
|
||||
auto ClassNameStr = QualifiedNameStr.substr(
|
||||
0, FDNode->getQualifiedNameAsString().length() -
|
||||
FDNode->getNameAsString().length() - 2);
|
||||
|
||||
if (FDNode->hasInClassInitializer()) {
|
||||
// Filter field that in class initializer
|
||||
GlobalSDKUnknownFieldProtectionEnabledMap[ClassNameStr] = false;
|
||||
outs() << "Error: Found field(" << FieldStr << ")"
|
||||
<< " that in class(" << ClassNameStr << ")"
|
||||
<< " initializer we don't support!\n ";
|
||||
exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
// Save sth that used later.
|
||||
GlobalFieldNodeVectorMap[ClassNameStr].push_back(FDNode);
|
||||
GlobalClassFieldDeclStringVectorMap[ClassNameStr].push_back(FieldStr);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Rewriter &Rewrite;
|
||||
};
|
||||
|
||||
class ObfuscateFieldASTConsumer : public ASTConsumer {
|
||||
public:
|
||||
ObfuscateFieldASTConsumer(Rewriter &R) : HandlerForObfuscateFieldDecl(R) {
|
||||
// Only match our main file.So we should use 'isExpansionInMainFile()'
|
||||
Matcher.addMatcher(
|
||||
traverse(TK_IgnoreUnlessSpelledInSource,
|
||||
fieldDecl(isExpansionInMainFile()).bind("ObfuscateField")),
|
||||
&HandlerForObfuscateFieldDecl);
|
||||
}
|
||||
|
||||
void HandleTranslationUnit(ASTContext &Context) override {
|
||||
Matcher.matchAST(Context);
|
||||
}
|
||||
|
||||
private:
|
||||
ObfuscateFieldDeclHandler HandlerForObfuscateFieldDecl;
|
||||
MatchFinder Matcher;
|
||||
};
|
||||
|
||||
class PreprocessorPPCallback : public PPCallbacks {
|
||||
public:
|
||||
/// Called by Preprocessor::HandleMacroExpandedIdentifier when a
|
||||
/// macro invocation is found.
|
||||
virtual void MacroExpands(const Token &MacroNameTok,
|
||||
const MacroDefinition &MD, SourceRange Range,
|
||||
const MacroArgs *Args) {
|
||||
|
||||
if (GlobalObfucated) {
|
||||
// This is a global tag
|
||||
return;
|
||||
}
|
||||
|
||||
auto IdentifierInfo = MacroNameTok.getIdentifierInfo();
|
||||
if (!IdentifierInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Args) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We only care about our markers
|
||||
if (IdentifierInfo->getName().compare(UnknownFieldProtectionTagName) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto UnexpArgument0 = Args->getUnexpArgument(0);
|
||||
if (!UnexpArgument0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto Arg0IdentifierInfo = UnexpArgument0->getIdentifierInfo();
|
||||
if (!Arg0IdentifierInfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
StringRef ClassName = Arg0IdentifierInfo->getName();
|
||||
GlobalSDKUnknownFieldProtectionEnabledMap[ClassName.str()] = true;
|
||||
outs() << "Scanning " << UnknownFieldProtectionTagName << " in class("
|
||||
<< ClassName << ").\n";
|
||||
}
|
||||
};
|
||||
|
||||
class ObfuscateFieldFrontendAction : public ASTFrontendAction {
|
||||
private:
|
||||
auto GenerateRandomKey() {
|
||||
std::random_device RD;
|
||||
// Generate seed
|
||||
std::mt19937 G(RD());
|
||||
return G;
|
||||
}
|
||||
|
||||
bool EnableObfuscated(std::string ClassName) {
|
||||
if (GlobalObfucated) {
|
||||
// This is a global tag
|
||||
return true;
|
||||
}
|
||||
|
||||
// Find class name that need to be protected.
|
||||
if (GlobalSDKUnknownFieldProtectionEnabledMap.find(ClassName) !=
|
||||
GlobalSDKUnknownFieldProtectionEnabledMap.end()) {
|
||||
if (GlobalSDKUnknownFieldProtectionEnabledMap[ClassName]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
ObfuscateFieldFrontendAction() {}
|
||||
void EndSourceFileAction() override {
|
||||
|
||||
// For Field
|
||||
{
|
||||
// Traverse map
|
||||
for (auto &Map : GlobalClassFieldDeclStringVectorMap) {
|
||||
if (!EnableObfuscated(Map.first)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Shuffle it
|
||||
std::shuffle(Map.second.begin(), Map.second.end(), GenerateRandomKey());
|
||||
|
||||
// Replace it
|
||||
size_t Count = Map.second.size();
|
||||
for (size_t i = 0; i < Count; ++i) {
|
||||
if (Map.second[i].empty()) {
|
||||
// Empty strings are not required
|
||||
continue;
|
||||
}
|
||||
auto FDNode = GlobalFieldNodeVectorMap[Map.first][i];
|
||||
TheRewriter.ReplaceText(FDNode->getSourceRange(),
|
||||
Map.second[i].c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_MODE
|
||||
TheRewriter.getEditBuffer(TheRewriter.getSourceMgr().getMainFileID())
|
||||
.write(llvm::outs());
|
||||
#else
|
||||
TheRewriter.overwriteChangedFiles();
|
||||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
|
||||
StringRef file) override {
|
||||
// Add PPCallbacks
|
||||
CI.getPreprocessor().addPPCallbacks(
|
||||
std::make_unique<PreprocessorPPCallback>());
|
||||
|
||||
// New ASTConsumer
|
||||
TheRewriter.setSourceMgr(CI.getSourceManager(), CI.getLangOpts());
|
||||
return std::make_unique<ObfuscateFieldASTConsumer>(TheRewriter);
|
||||
}
|
||||
|
||||
private:
|
||||
Rewriter TheRewriter;
|
||||
};
|
||||
|
||||
#endif
|
@ -1,3 +1,69 @@
|
||||
# UnknownField
|
||||
|
||||
UnknownField is a tool based clang that obfuscating the order of fields to protect your C/C++ game or code.
|
||||
|
||||
![image](images/UnknownField-gui.png)
|
||||
|
||||
## Before
|
||||
![image](images/UnknownField_before.png)
|
||||
|
||||
## After
|
||||
![image](images/UnknownField_after.png)
|
||||
|
||||
## Usage
|
||||
```
|
||||
UnknownField-cli.exe
|
||||
Usage: UnknownField-cli.exe [options] <source0> [... <sourceN>]
|
||||
|
||||
Optional arguments:
|
||||
-- -I - External include directory
|
||||
-g - Enable global obfucation
|
||||
```
|
||||
|
||||
## Example commands:
|
||||
```bash
|
||||
UnknownField-cli.exe test.cpp
|
||||
UnknownField-cli.exe test.cpp -g
|
||||
UnknownField-cli.exe test.cpp -- -IE:\External\Directory
|
||||
UnknownField-cli.exe test.cpp -- -IE:\External\Directory1 -IE:\External\Directory2
|
||||
```
|
||||
|
||||
## Example SDK:
|
||||
```C++
|
||||
#include "sdk/UnknownFieldSDK.h"
|
||||
#include <Windows.h>
|
||||
class UnknownFieldProtection(MyClassX) {
|
||||
public:
|
||||
MyClassX();
|
||||
~MyClassX();
|
||||
private:
|
||||
UCHAR name[300];
|
||||
DWORD mp;
|
||||
DWORD maxmp;
|
||||
DWORD hp;
|
||||
DWORD maxhp;
|
||||
unsigned char level;
|
||||
};
|
||||
```
|
||||
|
||||
## Usage Dependency
|
||||
- Visual Studio with SDK10 (without this you could not include windows.h in your file)
|
||||
|
||||
## Build Dependency
|
||||
- [llvm-msvc](https://github.com/NewWorldComingSoon/llvm-msvc-build/releases)
|
||||
|
||||
## Build
|
||||
```
|
||||
git clone --recurse-submodules https://github.com/NewWorldComingSoon/UnknownField.git
|
||||
cd UnknownField
|
||||
mkdir build
|
||||
cd build
|
||||
set LLVM-MSVC-BIN=E:\llvm\llvm-msvc-bin -> You need to replace your path.
|
||||
cmake ../ -DLLVM_DIR=%LLVM-MSVC-BIN%\lib\cmake\llvm -DClang_DIR=%LLVM-MSVC-BIN%\lib\cmake\clang
|
||||
cmake --build . --config Release -- -m
|
||||
```
|
||||
|
||||
## TODO
|
||||
- Obfuscating the order of virtual functions.
|
||||
|
||||
## Note
|
||||
This project is currently still a demo.
|
||||
|
@ -0,0 +1,8 @@
|
||||
cd ./
|
||||
mkdir build-release
|
||||
cd build-release
|
||||
cmake ../ -DLLVM_DIR=E:\llvm\llvm-msvc-bin\lib\cmake\llvm -DClang_DIR=E:\llvm\llvm-msvc-bin\lib\cmake\clang
|
||||
cd ../
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 29 KiB |
After Width: | Height: | Size: 3.3 KiB |
After Width: | Height: | Size: 13 KiB |
@ -0,0 +1,6 @@
|
||||
#ifndef _UNKNOWN_FIELD_SDK_H
|
||||
#define _UNKNOWN_FIELD_SDK_H
|
||||
|
||||
#define UnknownFieldProtection(CLASS) CLASS
|
||||
|
||||
#endif
|
@ -0,0 +1,49 @@
|
||||
#include "../sdk/UnknownFieldSDK.h"
|
||||
#include <Windows.h>
|
||||
|
||||
class UnknownFieldProtection(MyClassX) {
|
||||
public:
|
||||
MyClassX();
|
||||
~MyClassX();
|
||||
private:
|
||||
UCHAR name[300];
|
||||
DWORD mp;
|
||||
DWORD maxmp;
|
||||
DWORD hp;
|
||||
DWORD maxhp;
|
||||
unsigned char level;
|
||||
};
|
||||
|
||||
class MyClassX2 {
|
||||
public:
|
||||
MyClassX2();
|
||||
~MyClassX2();
|
||||
|
||||
private:
|
||||
char name2[300];
|
||||
int mp2;
|
||||
int maxmp2;
|
||||
int hp2;
|
||||
int maxhp2;
|
||||
unsigned char level2;
|
||||
};
|
||||
|
||||
class MyClassX3 {
|
||||
public:
|
||||
MyClassX3();
|
||||
~MyClassX3();
|
||||
|
||||
private:
|
||||
char name3[300];
|
||||
int mp3;
|
||||
int maxmp3;
|
||||
int hp3;
|
||||
int maxhp3;
|
||||
unsigned char level3;
|
||||
};
|
||||
|
||||
int myfunct(int a, int b) {
|
||||
int c;
|
||||
c = a + b;
|
||||
return c;
|
||||
}
|
Binary file not shown.
@ -0,0 +1,20 @@
|
||||
#include <stdio.h>
|
||||
#include "../sdk/UnknownFieldSDK.h"
|
||||
|
||||
static unsigned int gv = 0;
|
||||
class C1 {
|
||||
public:
|
||||
C1() { gv = 1; }
|
||||
};
|
||||
|
||||
class UnknownFieldProtection(C2) {
|
||||
public:
|
||||
C1 c;
|
||||
unsigned int gv_ = gv;
|
||||
};
|
||||
|
||||
int main() {
|
||||
C2 c2;
|
||||
printf("c2.gv=%d\n", c2.gv_);
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,147 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{eea027dd-c602-4efb-9b3a-7fe8d8f2b39c}</ProjectGuid>
|
||||
<RootNamespace>testp</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\test_p.cpp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\test_p.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,12 @@
|
||||
|
||||
add_subdirectory(cli)
|
||||
#add_subdirectory(gui)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../)
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/MT")
|
||||
|
||||
add_executable(UnknownField-cli
|
||||
UnknownField-cli.cpp
|
||||
)
|
||||
target_link_libraries(UnknownField-cli
|
||||
PRIVATE
|
||||
UnknownField-lib
|
||||
)
|
@ -0,0 +1,22 @@
|
||||
|
||||
#include "ObfuscateField.h"
|
||||
|
||||
int main(int argc, const char **argv) {
|
||||
Expected<tooling::CommonOptionsParser> eOptParser =
|
||||
clang::tooling::CommonOptionsParser::create(
|
||||
argc, argv, UnknownFieldOptionCategory, llvm::cl::OneOrMore, nullptr,
|
||||
false);
|
||||
if (auto E = eOptParser.takeError()) {
|
||||
errs() << "Problem constructing CommonOptionsParser "
|
||||
<< toString(std::move(E)) << '\n';
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
clang::tooling::ClangTool Tool(eOptParser->getCompilations(),
|
||||
eOptParser->getSourcePathList());
|
||||
int Ret = Tool.run(
|
||||
clang::tooling::newFrontendActionFactory<ObfuscateFieldFrontendAction>()
|
||||
.get());
|
||||
outs() << "UnknownField finished!\n";
|
||||
return Ret;
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
# This file is used to ignore files which are generated
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
*~
|
||||
*.autosave
|
||||
*.a
|
||||
*.core
|
||||
*.moc
|
||||
*.o
|
||||
*.obj
|
||||
*.orig
|
||||
*.rej
|
||||
*.so
|
||||
*.so.*
|
||||
*_pch.h.cpp
|
||||
*_resource.rc
|
||||
*.qm
|
||||
.#*
|
||||
*.*#
|
||||
core
|
||||
!core/
|
||||
tags
|
||||
.DS_Store
|
||||
.directory
|
||||
*.debug
|
||||
Makefile*
|
||||
*.prl
|
||||
*.app
|
||||
moc_*.cpp
|
||||
ui_*.h
|
||||
qrc_*.cpp
|
||||
Thumbs.db
|
||||
*.res
|
||||
*.rc
|
||||
/.qmake.cache
|
||||
/.qmake.stash
|
||||
|
||||
# qtcreator generated files
|
||||
*.pro.user*
|
||||
|
||||
# xemacs temporary files
|
||||
*.flc
|
||||
|
||||
# Vim temporary files
|
||||
.*.swp
|
||||
|
||||
# Visual Studio generated files
|
||||
*.ib_pdb_index
|
||||
*.idb
|
||||
*.ilk
|
||||
*.pdb
|
||||
*.sln
|
||||
*.suo
|
||||
*.vcproj
|
||||
*vcproj.*.*.user
|
||||
*.ncb
|
||||
*.sdf
|
||||
*.opensdf
|
||||
*.vcxproj
|
||||
*vcxproj.*
|
||||
|
||||
# MinGW generated files
|
||||
*.Debug
|
||||
*.Release
|
||||
|
||||
# Python byte code
|
||||
*.pyc
|
||||
|
||||
# Binaries
|
||||
# --------
|
||||
*.dll
|
||||
*.exe
|
||||
|
After Width: | Height: | Size: 4.2 KiB |
@ -0,0 +1,43 @@
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
# You can make your code fail to compile if it uses deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
||||
|
||||
##
|
||||
## Name
|
||||
##
|
||||
TARGET = UnknownField-gui
|
||||
|
||||
##
|
||||
## ICO
|
||||
##
|
||||
RC_ICONS = NewWorld.ico
|
||||
|
||||
##
|
||||
## RESOURCES
|
||||
##
|
||||
RESOURCES += QDarkStyleSheet/qdarkstyle/dark/style.qrc
|
||||
RESOURCES += QDarkStyleSheet/qdarkstyle/light/style.qrc
|
||||
RESOURCES += QDarkStyleSheet/qdarkstyle/X64DBGDark/style.qrc
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
#include "mainwindow.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
|
||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||
#endif
|
||||
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
|
||||
QFile f(":/qdarkstyle/dark/style.qss");
|
||||
if (!f.exists()) {
|
||||
printf("Unable to set stylesheet, file not found\n");
|
||||
} else {
|
||||
f.open(QFile::ReadOnly | QFile::Text);
|
||||
QTextStream ts(&f);
|
||||
qApp->setStyleSheet(ts.readAll());
|
||||
}
|
||||
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
@ -0,0 +1,126 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <QProcess>
|
||||
#include <QTextStream>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::MainWindow), mQStringFilename("") {
|
||||
ui->setupUi(this);
|
||||
|
||||
setDefaultDisposition();
|
||||
setDefaultComponent();
|
||||
|
||||
// signal-slot
|
||||
connect(mQPushButtonRun, SIGNAL(clicked()), this, SLOT(qPushButtonRunSlot()));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() { delete ui; }
|
||||
|
||||
void MainWindow::setDefaultComponent() {
|
||||
|
||||
mQLabelExternalInclude = new QLabel("External include directory");
|
||||
ui->verticalLayout_frame_top->addWidget(mQLabelExternalInclude);
|
||||
mQTextEditExternalInclude = new QTextEdit();
|
||||
ui->verticalLayout_frame_top->addWidget(mQTextEditExternalInclude);
|
||||
|
||||
mQLabelSourceFile = new QLabel("Source file");
|
||||
ui->verticalLayout_frame_middle->addWidget(mQLabelSourceFile);
|
||||
|
||||
mQTextEditSourceFile = new QTextEdit();
|
||||
QFont qFont("Courier", 8);
|
||||
qFont.setStyleHint(QFont::Monospace);
|
||||
qFont.setBold(true);
|
||||
qFont.setFixedPitch(true);
|
||||
mQTextEditSourceFile->setFont(qFont);
|
||||
ui->verticalLayout_frame_middle->addWidget(mQTextEditSourceFile);
|
||||
|
||||
mQPushButtonRun = new QPushButton("Run");
|
||||
ui->verticalLayout_frame_middle->addWidget(mQPushButtonRun);
|
||||
|
||||
mQLabelLog = new QLabel("Log");
|
||||
ui->verticalLayout_frame_bottom->addWidget(mQLabelLog);
|
||||
mQTextEditLog = new QTextEdit();
|
||||
mQTextEditLog->setReadOnly(true);
|
||||
mQTextEditLog->setUndoRedoEnabled(false);
|
||||
ui->verticalLayout_frame_bottom->addWidget(mQTextEditLog);
|
||||
}
|
||||
|
||||
void MainWindow::setDefaultDisposition() {
|
||||
int iHeight0 = ui->splitter->widget(0)->size().height();
|
||||
int iHeight1 = ui->splitter->widget(1)->size().height();
|
||||
int iHeight2 = ui->splitter->widget(2)->size().height();
|
||||
int iTotalHeight = iHeight0 + iHeight1 + iHeight2;
|
||||
|
||||
QList<int> qListSizes;
|
||||
// 20%
|
||||
qListSizes.append(iTotalHeight * 20 / 100);
|
||||
// 70%
|
||||
qListSizes.append(iTotalHeight * 70 / 100);
|
||||
// 10%
|
||||
qListSizes.append(iTotalHeight * 10 / 100);
|
||||
ui->splitter->setSizes(qListSizes);
|
||||
}
|
||||
|
||||
void MainWindow::readSourceFileIntoTextEdit(QString filename) {
|
||||
// clean content first
|
||||
mQTextEditSourceFile->setText(QString(""));
|
||||
|
||||
QFile qFile(filename);
|
||||
if (!qFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
QMessageBox::information(nullptr, QString("Error"),
|
||||
QString("Open file failed!"));
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream qTextStream(&qFile);
|
||||
while (!qTextStream.atEnd()) {
|
||||
QString qsLine = qTextStream.readLine();
|
||||
mQTextEditSourceFile->append(qsLine);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::qPushButtonRunSlot() {
|
||||
if (mQStringFilename.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
QProcess qProcess;
|
||||
QString qsCmd = "UnknownField-cli.exe ";
|
||||
qsCmd += mQStringFilename;
|
||||
QString qsExternalInclude = mQTextEditExternalInclude->toPlainText();
|
||||
if (qsExternalInclude.length() != 0) {
|
||||
QStringList qsList =
|
||||
qsExternalInclude.split(QRegExp("[\n|;]"), QString::SkipEmptyParts);
|
||||
qsCmd += " --";
|
||||
for (int i = 0; i < qsList.size(); ++i) {
|
||||
QString qsInc = qsList[i].trimmed();
|
||||
if (qsInc.length() > 0) {
|
||||
qsCmd += " -I";
|
||||
qsCmd += "\"";
|
||||
qsCmd += qsInc;
|
||||
qsCmd += "\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
qProcess.start(qsCmd);
|
||||
qProcess.waitForFinished();
|
||||
mQTextEditLog->append(qProcess.readAllStandardError());
|
||||
mQTextEditLog->append(qProcess.readAllStandardOutput());
|
||||
readSourceFileIntoTextEdit(mQStringFilename);
|
||||
}
|
||||
|
||||
void MainWindow::on_actionOpen_triggered() {
|
||||
QString qsFilename = QFileDialog::getOpenFileName(
|
||||
this, "Open file", 0, "Source file (*.h *.hpp *.c *.cpp *.cc)");
|
||||
if (qsFilename.length() == 0) {
|
||||
return;
|
||||
}
|
||||
qsFilename = QDir::toNativeSeparators(qsFilename);
|
||||
// Set mQStringFilename
|
||||
mQStringFilename = qsFilename;
|
||||
|
||||
readSourceFileIntoTextEdit(qsFilename);
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QLabel>
|
||||
#include <QMainWindow>
|
||||
#include <QPushButton>
|
||||
#include <QTextEdit>
|
||||
#include <QWidget>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow {
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
public:
|
||||
void setDefaultDisposition();
|
||||
void setDefaultComponent();
|
||||
void readSourceFileIntoTextEdit(QString filename);
|
||||
private slots:
|
||||
void on_actionOpen_triggered();
|
||||
void qPushButtonRunSlot();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
QString mQStringFilename;
|
||||
|
||||
QLabel *mQLabelExternalInclude;
|
||||
QTextEdit *mQTextEditExternalInclude;
|
||||
|
||||
QLabel *mQLabelSourceFile;
|
||||
QTextEdit *mQTextEditSourceFile;
|
||||
QPushButton *mQPushButtonRun;
|
||||
|
||||
QLabel *mQLabelLog;
|
||||
QTextEdit *mQTextEditLog;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>UnknownField</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QFrame" name="frame_top">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_frame_top"/>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_middle">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_frame_middle"/>
|
||||
</widget>
|
||||
<widget class="QFrame" name="frame_bottom">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_frame_bottom"/>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
<property name="title">
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionOpen"/>
|
||||
</widget>
|
||||
<addaction name="menuFile"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<action name="actionOpen">
|
||||
<property name="text">
|
||||
<string>Open</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>F3</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Loading…
Reference in new issue