diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..a1bfca487de9aff676362989ca2cb0cd76fdc941 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.15) +project(restool) +set(CMAKE_CXX_STANDARD 17) +if (WIN32) +set(CMAKE_EXE_LINKER_FLAGS "-static -s") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fstack-protector -DLIBXML_STATIC -Wno-attributes") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fstack-protector -Wno-attributes") +elseif (APPLE) +set(CMAKE_EXE_LINKER_FLAGS "-fPIE -pie -static-libgcc -static-libstdc++") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fstack-protector -O2 -g -Wall") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fstack-protector") +else() +set(CMAKE_EXE_LINKER_FLAGS "-Wl,-z,relro,-z,now -fPIE -pie -Wl,-z,noexecstack -s -static-libgcc -static-libstdc++") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -fstack-protector -O2 -g -Wall") +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC -fstack-protector") +endif() + +set(jsoncpp_dir ${CMAKE_SOURCE_DIR}/../../third_party/jsoncpp) +set(bound_checking_function_dir ${CMAKE_SOURCE_DIR}/../../third_party/bounds_checking_function) +set(libxml2_dir ${CMAKE_SOURCE_DIR}/../../third_party/libxml2) +set(sqlite3_dir ${CMAKE_SOURCE_DIR}/../../third_party/sqlite) +include_directories(include) +include_directories(${jsoncpp_dir}/include) +include_directories(${bound_checking_function_dir}/include) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/third_party/libxml2/libxml2/include) +include_directories(${sqlite3_dir}/include) + +aux_source_directory(src restool_source) +aux_source_directory(src/xml restool_source) + +add_executable(restool ${restool_source}) +target_link_libraries(restool myxml2 jsoncpp securec sqlite3) + +add_subdirectory(third_party/libxml2) +add_subdirectory(third_party/jsoncpp) +add_subdirectory(third_party/bounds_checking_function) +add_subdirectory(third_party/sqlite3) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..261eeb9e9f8b2b4b0d119366dda99c6fd7d35c64 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.en.md b/README.en.md index 2db917798db5bf5e6001a8c2971352fb65fbad6b..446e80c2fa8349aa41f9fe6baff5937c5f9cb003 100644 --- a/README.en.md +++ b/README.en.md @@ -1,22 +1,31 @@ # global_resource_tool #### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} +OpenHarmony resource compile tool #### Software Architecture -Software architecture description +>developtools/ +>>----global_resource_tool +>>>----include +>>>----src +>>>----third_party denpence third patry lib make script +>>>----CMakeLists.txt +>>>----win32.cmake windows cross compile script #### Installation -1. xxxx -2. xxxx -3. xxxx +1. gcc/g++ version 9.3.0 +2. cmake version mini 3.15 +3. mkdir build +4. cd build +5. cmake ../restool_standard +6. make +7. compile result restool binary #### Instructions -1. xxxx -2. xxxx -3. xxxx +1. restool -v show version. +2. restool show help. #### Contribution diff --git a/README.md b/README.md index 84e2442778879e762fbf4df2c2017fde84421463..77f5475a3df9f9bbc2d27b2a64f74aee32a1e601 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,32 @@ # global_resource_tool #### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +OpenHarmony 资源编译编译工具 #### 软件架构 -软件架构说明 +>developtools/ +>>----global_resource_tool +>>>----include +>>>----src +>>>----third_party 依赖三方库编译脚本 +>>>----CMakeLists.txt +>>>----win32.cmake windows交叉编译脚本 #### 安装教程 -1. xxxx -2. xxxx -3. xxxx +1. 编译环境gcc/g++ 9.3.0 +2. cmake 版本最低3.15 +3. 与global_resource_tool同级目录新建build +4. cd build +5. cmake ../global_resource_tool +6. make +7. 编译结果输出restool #### 使用说明 -1. xxxx -2. xxxx -3. xxxx +1. restool -v 显示版本信息 +2. restool 显示帮助信息 #### 参与贡献 diff --git a/include/cmd_list.h b/include/cmd_list.h new file mode 100644 index 0000000000000000000000000000000000000000..51892d7d6585569b83482fa21cccf4a95e5ca7e8 --- /dev/null +++ b/include/cmd_list.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_CMD_LIST_H +#define OHOS_RESTOOL_CMD_LIST_H + +#include +#include +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class CmdList { +public: + CmdList() {}; + virtual ~CmdList() {}; + using HandleBack = std::function; + uint32_t Init(const std::string &filePath, HandleBack callback); +private: + uint32_t GetString(const Json::Value &node, int c, HandleBack callback); + uint32_t GetArray(const Json::Value &node, int c, HandleBack callback); + uint32_t GetModuleNames(const Json::Value &node, HandleBack callback); +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/cmd_parser.h b/include/cmd_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..1f120fbee4e9eb95e8f16df4e286bc8179634893 --- /dev/null +++ b/include/cmd_parser.h @@ -0,0 +1,139 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_CMD_PARSER_H +#define OHOS_RESTOOL_CMD_PARSER_H + +#include +#include +#include +#include +#include "singleton_object.h" +#include "resource_data.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ICmdParser { +public: + virtual uint32_t Parse(int argc, char *argv[]) = 0; +}; + +class PackageParser : public ICmdParser { +public: + PackageParser() {}; + ~PackageParser() = default; + uint32_t Parse(int argc, char *argv[]) override; + const std::vector &GetInputs() const; + const std::string &GetPackageName() const; + const std::string &GetOutput() const; + const std::vector &GetResourceHeaders() const; + bool GetForceWrite() const; + const std::vector &GetModuleNames() const; + const std::string &GetConfig() const; + const std::string &GetRestoolPath() const; + int32_t GetStartId() const; + const std::string &GetCachePath() const; + bool IsFileList() const; + bool GetPreviewMode() const; + int32_t GetPriority() const; + +private: + void InitCommand(); + uint32_t ParseCommand(int argc, char *argv[]); + uint32_t AddInput(const std::string& argValue); + uint32_t AddPackageName(const std::string& argValue); + uint32_t AddOutput(const std::string& argValue); + uint32_t AddResourceHeader(const std::string& argValue); + uint32_t ForceWrite(); + uint32_t PrintVersion(); + uint32_t AddMoudleNames(const std::string& argValue); + uint32_t AddConfig(const std::string& argValue); + uint32_t AddStartId(const std::string& argValue); + uint32_t AddCachePath(const std::string& argValue); + uint32_t CheckParam() const; + uint32_t HandleProcess(int c, const std::string& argValue); + uint32_t ParseFileList(const std::string& fileListPath); + uint32_t SetPreviewMode(); + uint32_t SetPriority(const std::string& argValue); + + static const struct option CMD_OPTS[]; + static const std::string CMD_PARAMS; + using HandleArgValue = std::function; + std::map handles_; + std::vector inputs_; + std::string packageName_; + std::string output_; + std::vector resourceHeaderPaths_; + bool forceWrite_ = false; + std::vector moduleNames_; + std::string configPath_; + std::string restoolPath_; + int32_t startId_ = 0; + std::string cachePath_; + bool isFileList_ = false; + bool previewMode_ = false; + int32_t priority_ = -1; +}; + +template +class CmdParser : public Singleton> { +public: + T &GetCmdParser(); + uint32_t Parse(int argc, char *argv[]); + static void ShowUseage(); + +private: + T cmdParser_; +}; + +template +void CmdParser::ShowUseage() +{ + std::cout << "This is an OHOS Packaging Tool.\n"; + std::cout << "Useage:\n"; + std::cout << TOOL_NAME << " [arguments] Package the OHOS resources.\n"; + std::cout << "[arguments]:\n"; + std::cout << " -i input resource path, can add more.\n"; + std::cout << " -p package name.\n"; + std::cout << " -o output path.\n"; + std::cout << " -r resource header file path(like ./ResourceTable.js, ./ResrouceTable.h).\n"; + std::cout << " -f if output path exists,force delete it.\n"; + std::cout << " -v print tool version.\n"; + std::cout << " -m module name, can add more, split by ','(like entry1,entry2,...).\n"; + std::cout << " -j config.json path.\n"; + std::cout << " -e start id mask, e.g 0x01000000, in [0x01000000, 0x06FFFFFF),[0x08000000, 0x41FFFFFF)\n"; + std::cout << " -c increment compile cache directory path.\n"; +} + +template +T &CmdParser::GetCmdParser() +{ + return cmdParser_; +} + +template +uint32_t CmdParser::Parse(int argc, char *argv[]) +{ + if (cmdParser_.Parse(argc, argv) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} +} +} +} +#endif \ No newline at end of file diff --git a/include/config_parser.h b/include/config_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..7a5bdcf7c5b4452039b68f4bbf537cb3ddf71e5d --- /dev/null +++ b/include/config_parser.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_CONFIG_PARSER_H +#define OHOS_RESTOOL_CONFIG_PARSER_H + +#include +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ConfigParser { +public: + enum class ModuleType { + NONE = 0, + HAR = 1, + ENTRY = 2, + FEATURE = 3, + }; + + ConfigParser(); + explicit ConfigParser(const std::string &filePath); + virtual ~ConfigParser(); + uint32_t Init(); + const std::string &GetPackageName() const; + const std::string &GetModuleName() const; + ModuleType GetModuleType() const; + uint32_t ParseRefence(); + uint32_t Save(const std::string &filePath) const; + static void SetUseModule() { useModule_ = true; }; + static std::string GetConfigName() { return useModule_ ? MODULE_JSON : CONFIG_JSON; }; +private: + bool ParseModule(Json::Value &moduleNode); + bool ParseDistro(Json::Value &distroNode); + bool ParseRefImpl(Json::Value &parent, const std::string &key, Json::Value &node); + bool ParseJsonArrayRef(Json::Value &parent, const std::string &key, Json::Value &node); + bool ParseJsonStringRef(Json::Value &parent, const std::string &key, Json::Value &node); + bool GetRefIdFromString(std::string &value, bool &update, const std::string &match) const; + bool ParseModuleType(const std::string &type); + std::string filePath_; + std::string packageName_; + std::string moduleName_; + ModuleType moduleType_; + Json::Value rootNode_; + static const std::map MODULE_TYPES; + static const std::map JSON_STRING_IDS; + static const std::map JSON_ARRAY_IDS; + static bool useModule_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/factory_resource_compiler.h b/include/factory_resource_compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..e27f4f87edde366fda88169676085301413a8f34 --- /dev/null +++ b/include/factory_resource_compiler.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_FACTORY_RESOURCE_COMPILER_H +#define OHOS_RESTOOL_FACTORY_RESOURCE_COMPILER_H + +#include +#include "i_resource_compiler.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class FactoryResourceCompiler { +public: + static std::unique_ptr CreateCompiler(ResType type, const std::string &output); +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/file_manager.h b/include/file_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..6fd5f0fea7304f52b5e82149f2183c088799227d --- /dev/null +++ b/include/file_manager.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_FILE_MANAGER_H +#define OHOS_RESTOOL_FILE_MANAGER_H + +#include +#include "resource_data.h" +#include "resource_item.h" +#include "increment_manager.h" +#include "singleton_object.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class FileManager : public Singleton { +public: + uint32_t ScanModules(const std::vector &inputs, const std::string &output); + const std::map> &GetResources() const { return alls_; }; + void SetModuleName(const std::string &moduleName) { moduleName_ = moduleName; }; + uint32_t ScanIncrement(const std::string &output); + +private: + uint32_t ScanModule(const std::string &input, const std::string &output, + std::map> &resTypeOfDirs); + uint32_t MergeResourceItem(const std::map> &resourceInfos); + uint32_t ParseReference(const std::string &output, const std::vector &sxmlFolders); + bool NeedParseReferenceInSolidXml(ResType resType) const; + void FilterRefSolidXml(const std::string &output, std::vector &outputPaths, + const std::map> &resTypeOfDirs) const; + + // id, resource items + std::map> alls_; + std::string moduleName_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/generic_compiler.h b/include/generic_compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..08d36eb569e1eb2022c9947a96d12851b9905378 --- /dev/null +++ b/include/generic_compiler.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_GENERIC_COMPILER_H +#define OHOS_RESTOOL_GENERIC_COMPILER_H + +#include "i_resource_compiler.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class GenericCompiler : public IResourceCompiler { +public: + GenericCompiler(ResType type, const std::string &output); + virtual ~GenericCompiler(); +protected: + uint32_t CompileSingleFile(const FileInfo &fileInfo) override; + bool PostFile(const FileInfo &fileInfo); +private: + std::string GetOutputFilePath(const FileInfo &fileInfo) const; + bool IsIgnore(const FileInfo &fileInfo) const; + bool CopyFile(const FileInfo &fileInfo) const; + bool IsConvertToSolidXml(const FileInfo &fileInfo) const; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/header.h b/include/header.h new file mode 100644 index 0000000000000000000000000000000000000000..3b27361a4628fbd746dc99cc21f539868f84cb50 --- /dev/null +++ b/include/header.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_HEADER_H +#define OHOS_RESTOOL_HEADER_H + +#include +#include +#include +#include "id_worker.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class Header { +public: + static const std::string LICENSE_HEADER; + Header(const std::string &outputPath); + virtual ~Header(); + using HandleHeaderTail = std::function; + using HandleBody = std::function; + uint32_t Create(HandleHeaderTail headerHandler, HandleBody bodyHander, HandleHeaderTail tailHander) const; +private: + const std::string &outputPath_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/i_resource_compiler.h b/include/i_resource_compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..4fc882e97ac89a5bb444ba0e2f84d0df66612b03 --- /dev/null +++ b/include/i_resource_compiler.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_COMPILER_H +#define OHOS_RESTOOL_RESOURCE_COMPILER_H + +#include +#include "increment_manager.h" +#include "resource_data.h" +#include "resource_item.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class IResourceCompiler { +public: + IResourceCompiler(ResType type, const std::string &output); + virtual ~IResourceCompiler(); + uint32_t Compile(const std::vector &directoryInfos); + const std::map> &GetResult() const; + uint32_t Compile(const FileInfo &fileInfo); + void SetModuleName(const std::string &moduleName); + void SetPreviewMode(bool enable) { previewMode_ = enable; }; + +protected: + virtual uint32_t CompileSingleFile(const FileInfo &fileInfo); + bool MergeResourceItem(const ResourceItem &resourceItem); + bool IsXmlFile(const FileInfo &fileInfo) const; + bool HasConvertedToSolidXml(const FileInfo &fileInfo) const; + bool NeedIfConvertToSolidXml() const; + std::string GetOutputFolder(const DirectoryInfo &directoryInfo) const; + ResType type_; + std::string output_; + std::string moduleName_; + bool previewMode_ = false; + + // id, resource items + std::map> resourceInfos_; + // ResType, name, resourceItems + std::map, std::vector> nameInfos_; + +private: + uint32_t ConvertToSolidXml(const std::map> &setsByDirectory); + uint32_t PostCommit(); + void ListXmlFile(const std::vector &fileInfo, std::vector &xmlPaths) const; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/id_worker.h b/include/id_worker.h new file mode 100644 index 0000000000000000000000000000000000000000..5ed46ff100d74ce416dba687ba57d7f56e25e3b7 --- /dev/null +++ b/include/id_worker.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_ID_WORKER_H +#define OHOS_RESTOOL_ID_WORKER_H + +#include +#include +#include "singleton_object.h" +#include "resource_data.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class IdWorker : public Singleton { +public: + enum class ResourceIdCluster { + RES_ID_APP = 0, + RES_ID_SYS, + RES_ID_TYPE_MAX, + }; + + struct ResourceId { + int32_t id; + int32_t seq; + std::string type; + std::string name; + }; + + uint32_t Init(ResourceIdCluster type, int32_t start = 0x01000000); + int32_t GenerateId(ResType resType, const std::string &name); + std::vector GetHeaderId() const; + int32_t GetId(ResType resType, const std::string &name) const; + int32_t GetSystemId(ResType resType, const std::string &name) const; + bool IsValidName(const std::string &name) const; + bool PushCache(ResType resType, const std::string &name, int32_t id); + void PushDelId(int32_t id); + +private: + int32_t GenerateAppId(ResType resType, const std::string &name); + int32_t GenerateSysId(ResType resType, const std::string &name); + uint32_t InitIdDefined(); + uint32_t InitIdDefined(const std::string &filePath); + using ParseFunction = std::function; + void InitParser(); + bool ParseType(const Json::Value &type, ResourceId &resourceId); + bool ParseName(const Json::Value &name, ResourceId &resourceId); + bool ParseOrder(const Json::Value &order, ResourceId &resourceId); + bool PushResourceId(const ResourceId &resourceId); + bool IsValidSystemName(const std::string &name) const; + int32_t GetStartId(const Json::Value &root) const; + int32_t GetMaxId(int32_t startId) const; + int32_t appId_; + int32_t maxId_; + ResourceIdCluster type_; + std::map, int32_t> ids_; + std::map, ResourceId> definedIds_; + std::map handles_; + std::vector delIds_; + std::map, int32_t> cacheIds_; + static const int32_t START_SYS_ID; +}; +} +} +} +#endif diff --git a/include/increment_index.h b/include/increment_index.h new file mode 100644 index 0000000000000000000000000000000000000000..dfa4a6094a4d719056e062c55a7f1b21627b16f9 --- /dev/null +++ b/include/increment_index.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_INCREMENT_INDEX_H +#define OHOS_RESTOOL_INCREMENT_INDEX_H + +#include "resource_item.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class IncrementIndex { +public: + IncrementIndex(const std::string &indexPath, const std::vector &folder); + virtual ~IncrementIndex() {}; + bool Save(const std::map> &items) const; + bool Load(std::map> &items) const; + void SetSkipPaths(const std::vector &skipPaths); + + static const std::string INDEX_FILE; +private: + bool LoadIndex(const Json::Value &indexInfo, std::map> &items) const; + bool ParseResourceItem(const Json::Value &item, const std::string &filePath, ResourceItem &resourceItem) const; + bool GetResourceItemProp(const Json::Value &item, const std::string &key, std::string &value) const; + bool PushResourceItem(const ResourceItem &resourceItem, int32_t id, + std::map> &items) const; + bool IsIgnore(const std::string &filePath) const; + const std::string &indexPath_; + const std::vector &folder_; + std::vector skipPaths_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/increment_list.h b/include/increment_list.h new file mode 100644 index 0000000000000000000000000000000000000000..ea906c62863390efb77a36035ff56736761778cb --- /dev/null +++ b/include/increment_list.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_INCREMENT_LIST_H +#define OHOS_RESTOOL_INCREMENT_LIST_H + +#include +#include +#include "resource_data.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class IncrementList { +public: + struct FileIncrement : FileInfo { + bool isDeleted; + std::string rootPath; + std::string relativePath; + }; + IncrementList(const std::string &listPath, const std::vector &folder); + virtual ~IncrementList() {}; + bool Parse(std::vector &fileList) const; + + static const std::string RESTOOL_LIST_FILE; +private: + bool GetFromPath(const std::string &filePath, FileIncrement &info) const; + int32_t GetPriority(const std::string &filePath) const; + bool ParseSegment(const std::string &filePath, std::vector &segments) const; + bool IteratorArray(const Json::Value &array, std::function callback) const; + bool ParseArray(const Json::Value &array, std::vector &fileList, bool isDeleted) const; + const std::string &listPath_; + const std::vector &folder_; + enum PathSegment { + SEG_RESOURCE = 0, + SEG_LIMIT_KEY = 1, + SEG_FILE_CLUSTER = 2, + SEG_FILE_NAME =3, + SEG_MAX + }; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/increment_manager.h b/include/increment_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..918314d2da704eab03b2b3f431fafd44fc189890 --- /dev/null +++ b/include/increment_manager.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_INCREMENT_MANAGER_H +#define OHOS_RESTOOL_INCREMENT_MANAGER_H + +#include +#include "resource_util.h" +#include "resource_item.h" +#include "singleton_object.h" + +#include "increment_list.h" +#include "increment_index.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class IncrementManager : public Singleton { +public: + struct FileIncrement : FileInfo { + std::string extension; + std::string relativePath; + std::string inputPath; + int32_t priority; + }; + + struct ModuleInfo { + std::string rootPath; + std::vector fileIncrements; + }; + + virtual ~IncrementManager(); + uint32_t Init(const std::string &cachePath, const std::vector &folder, + const std::string &outputPath, const std::string &moduleName); + const std::map> &GetResourceItems() const { return items_; }; + const std::map> &GetScanDirs() const { return scanDirs_; }; + bool FirstIncrement() const { return firstIncrement_; }; + bool Enable() const { return enalbe_; }; + + static const std::string ID_JSON_FILE; +private: + bool InitIdJson(); + bool InitList(std::vector &dels) const; + bool ScanModules(const std::vector &dels); + void FlushId(); + bool SaveIdJson() const; + bool LoadIdJson(); + void PushScanDir(const std::map> &scanDirs); + void DeleteRawFile(std::vector &dels) const; + bool ClearSolidXml() const; + std::string cachePath_; + std::vector folder_; + std::string outputPath_; + std::string moduleName_; + std::map> items_; + std::map> scanDirs_; + bool enalbe_ = false; + bool firstIncrement_ = true; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/json_compiler.h b/include/json_compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..d561565d99fd990db0eaafe7513e6af02efe2f60 --- /dev/null +++ b/include/json_compiler.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_JSON_COMPILER_H +#define OHOS_RESTOOL_JSON_COMPILER_H + +#include +#include "i_resource_compiler.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class JsonCompiler : public IResourceCompiler { +public: + JsonCompiler(ResType type, const std::string &output); + virtual ~JsonCompiler(); +protected: + uint32_t CompileSingleFile(const FileInfo &fileInfo) override; +private: + void InitParser(); + bool ParseJsonArrayLevel(const Json::Value &arrayNode, const FileInfo &fileInfo); + bool ParseJsonObjectLevel(const Json::Value &objectNode, const FileInfo &fileInfo); + + using HandleResource = std::function; + bool HandleString(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleInteger(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleBoolean(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleColor(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleFloat(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleStringArray(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleIntegerArray(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandleTheme(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandlePattern(const Json::Value &objectNode, ResourceItem &resourceItem) const; + bool HandlePlural(const Json::Value &objectNode, ResourceItem &resourceItem) const; + + bool PushString(const std::string &value, ResourceItem &resourceItem) const; + bool CheckJsonStringValue(const Json::Value &valueNode, const ResourceItem &resourceItem) const; + bool CheckJsonIntegerValue(const Json::Value &valueNode, const ResourceItem &resourceItem) const; + using HandleValue = std::function&)>; + bool ParseValueArray(const Json::Value &objectNode, ResourceItem &resourceItem, + const std::vector &extra, HandleValue callback) const; + bool ParseParent(const Json::Value &objectNode, const ResourceItem &resourceItem, + std::vector &extra) const; + bool ParseAttribute(const Json::Value &arrayItem, const ResourceItem &resourceItem, + std::vector &values) const; + bool CheckPluralValue(const Json::Value &arrayItem, const ResourceItem &resourceItem) const; + std::map handles_; + static const std::string TAG_NAME; + static const std::string TAG_VALUE; + static const std::string TAG_PARENT; + static const std::string TAG_QUANTITY; + static const std::vector QUANTITY_ATTRS; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/key_manager.h b/include/key_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..5c5d00130daad02d5b25e4c77287244fe0a2f4e5 --- /dev/null +++ b/include/key_manager.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_KEY_MANAGER_H +#define OHOS_RESTOOL_KEY_MANAGER_H + +#include +#include "xml_key_node.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class KeyManager { +public: + KeyManager(); + virtual ~KeyManager() {}; + bool LoadKey(const std::string &keysPath); + bool SaveKey(const std::string &keysPath); + std::map> &GetKeys() { return keys_; }; +private: + std::map> keys_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/key_parser.h b/include/key_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..dcf99f4384d9d6ee04ab9ac3ba7064072fad73c9 --- /dev/null +++ b/include/key_parser.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_KEY_PARSER_H +#define OHOS_RESTOOL_KEY_PARSER_H + +#include +#include "resource_data.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class KeyParser { +public: + static bool Parse(const std::string &folderName, std::vector &keyparams); + +private: + typedef bool (*parse_key_founction)(const std::string &folderName, std::vector &keyparams); + static bool ParseMatch(const std::vector &keys, std::vector &keyparams, const std::vector &founctions); + static bool ParseMatchBySeq(const std::vector &keys, std::vector &keyparams, const std::vector &founctions); + + static bool ParseMccMnc(const std::string &folderName, std::vector &keyparams); + static bool ParseMcc(const std::string &folderName, std::vector &keyparams); + static bool ParseMnc(const std::string &folderName, std::vector &keyparams); + static bool ParseLSR(const std::string &folderName, std::vector &keyparams); + static bool ParseLanguage(const std::string &folderName, std::vector &keyparams); + static bool ParseScript(const std::string &folderName, std::vector &keyparams); + static bool ParseRegion(const std::string &folderName, std::vector &keyparams); + static bool ParseOrientation(const std::string &folderName, std::vector &keyparams); + static bool ParseDeviceType(const std::string &folderName, std::vector &keyparams); + static bool ParseNightMode(const std::string &folderName, std::vector &keyparams); + static bool ParseResolution(const std::string &folderName, std::vector &keyparams); + + static void PushMccMnc(const std::string &folderName, KeyType type, std::vector &keyparams); + static void PushLSR(const std::string &folderName, KeyType type, std::vector &keyparams); + static void PushValue(uint32_t value, KeyType type, std::vector &keyparams); + static const int32_t MCC_MNC_KEY_LENGHT = 3; + static const int32_t SCRIPT_LENGHT = 4; + static const int32_t MIN_REGION_LENGHT = 2; + static const int32_t MAX_REGION_LENGHT = 3; + static std::map> caches_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/module_combine.h b/include/module_combine.h new file mode 100644 index 0000000000000000000000000000000000000000..735180bf23938d46a5bf8e91ada76145b657dbe5 --- /dev/null +++ b/include/module_combine.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_FILE_COMBINE_H +#define OHOS_RESTOOL_FILE_COMBINE_H + +#include "resource_directory.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ModuleCombine { +public: + ModuleCombine(const std::string &modulePath, const std::string &outputPath); + virtual ~ModuleCombine() {}; + bool Combine(); + +private: + bool CombineDirectory(const DirectoryInfo &directoryInfo); + bool CombineSolidXml(const std::string &src, const std::string &dst, + const std::map &sxmlPaths); + const std::string &modulePath_; + const std::string &outputPath_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/nocopyable_object.h b/include/nocopyable_object.h new file mode 100644 index 0000000000000000000000000000000000000000..e104fac615f5de051bea648d58b2cc5b9953d257 --- /dev/null +++ b/include/nocopyable_object.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_NOCOPYABLE_OBJECT_H +#define OHOS_RESTOOL_NOCOPYABLE_OBJECT_H + +namespace OHOS { +namespace Global { +namespace Restool { +#define DISALLOW_COPY_AND_MOVE(className) \ + DISALLOW_COPY(className); \ + DISALLOW_MOVE(className) + +#define DISALLOW_COPY(className) \ + className(const className&) = delete; \ + className& operator=(const className&&) = delete + +#define DISALLOW_MOVE(className) \ + className(className&&) = delete; \ + className& operator=(className&&) = delete + +class NoCopyable { +protected: + NoCopyable() {}; + virtual ~NoCopyable() {}; + +private: + DISALLOW_COPY_AND_MOVE(NoCopyable); +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/preview_manager.h b/include/preview_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..92d8e5aaccc02a0982bc6e436f181910fa19a53b --- /dev/null +++ b/include/preview_manager.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_PREVIEW_MANAGER_H +#define OHOS_RESTOOL_PREVIEW_MANAGER_H + +#include +#include +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class PreviewManager { +public: + PreviewManager() {}; + virtual ~PreviewManager(); + uint32_t ScanModules(const std::vector &modulePaths, const std::string &output); + void SetPriority(int32_t priority) { priority_ = priority; }; +private: + bool ScanFile(const std::string &filePath, int32_t priority); + int32_t priority_ = -1; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/reference_parser.h b/include/reference_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..60e9e8fb6d0d019c490be8be3b4803eb4cdc64ed --- /dev/null +++ b/include/reference_parser.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_REFERENCE_PARSER_H +#define OHOS_RESTOOL_REFERENCE_PARSER_H + +#include "id_worker.h" +#include "resource_item.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ReferenceParser { +public: + ReferenceParser(); + virtual ~ReferenceParser(); + uint32_t ParseRefInSolidXml(const std::vector &solidXmlFolders) const; + uint32_t ParseRefInElement(std::map> &alls) const; + uint32_t ParseRefInString(std::string &value, bool &update) const; + uint32_t ParseRefInProfile(const std::string &output) const; + uint32_t ParseRefInJson(const std::string &filePath) const; +private: + bool ParseRefResourceItem(ResourceItem &resourceItem) const; + bool ParseRefResourceItemData(const ResourceItem &resourceItem, std::string &data, bool &update) const; + bool IsStringOfResourceItem(ResType resType) const; + bool IsArrayOfResourceItem(ResType resType) const; + bool IsNotElement(ResType resType) const; + bool ParseRefString(std::string &key) const; + bool ParseRefString(std::string &key, bool &update) const; + bool ParseRefImpl(std::string &key, const std::map &refs, bool isSystem) const; + bool ParseRefJsonImpl(Json::Value &root) const; + const IdWorker &idWorker_; + static const std::map ID_REFS; + static const std::map ID_OHOS_REFS; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_data.h b/include/resource_data.h new file mode 100644 index 0000000000000000000000000000000000000000..d714d213ee0f500f599fa85f6b2da314b601fba7 --- /dev/null +++ b/include/resource_data.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_DATA_H +#define OHOS_RESTOOL_RESOURCE_DATA_H + +#include +#include +#include + +namespace OHOS { +namespace Global { +namespace Restool { +const static std::string TOOL_NAME = "restool"; +const static std::string RESOURCES_DIR = "resources"; +const static std::string CONFIG_JSON = "config.json"; +const static std::string MODULE_JSON = "module.json"; +const static std::string RAW_FILE_DIR = "rawfile"; +const static std::string ID_DEFINED_FILE = "id_defined.json"; +const static std::string RESOURCE_INDEX_FILE = "resources.index"; +const static std::string SEPARATOR = "/"; +const static int32_t VERSION_MAX_LEN = 128; +static const int8_t RESTOOL_VERSION[VERSION_MAX_LEN] = { "Restool 2.007" }; +const static int32_t TAG_LEN = 4; + +enum class KeyType { + LANGUAGE = 0, + REGION = 1, + RESOLUTION = 2, + ORIENTATION = 3, + DEVICETYPE = 4, + SCRIPT = 5, + NIGHTMODE = 6, + MCC = 7, + MNC = 8, + KEY_TYPE_MAX, +}; + +enum class ResType { + ELEMENT = 0, + ANIMATION = 1, + LAYOUT = 3, + RAW = 6, + INTEGER = 8, + STRING = 9, + STRARRAY = 10, + INTARRAY = 11, + BOOLEAN = 12, + COLOR = 14, + ID = 15, + THEME = 16, + PLURAL = 17, + FLOAT = 18, + MEDIA = 19, + PROF = 20, + GRAPHIC = 21, + PATTERN = 22, + INVALID_RES_TYPE = -1, +}; + +enum class OrientationType { + VERTICAL = 0, + HORIZONTAL = 1, +}; + +const std::map g_orientaionMap = { + { "vertical", OrientationType::VERTICAL }, + { "horizontal", OrientationType::HORIZONTAL }, +}; + +enum class DeviceType { + PHONE = 0, + TABLET = 1, + CAR = 2, + // RESERVER 3 + TV = 4, + WEARABLE = 6, +}; + +const std::map g_deviceMap = { + { "phone", DeviceType::PHONE }, + { "tablet", DeviceType::TABLET }, + { "car", DeviceType::CAR }, + { "tv", DeviceType::TV }, + { "wearable", DeviceType::WEARABLE }, +}; + +enum class ResolutionType { + SDPI = 120, + MDPI = 160, + LDPI = 240, + XLDPI = 320, + XXLDPI = 480, + XXXLDPI = 640, +}; + +const std::map g_resolutionMap = { + { "sdpi", ResolutionType::SDPI }, + { "mdpi", ResolutionType::MDPI }, + { "ldpi", ResolutionType::LDPI }, + { "xldpi", ResolutionType::XLDPI }, + { "xxldpi", ResolutionType::XXLDPI }, + { "xxxldpi", ResolutionType::XXXLDPI }, +}; + +enum class NightMode { + DARK = 0, + LIGHT = 1, +}; + +const std::map g_nightModeMap = { + { "dark", NightMode::DARK }, + { "light", NightMode::LIGHT }, +}; + +struct KeyParam { + KeyType keyType; + uint32_t value; +}; + +const std::map g_fileClusterMap = { + { "element", ResType::ELEMENT }, + { "media", ResType::MEDIA }, + { "profile", ResType::PROF }, + { "animation", ResType::ANIMATION }, + { "graphic", ResType::GRAPHIC }, + { "layout", ResType::LAYOUT } +}; + +const std::map g_contentClusterMap = { + { "id", ResType::ID }, + { "integer", ResType::INTEGER }, + { "string", ResType::STRING }, + { "strarray", ResType::STRARRAY }, + { "intarray", ResType::INTARRAY }, + { "color", ResType::COLOR }, + { "plural", ResType::PLURAL }, + { "boolean", ResType::BOOLEAN }, + { "pattern", ResType::PATTERN }, + { "theme", ResType::THEME }, + { "float", ResType::FLOAT } +}; + +struct DirectoryInfo { + std::string limitKey; + std::string fileCluster; + std::string dirPath; + std::vector keyParams; + ResType dirType; +}; + +struct FileInfo : DirectoryInfo { + std::string filePath; + std::string filename; + ResType fileType; +}; +} +} +} +#endif diff --git a/include/resource_directory.h b/include/resource_directory.h new file mode 100644 index 0000000000000000000000000000000000000000..cf2d75bd722a0e9ca346aed13dd512ba12e0999d --- /dev/null +++ b/include/resource_directory.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_DIRECTORY +#define OHOS_RESTOOL_RESOURCE_DIRECTORY + +#include +#include +#include +#include "key_parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourceDirectory { +public: + ResourceDirectory() {}; + virtual ~ResourceDirectory() {}; + bool ScanResources(const std::string &resourcesDir, std::function callback) const; +private: + bool ScanResourceLimitKeyDir(const std::string &resourceTypeDir, const std::string &limitKey, + std::function callback) const; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_item.h b/include/resource_item.h new file mode 100644 index 0000000000000000000000000000000000000000..bf7a84235579e5565a5d42783bb3053443dd40b2 --- /dev/null +++ b/include/resource_item.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_ITEM_H +#define OHOS_RESTOOL_RESOURCE_ITEM_H + +#include +#include "resource_data.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourceItem { +public: + ResourceItem(); + ResourceItem(const ResourceItem &other); + ResourceItem(const std::string &name, const std::vector &keyparams, ResType type); + virtual ~ResourceItem(); + + bool SetData(const std::string &data); + bool SetData(const int8_t *data, uint32_t length); + void SetFilePath(const std::string &filePath); + void SetLimitKey(const std::string &limitKey); + + const int8_t *GetData() const; + const uint32_t GetDataLength() const; + const std::string &GetName() const; + const ResType &GetResType() const; + const std::vector &GetKeyParam() const; + const std::string &GetFilePath() const; + const std::string &GetLimitKey() const; + + ResourceItem &operator=(const ResourceItem &other); +private: + void ReleaseData(); + void CopyFrom(const ResourceItem &other); + int8_t *data_ = nullptr; + uint32_t dataLen_; + std::string name_; + std::vector keyparams_; + ResType type_; + std::string filePath_; + std::string limitKey_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_merge.h b/include/resource_merge.h new file mode 100644 index 0000000000000000000000000000000000000000..a6e792287818f480a02046a917fca4eaaf7d012a --- /dev/null +++ b/include/resource_merge.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_MERGE_H +#define OHOS_RESTOOL_RESOURCE_MERGE_H + +#include +#include +#include "config_parser.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourceMerge { +public: + ResourceMerge(); + virtual ~ResourceMerge(); + uint32_t Init(); + const std::vector &GetInputs() const; +private: + std::vector inputsOrder_; + static const std::vector ORDERS; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_module.h b/include/resource_module.h new file mode 100644 index 0000000000000000000000000000000000000000..61bdda153f7c1c43b5a68b59d31d5068d2b224e0 --- /dev/null +++ b/include/resource_module.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_MODULE_H +#define OHOS_RESTOOL_RESOURCE_MODULE_H + +#include "resource_item.h" +#include "resource_directory.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourceModule { +public: + ResourceModule(const std::string &modulePath, const std::string &moduleOutput, const std::string &moduleName); + virtual ~ResourceModule() {}; + uint32_t ScanResource(); + const std::map> &GetOwner() const; + const std::map> &GetScanDirectorys() const; + static uint32_t MergeResourceItem(std::map> &alls, + const std::map> &other, bool tipError = false); + void SetPreviewMode(bool enable) { previewMode_ = enable; }; + +protected: + const std::string &modulePath_; + const std::string &moduleOutput_; + const std::string &moduleName_; + std::map> owner_; + std::map> scanDirs_; + bool previewMode_ = false; +private: + void Push(const std::map> &other); + static const std::vector SCAN_SEQ; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_module_inc.h b/include/resource_module_inc.h new file mode 100644 index 0000000000000000000000000000000000000000..9998579dfae0f37df59f87fbe47fde6e789740a1 --- /dev/null +++ b/include/resource_module_inc.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_MODULE_INC_H +#define OHOS_RESTOOL_RESOURCE_MODULE_INC_H + +#include "increment_list.h" +#include "resource_module.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourceModuleInc : public ResourceModule { +public: + ResourceModuleInc(const std::string &modulePath, const std::string &moduleOutput, const std::string &moduleName, const std::vector &folder); + virtual ~ResourceModuleInc() {}; + uint32_t ScanResource(const std::vector &fileIncrements); + uint32_t SaveIndex() const; +private: + const std::vector &folder_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_pack.h b/include/resource_pack.h new file mode 100644 index 0000000000000000000000000000000000000000..968a109fe5ec1f5623b0a3e087496214401fcdb4 --- /dev/null +++ b/include/resource_pack.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_PACK_H +#define OHOS_RESTOOL_RESOURCE_PACK_H + +#include "cmd_parser.h" +#include "config_parser.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourcePack { +public: + explicit ResourcePack(const PackageParser &packageParser); + virtual ~ResourcePack() = default; + uint32_t Package(); + +private: + uint32_t Init(); + uint32_t InitModule(); + void InitHeaderCreater(); + uint32_t InitOutput() const; + uint32_t GenerateHeader() const; + uint32_t InitConfigJson(); + uint32_t GenerateTextHeader(const std::string &headerPath) const; + uint32_t GenerateCplusHeader(const std::string &headerPath) const; + uint32_t GenerateJsHeader(const std::string &headerPath) const; + uint32_t CopyRawFile(const std::vector &inputs) const; + uint32_t CopyRawFileImpl(const std::string &src, const std::string &dst) const; + uint32_t GenerateConfigJson(); + uint32_t ScanResources(const std::vector &inputs, const std::string &output); + PackageParser packageParser_; + std::string moduleName_; + using HeaderCreater = std::function; + std::map headerCreaters_; + ConfigParser configJson_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_table.h b/include/resource_table.h new file mode 100644 index 0000000000000000000000000000000000000000..232f369fbf134dc86a6998f9beff0604ced27d37 --- /dev/null +++ b/include/resource_table.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_TABLE_H +#define OHOS_RESTOOL_RESOURCE_TABLE_H + +#include +#include "resource_item.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class ResourceTable { +public: + ResourceTable(); + virtual ~ResourceTable(); + uint32_t CreateResourceTable(); +private: + struct TableData { + int32_t id; + ResourceItem resourceItem; + }; + + struct IndexHeader { + int8_t version[VERSION_MAX_LEN]; + uint32_t fileSize; + uint32_t limitKeyConfigSize; + }; + + struct LimitKeyConfig { + int8_t keyTag[TAG_LEN] = {'K', 'E', 'Y', 'S'}; + uint32_t offset; // IdSet file address offset + uint32_t keyCount; // KeyParam count + std::vector data; + }; + + struct IdSet { + int8_t idTag[TAG_LEN] = {'I', 'D', 'S', 'S'}; + uint32_t idCount; + std::map data; // pair id and offset + }; + + struct RecordItem { + uint32_t size; + int32_t resType; + int32_t id; + }; + uint32_t SaveToResouorceIndex(const std::map> &configs) const; + bool InitIndexHeader(IndexHeader &indexHeader, uint32_t count) const; + bool Prepare(const std::map> &configs, + std::map &limitKeyConfigs, + std::map &idSets, uint32_t &pos) const; + bool SaveRecordItem(const std::map> &configs, std::ofstream &out, + std::map &idSets, uint32_t &pos) const; + void SaveHeader(const IndexHeader &indexHeader, std::ofstream &out) const; + void SaveLimitKeyConfigs(const std::map &limitKeyConfigs, std::ofstream &out) const; + void SaveIdSets(const std::map &idSets, std::ofstream &out) const; + std::string indexFilePath_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/resource_util.h b/include/resource_util.h new file mode 100644 index 0000000000000000000000000000000000000000..b5698f60008cbe54d40a8497f60b4d9d3dc6a5b2 --- /dev/null +++ b/include/resource_util.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_RESOURCE_UTIL_H +#define OHOS_RESTOOL_RESOURCE_UTIL_H + +#include +#include +#include "resource_data.h" +#include "json/json.h" + +namespace OHOS { +namespace Global { +namespace Restool { + +class ResourceUtil { +public: + /** + * @brief split the string with given splitter. + * @param str: input string. + * @param out: the array of strings computed by splitter. + * @param splitter: the split string. + */ + static void Split(const std::string &str, std::vector &out, const std::string &splitter); + + /** + * @brief check file exist. + * @param path: file path. + * @return true if exist, other false. + */ + static bool FileExist(const std::string &path); + + /** + * @brief remove all files in the directory. + * @param path: input directory. + * @return true if remove success, other false. + */ + static bool RmoveAllDir(const std::string &path); + + /** + * @brief open json file. + * @param path: json file path. + * @param root: json root node + * @return true if open success, other false. + */ + static bool OpenJsonFile(const std::string &path, Json::Value &root); + + /** + * @brief save json file. + * @param path: json file path. + * @param root: json root node + * @return true if save success, other false. + */ + static bool SaveToJsonFile(const std::string &path, const Json::Value &root); + + /** + * @brief get resource type from directory. + * @param name: directory name. + * @return resrouce type. + */ + static ResType GetResTypeByDir(const std::string &name); + + /** + * @brief ResType to string + * @param type: ResType + * @return resrouce type string. + */ + static std::string ResTypeToString(ResType type); + + /** + * @brief get id name + * @param name; id name or file name + * @param type: ResType + * @return return id name. + */ + static std::string GetIdName(const std::string &name, ResType type); + + /** + * @brief compose multi strings to string + * @param contents: multi strings + * @param addNull: if true, string length contains '\0'. + * @return return string, empty if error + */ + static std::string ComposeStrings(const std::vector &contents, bool addNull = false); + + /** + * @brief decompose string to multi strings + * @param content: string + * @return return string vector, empty if error + */ + static std::vector DecomposeStrings(const std::string &content); + + /** + * @brief string to ResType + * @param type: string + * @return return ResType + */ + static ResType GetResTypeFromString(const std::string &type); + + /** + * @brief copy file + * @param src: source file path + * @param dst: destination file path + * @return true if success, other false + */ + static bool CopyFleInner(const std::string &src, const std::string &dst); + + /** + * @brief create directorys + * @param filePath: directory path + * @return true if success, other false + */ + static bool CreateDirs(const std::string &filePath); + + /** + * @brief ignore file or directory + * @param filename: file or directory name + * @return true if ignore, other false + */ + static bool IsIgnoreFile(const std::string &filename, std::filesystem::file_type type); + + /** + * @brief need convert to solid xml + * @param resType: ResType + * @return true if need, other false + */ + static bool NeedConverToSolidXml(ResType resType); + + /** + * @brief generate hash string + * @param key: string + * @return hash string + */ + static std::string GenerateHash(const std::string key); +private: + enum class IgnoreType { + IGNORE_FILE, + IGNORE_DIR, + IGNORE_ALL + }; + static const std::map IGNORE_FILE_REGEX; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/restool_errors.h b/include/restool_errors.h new file mode 100644 index 0000000000000000000000000000000000000000..372dad3e218af0c1512febce7db16a64c3472612 --- /dev/null +++ b/include/restool_errors.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_ERRORS_H +#define OHOS_RESTOOL_ERRORS_H + +#include + +namespace OHOS { +namespace Global { +namespace Restool { +constexpr uint32_t RESTOOL_SUCCESS = 0; +constexpr uint32_t RESTOOL_ERROR = -1; +} +} +} +#endif \ No newline at end of file diff --git a/include/singleton_object.h b/include/singleton_object.h new file mode 100644 index 0000000000000000000000000000000000000000..103412b4a123f052758b44b3c82bac0f9a179bb7 --- /dev/null +++ b/include/singleton_object.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_SINGLETON_OBJECT_H +#define OHOS_RESTOOL_SINGLETON_OBJECT_H + +#include "nocopyable_object.h" + +namespace OHOS { +namespace Global { +namespace Restool { +template +class Singleton : public NoCopyable { +public: + static T &GetInstance() + { + return instance_; + } + +private: + static T instance_; +}; + +template +T Singleton::instance_; +} +} +} +#endif \ No newline at end of file diff --git a/include/solid_xml.h b/include/solid_xml.h new file mode 100644 index 0000000000000000000000000000000000000000..b7365ed970ea9777374093238c32fb792664dd34 --- /dev/null +++ b/include/solid_xml.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_SOLID_XML_H +#define OHOS_RESTOOL_SOLID_XML_H + +#include +#include +#include +#include +#include "libxml/parser.h" +#include "xml_key_node.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class SolidXml { +public: + explicit SolidXml(const std::string &xmlPath, std::map> &keys); + virtual ~SolidXml(); + bool GenerateSolidXml(const std::string &filePath); + bool FlushNodeKeys(const std::string &filePath, + std::map> &newKeys); +private: + class Node { + public: + Node(): name_(-1), value_(-1), nameSpace_(-1) {}; + virtual ~Node() {}; + virtual void RawData(std::ofstream &out) const; + virtual bool LoadFrom(std::ifstream &in); + virtual bool FlushIndex(const std::map> &oldKeys, + std::map> &newKeys); + void SetName(int32_t index) { name_ = index; }; + void SetValue(int32_t index) { value_ = index; }; + void SetNameSpace(int32_t index) { nameSpace_ = index; }; + protected: + int32_t name_; + int32_t value_; + int32_t nameSpace_; + }; + + class XmlNode : public Node { + public: + XmlNode() : child_(-1), brother_(-1) {}; + virtual ~XmlNode() {}; + void RawData(std::ofstream &out) const override; + bool LoadFrom(std::ifstream &in) override; + bool FlushIndex(const std::map> &oldKeys, + std::map> &newKeys) override; + void SetChild(int32_t index) { child_ = index; }; + void SetBrother(int32_t index) { brother_ = index; }; + void AddAttribute(int32_t index) { attributes_.push_back(index); }; + private: + int32_t child_; + int32_t brother_; + std::vector attributes_; + }; + + void Compile(const xmlNodePtr nodePtr, std::shared_ptr &node); + void CompileAttr(const xmlAttrPtr attrPtr, std::shared_ptr &node); + void CompileNameSpace(const xmlNodePtr nodePtr, std::shared_ptr &node); + void AddNampeSpaceDef(int32_t nameSpace, int32_t href); + bool SaveToFile(const std::string &filePath) const; + void PretreatmentAttr(std::string &value) const; + bool LoadFromFile(const std::string &sxmlPath); + static bool ChangeToNewKey(const std::map> &oldKeys, + std::map> &newKeys, + XmlKeyNode::KeyType keyType, int32_t &keyId); + bool FlushXmlnsKey(std::map> &newKeys); + const std::string &xmlPath_; + std::map> &keys_; + std::vector> attributes_; + std::vector> nodes_; + std::vector nameSpaces_; + std::vector hrefs_; + + static const uint8_t SOLID_XML_MAGIC[]; + static const uint32_t SOLID_XML_MAGIC_LENGTH; + #define CHECK_IO(stream) \ + if (!stream) { \ + return false; \ + } +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/solid_xml_compiler.h b/include/solid_xml_compiler.h new file mode 100644 index 0000000000000000000000000000000000000000..b2b9044fcd2962f5a8a34bae229b432f662a0b2c --- /dev/null +++ b/include/solid_xml_compiler.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_SOLID_XML_COMPILER_H +#define OHOS_RESTOOL_SOLID_XML_COMPILER_H + +#include "generic_compiler.h" +#include "libxml/parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class SolidXmlCompiler : public GenericCompiler { +public: + SolidXmlCompiler(ResType type, const std::string &output); + virtual ~SolidXmlCompiler(); +protected: + uint32_t CompileSingleFile(const FileInfo &fileInfo) override; +private: + bool ParseXml(const FileInfo &fileInfo); + bool ParseNodeId(const FileInfo &fileInfo, const xmlNodePtr &node, std::vector &ids); +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/sqlite_database.h b/include/sqlite_database.h new file mode 100644 index 0000000000000000000000000000000000000000..08c511ba0809c80b51476fb9a3a5c5b87cf3ad63 --- /dev/null +++ b/include/sqlite_database.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_SQLITE_DATABASE_H +#define OHOS_RESTOOL_SQLITE_DATABASE_H + +#include +#include "resource_item.h" +#include "singleton_object.h" +#include "sqlite3.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class SqliteDatabase : public Singleton { +public: + void Init(const std::string &dbPath); + bool OpenDatabase(); + void CloseDatabase(); + bool Insert(const ResourceItem &resourceItem); + void SetPriority(int32_t priority) { priority_ = priority; }; +private: + bool Query(const ResourceItem &resourceItem, int32_t &id); + bool FindMaxId(); + bool CreateTable(); + std::string GetValue(const ResourceItem &resourceItem) const; + std::string dbPath_; + sqlite3 * db_ = nullptr; + static int32_t id_; + int32_t priority_ = 0; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/task_handle.h b/include/task_handle.h new file mode 100644 index 0000000000000000000000000000000000000000..8100e9606971a29f37e90de6f59dc8710257076f --- /dev/null +++ b/include/task_handle.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_TASK_HANDLE_H +#define OHOS_RESTOOL_TASK_HANDLE_H + +#include "cmd_parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { + +class TaskHandle { +public: + TaskHandle() {}; + ~TaskHandle() {}; + uint32_t HandlePackage(const PackageParser &packageParser); +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/xml_converter.h b/include/xml_converter.h new file mode 100644 index 0000000000000000000000000000000000000000..94bc8fb052d4610d400ec7871ed5e0996eef8b46 --- /dev/null +++ b/include/xml_converter.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_XML_CONVERTER_H +#define OHOS_RESTOOL_XML_CONVERTER_H + +#include +#include +#include +#include "key_manager.h" + +namespace OHOS { +namespace Global { +namespace Restool { +class XmlConverter { +public: + XmlConverter(const std::vector &xmlPaths, const std::string &outputPath); + virtual ~XmlConverter(); + bool GenerateSolidXml(); + bool GenerateKey(); +private: + bool LoadKeys(const std::string &folderPath); + const std::vector &xmlPaths_; + const std::string &outputPath_; + KeyManager keyManager; +}; +} +} +} +#endif \ No newline at end of file diff --git a/include/xml_key_node.h b/include/xml_key_node.h new file mode 100644 index 0000000000000000000000000000000000000000..bc36d3c0bc004fbe1c69c3fcd95f9e0c3e8f5a73 --- /dev/null +++ b/include/xml_key_node.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OHOS_RESTOOL_XML_KEY_NODE_H +#define OHOS_RESTOOL_XML_KEY_NODE_H + +#include +#include +#include +#include + +namespace OHOS { +namespace Global { +namespace Restool { +class XmlKeyNode { +public: + XmlKeyNode(); + virtual ~XmlKeyNode(); + int32_t PushKey(const std::string &name); + bool SaveToFile(const std::string &filePath) const; + bool LoadFromFile(const std::string &filePath); + using RefParser = std::function; + bool LoadFromFile(const std::string &filePath, RefParser parser); + bool GetKeyValue(int32_t keyId, std::string &value) const; + + enum class KeyType { + NODE = 0, + ATTRIBUTE, + CONSTANT, + CONTENT, + END + }; + static const std::map KEY_TO_FILE_NAME; +private: + int32_t keyId_; + std::map keyMap_; +}; +} +} +} +#endif \ No newline at end of file diff --git a/src/cmd_list.cpp b/src/cmd_list.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de2e327587de8810d3cc6924529ac10c41eab8d8 --- /dev/null +++ b/src/cmd_list.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmd_list.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +uint32_t CmdList::Init(const string &filePath, function callback) +{ + Json::Value root; + if (!ResourceUtil::OpenJsonFile(filePath, root)) { + return RESTOOL_ERROR; + } + + if (!callback) { + return RESTOOL_SUCCESS; + } + + if (GetString(root["configPath"], 'j', callback) != RESTOOL_SUCCESS || + GetString(root["packageName"], 'p', callback) != RESTOOL_SUCCESS || + GetString(root["output"], 'o', callback) != RESTOOL_SUCCESS || + GetString(root["startId"], 'e', callback) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (GetModuleNames(root["moduleNames"], callback) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (GetArray(root["ResourceTable"], 'r', callback) != RESTOOL_SUCCESS || + GetString(root["applicationResource"], 'i', callback) != RESTOOL_SUCCESS || + GetArray(root["moduleResources"], 'i', callback) != RESTOOL_SUCCESS || + GetArray(root["dependencies"], 'i', callback) != RESTOOL_SUCCESS ) { + return RESTOOL_ERROR; + } + + callback('f', ""); + return RESTOOL_SUCCESS; +} + +// below private +uint32_t CmdList::GetString(const Json::Value &node, int c, HandleBack callback) +{ + if (!node.isString()) { + return RESTOOL_SUCCESS; + } + + if (callback(c, node.asString()) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +uint32_t CmdList::GetArray(const Json::Value &node, int c, HandleBack callback) +{ + if (!node.isArray()) { + return RESTOOL_SUCCESS; + } + + for (Json::ArrayIndex i = 0; i < node.size(); i++) { + if (!node[i].isString()) { + return RESTOOL_ERROR; + } + if (callback(c, node[i].asString()) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t CmdList::GetModuleNames(const Json::Value &node, HandleBack callback) +{ + string moduleNames; + if (GetArray(node, 'm', [&moduleNames](int c, const string &argValue) { + if (!moduleNames.empty()) { + moduleNames.append(","); + } + moduleNames.append(argValue); + return RESTOOL_SUCCESS; + }) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (!moduleNames.empty() && callback('m', moduleNames) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} +} +} +} \ No newline at end of file diff --git a/src/cmd_parser.cpp b/src/cmd_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3cfc29bd74ba2c0b5123cc3ce5a088a731fad975 --- /dev/null +++ b/src/cmd_parser.cpp @@ -0,0 +1,322 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmd_parser.h" +#include +#include "resource_util.h" + +#include "cmd_list.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const struct option PackageParser::CMD_OPTS[] = { + { "inputPath", required_argument, nullptr, 'i' }, + { "packageName", required_argument, nullptr, 'p' }, + { "outputPath", required_argument, nullptr, 'o' }, + { "resHeader", required_argument, nullptr, 'r' }, + { "forceWrite", no_argument, nullptr, 'f' }, + { "version", no_argument, nullptr, 'v'}, + { "modules", optional_argument, nullptr, 'm' }, + { "json", optional_argument, nullptr, 'j' }, + { "startId", optional_argument, nullptr, 'e' }, + { "cache", optional_argument, nullptr, 'c' }, + { "fileList", required_argument, nullptr, 'l' }, + { "preview", no_argument, nullptr, 'a' }, + { "priority", required_argument, nullptr, 'g' }, +}; + +const string PackageParser::CMD_PARAMS = "i:p:o:r:m:j:e:c:l:g:afv"; + +uint32_t PackageParser::Parse(int argc, char *argv[]) +{ + InitCommand(); + if (ParseCommand(argc, argv) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return CheckParam(); +} + +const vector &PackageParser::GetInputs() const +{ + return inputs_; +} + +const string &PackageParser::GetPackageName() const +{ + return packageName_; +} + +const string &PackageParser::GetOutput() const +{ + return output_; +} + +const vector &PackageParser::GetResourceHeaders() const +{ + return resourceHeaderPaths_; +} + +bool PackageParser::GetForceWrite() const +{ + return forceWrite_; +} + +const vector &PackageParser::GetModuleNames() const +{ + return moduleNames_; +} + +const string &PackageParser::GetConfig() const +{ + return configPath_; +} + +const string &PackageParser::GetRestoolPath() const +{ + return restoolPath_; +} + +int32_t PackageParser::GetStartId() const +{ + return startId_; +} + +const string &PackageParser::GetCachePath() const +{ + return cachePath_; +} + +uint32_t PackageParser::AddInput(const string& argValue) +{ + auto ret = find_if(inputs_.begin(), inputs_.end(), [argValue](auto iter) {return argValue == iter;}); + if (ret != inputs_.end()) { + cerr << "Error: repeat input '" << argValue << "'" << endl; + return RESTOOL_ERROR; + } + + inputs_.push_back(argValue); + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::AddPackageName(const string& argValue) +{ + if (!packageName_.empty()) { + cerr << "Error: double package name " << packageName_ << " vs " << argValue << endl; + return RESTOOL_ERROR; + } + + packageName_ = argValue; + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::AddOutput(const string& argValue) +{ + if (!output_.empty()) { + cerr << "Error: double output " << output_ << " vs " << argValue << endl; + return RESTOOL_ERROR; + } + + output_ = argValue; + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::AddResourceHeader(const string& argValue) +{ + if (find(resourceHeaderPaths_.begin(), resourceHeaderPaths_.end(), argValue) != resourceHeaderPaths_.end()) { + cerr << "Error: '" << argValue << "' input duplicated." << endl; + return RESTOOL_ERROR; + } + resourceHeaderPaths_.push_back(argValue); + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::ForceWrite() +{ + forceWrite_ = true; + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::PrintVersion() +{ + cout << "Info: Restool version= " << RESTOOL_VERSION << endl; + cout << "time = (" << __DATE__ << " " << __TIME__ << ")" << endl; + exit(RESTOOL_SUCCESS); + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::AddMoudleNames(const string& argValue) +{ + if (!moduleNames_.empty()) { + cerr << "Error: -m double module name '" << argValue << "'" << endl; + return RESTOOL_ERROR; + } + + ResourceUtil::Split(argValue, moduleNames_, ","); + for (auto it = moduleNames_.begin(); it != moduleNames_.end(); it++) { + auto ret = find_if(moduleNames_.begin(), moduleNames_.end(), [it](auto iter) {return *it == iter;}); + if (ret != it) { + cerr << "Error: double module name '" << *it << "'" << endl; + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::AddConfig(const string& argValue) +{ + if (!configPath_.empty()) { + cerr << "Error: double config.json " << configPath_ << " vs " << argValue << endl; + return RESTOOL_ERROR; + } + + configPath_ = argValue; + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::AddStartId(const string& argValue) +{ + startId_ = strtol(argValue.c_str(), nullptr, 16); + if ((startId_ >= 0x01000000 && startId_ < 0x06ffffff) || (startId_ >= 0x08000000 && startId_ < 0x41ffffff)) { + return RESTOOL_SUCCESS; + } + cerr << "Error: invalid start id " << argValue << endl; + return RESTOOL_ERROR; +} + +uint32_t PackageParser::AddCachePath(const string& argValue) +{ + cachePath_ = argValue; + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::CheckParam() const +{ + + if (inputs_.empty()) { + cerr << "Error: input path empty." << endl; + return RESTOOL_ERROR; + } + + if (output_.empty()) { + cerr << "Error: output path empty." << endl; + return RESTOOL_ERROR; + } + + if (previewMode_) { + return RESTOOL_SUCCESS; + } + if (packageName_.empty()) { + cerr << "Error: package name empty." << endl; + return RESTOOL_ERROR; + } + + if (resourceHeaderPaths_.empty()) { + cerr << "Error: resource header path empty." << endl; + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +bool PackageParser::IsFileList() const +{ + return isFileList_; +} + +uint32_t PackageParser::SetPreviewMode() +{ + previewMode_ = true; + return RESTOOL_SUCCESS; +} + +bool PackageParser::GetPreviewMode() const +{ + return previewMode_; +} + +int32_t PackageParser::GetPriority() const +{ + return priority_; +} + +uint32_t PackageParser::SetPriority(const string& argValue) +{ + priority_ = atoi(argValue.c_str()); + return RESTOOL_SUCCESS; +} + +void PackageParser::InitCommand() +{ + using namespace placeholders; + handles_.emplace('i', bind(&PackageParser::AddInput, this, _1)); + handles_.emplace('p', bind(&PackageParser::AddPackageName, this, _1)); + handles_.emplace('o', bind(&PackageParser::AddOutput, this, _1)); + handles_.emplace('r', bind(&PackageParser::AddResourceHeader, this, _1)); + handles_.emplace('f', [this](const string &) -> uint32_t { return ForceWrite(); }); + handles_.emplace('v', [this](const string &) -> uint32_t { return PrintVersion(); }); + handles_.emplace('m', bind(&PackageParser::AddMoudleNames, this, _1)); + handles_.emplace('j', bind(&PackageParser::AddConfig, this, _1)); + handles_.emplace('e', bind(&PackageParser::AddStartId, this, _1)); + handles_.emplace('c', bind(&PackageParser::AddCachePath, this, _1)); + handles_.emplace('a', [this](const string &) -> uint32_t { return SetPreviewMode(); }); + handles_.emplace('g', bind(&PackageParser::SetPriority, this, _1)); +} + +uint32_t PackageParser::HandleProcess(int c, const string& argValue) +{ + auto handler = handles_.find(c); + if (handler == handles_.end()) { + cout << "Warning: unsupport " << c << endl; + return RESTOOL_SUCCESS; + } + return handler->second(argValue); +} + +uint32_t PackageParser::ParseFileList(const string& fileListPath) +{ + isFileList_ = true; + CmdList cmdList; + if (cmdList.Init(fileListPath, [this](int c, const string &argValue) -> int32_t { + return HandleProcess(c, argValue); + }) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +uint32_t PackageParser::ParseCommand(int argc, char *argv[]) +{ + restoolPath_ = string(argv[0]); + while (true) { + int optIndex = 0; + int c = getopt_long(argc, argv, CMD_PARAMS.c_str(), CMD_OPTS,&optIndex); + if (c == -1) { + break; + } + + string argValue = (optarg != nullptr) ? optarg : ""; + if (c == 'l') { + return ParseFileList(argValue); + } + if (HandleProcess(c, argValue) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} +} +} +} \ No newline at end of file diff --git a/src/config_parser.cpp b/src/config_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..15e5f006406b44baffb03a20eb13d7e7d665c637 --- /dev/null +++ b/src/config_parser.cpp @@ -0,0 +1,266 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "config_parser.h" +#include +#include +#include "reference_parser.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const map ConfigParser::MODULE_TYPES = { + { "har", ModuleType::HAR, }, + { "entry", ModuleType::ENTRY }, + { "feature", ModuleType::FEATURE } +}; + +const map ConfigParser::JSON_STRING_IDS = { + { "icon", "^\\$media:" }, + { "label", "^\\$string:" }, + { "description", "^\\$string:" }, + { "theme", "^\\$theme:" }, + { "reason", "^\\$string:" } +}; + +const map ConfigParser::JSON_ARRAY_IDS = { + { "landscapeLayouts", "^\\$layout:" }, + { "portraitLayouts", "^\\$layout:" } +}; + +bool ConfigParser::useModule_ = false; + +ConfigParser::ConfigParser() + : filePath_("") ,packageName_("") ,moduleName_(""), moduleType_(ModuleType::NONE) +{ +} + +ConfigParser::ConfigParser(const string &filePath) + : filePath_(filePath) ,packageName_("") ,moduleName_(""), moduleType_(ModuleType::NONE) +{ +} + +ConfigParser::~ConfigParser() +{ +} + +uint32_t ConfigParser::Init() +{ + if (!ResourceUtil::OpenJsonFile(filePath_, rootNode_)) { + return RESTOOL_ERROR; + } + + if (!rootNode_.isObject()) { + cerr << "Error: root node not obeject in " << filePath_ << endl; + return RESTOOL_ERROR; + } + + if (!ParseModule(rootNode_["module"])) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +const string &ConfigParser::GetPackageName() const +{ + return packageName_; +} + +const string &ConfigParser::GetModuleName() const +{ + return moduleName_; +} + +ConfigParser::ModuleType ConfigParser::GetModuleType() const +{ + return moduleType_; +} + +uint32_t ConfigParser::ParseRefence() +{ + if (ParseRefImpl(rootNode_, "", rootNode_)) { + return RESTOOL_SUCCESS; + } + return RESTOOL_ERROR; +} + +uint32_t ConfigParser::Save(const string &filePath) const +{ + if (ResourceUtil::SaveToJsonFile(filePath, rootNode_)) { + return RESTOOL_SUCCESS; + } + return RESTOOL_ERROR; +} + +// below private +bool ConfigParser::ParseModule(Json::Value &moduleNode) +{ + if (!moduleNode.isObject()) { + cerr << "Error: 'module' not object in " << filePath_ << endl; + return false; + } + if (moduleNode.empty()) { + cerr << "Error: 'module' empty in " << filePath_ << endl; + return false; + } + + if (!useModule_) { + if (moduleNode["package"].isString()) { + packageName_ = moduleNode["package"].asString(); + } + return ParseDistro(moduleNode["distro"]); + } + + if (moduleNode["name"].isString()) { + moduleName_ = moduleNode["name"].asString(); + } + + if (moduleName_.empty()) { + cerr << "Error: 'name' don't found in 'module', " << filePath_ << endl; + return false; + } + + if (moduleNode["type"].isString() && !ParseModuleType(moduleNode["type"].asString())) { + return false; + } + return true; +} + +bool ConfigParser::ParseDistro(Json::Value &distroNode) +{ + if (!distroNode.isObject()) { + cerr << "Error: 'distro' not object in " << filePath_ << endl; + return false; + } + if (distroNode.empty()) { + cerr << "Error: 'distro' empty in " << filePath_ << endl; + return false; + } + + if (distroNode["moduleName"].isString()) { + moduleName_ = distroNode["moduleName"].asString(); + } + + if (moduleName_.empty()) { + cerr << "Error: 'moduleName' don't found in 'distro', " << filePath_ << endl; + return false; + } + + if (distroNode["moduleType"].isString() && !ParseModuleType(distroNode["moduleType"].asString())) { + return false; + } + return true; +} + +bool ConfigParser::ParseRefImpl(Json::Value &parent, const std::string &key, Json::Value &node) +{ + if (node.isArray()) { + const auto &result = JSON_ARRAY_IDS.find(key); + if (result != JSON_ARRAY_IDS.end()) { + return ParseJsonArrayRef(parent, key, node); + } + for (Json::ArrayIndex index = 0; index < node.size(); index++) { + if (!ParseRefImpl(node, "", node[index])) { + return false; + } + } + } else if (node.isObject()) { + const auto members = node.getMemberNames(); + for (const auto &member : members) { + if (!ParseRefImpl(node, member, node[member])) { + return false; + } + } + } else if (!key.empty() && node.isString()) { + return ParseJsonStringRef(parent, key, node); + } + return true; +} + +bool ConfigParser::ParseJsonArrayRef(Json::Value &parent, const string &key, Json::Value &node) +{ + Json::ArrayIndex size = node.size(); + Json::Value array(Json::arrayValue); + for (Json::ArrayIndex index = 0; index < size; index++) { + if (!node[index].isString()) { + cerr << "Error: '" << key << "' invalid value. " << filePath_ << endl; + return false; + } + string value = node[index].asString(); + bool update = false; + if (!GetRefIdFromString(value, update, JSON_ARRAY_IDS.at(key))) { + cerr << "Error: '" << key << "' value " << node[index] << " invalid. " << filePath_ << endl; + return false; + } + if (update) { + array.append(atoi(value.c_str())); + } + } + parent[key + "Id"] = array; + return true; +} + +bool ConfigParser::ParseJsonStringRef(Json::Value &parent, const string &key, Json::Value &node) +{ + const auto &result = JSON_STRING_IDS.find(key); + if (result == JSON_STRING_IDS.end()) { + return true; + } + string value = node.asString(); + bool update = false; + if (!GetRefIdFromString(value, update, JSON_STRING_IDS.at(key))) { + cerr << "Error: '" << key << "' value " << node << " invalid value. " << filePath_ << endl; + return false; + } + if (update) { + parent[key + "Id"] = atoi(value.c_str()); + } + return true; +} + +bool ConfigParser::GetRefIdFromString(string &value, bool &update, const string &match) const +{ + ReferenceParser refParser; + string error = "Error: '" + value + "' must start with '" + match.substr(match.find("\\") + 1) + "'"; + if (refParser.ParseRefInString(value, update) != RESTOOL_SUCCESS) { + return false; + } + if (!update) { + return true; + } + smatch result; + if (regex_search(value, result, regex(match))) { + value = value.substr(result[0].str().length()); + return true; + } + cerr << error << endl; + return false; +} + +bool ConfigParser::ParseModuleType(const string &type) +{ + const auto &result = MODULE_TYPES.find(type); + if (result == MODULE_TYPES.end()) { + cerr << "Error: moduleType='" << type << "' invalid value in " << filePath_ << endl; + return false; + } + moduleType_ = result->second; + return true; +} +} +} +} \ No newline at end of file diff --git a/src/factory_resource_compiler.cpp b/src/factory_resource_compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3e167c6a42a3f4ea359218e03471689ecb55322 --- /dev/null +++ b/src/factory_resource_compiler.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "factory_resource_compiler.h" +#include "generic_compiler.h" +#include "json_compiler.h" +#include "solid_xml_compiler.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +unique_ptr FactoryResourceCompiler::CreateCompiler(ResType type, const string &output) +{ + if (type == ResType::ELEMENT) { + return make_unique(type, output); + } else if (type == ResType::LAYOUT || type == ResType::ANIMATION || type == ResType::GRAPHIC) { + return make_unique(type, output); + } else { + return make_unique(type, output); + } +} +} +} +} \ No newline at end of file diff --git a/src/file_manager.cpp b/src/file_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d02214cfe59a67dafddfebdba9d9c1057a0f8b2 --- /dev/null +++ b/src/file_manager.cpp @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "file_manager.h" +#include +#include +#include +#include "factory_resource_compiler.h" +#include "key_parser.h" +#include "reference_parser.h" +#include "resource_directory.h" +#include "resource_util.h" +#include "restool_errors.h" + +#include "resource_module.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +uint32_t FileManager::ScanModules(const vector &inputs, const string &output) +{ + vector sxmlFolders; + for (auto input : inputs) { + map> resTypeOfDirs; + if(ScanModule(input, output, resTypeOfDirs) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + FilterRefSolidXml(output, sxmlFolders, resTypeOfDirs); + } + return ParseReference(output, sxmlFolders); +} + +uint32_t FileManager::ScanIncrement(const string &output) +{ + auto &incrementManager = IncrementManager::GetInstance(); + alls_ = incrementManager.GetResourceItems(); + vector sxmlFolders; + FilterRefSolidXml(output, sxmlFolders, incrementManager.GetScanDirs()); + return ParseReference(output, sxmlFolders); +} + +//below private founction +uint32_t FileManager::ScanModule(const string &input, const string &output, + map> &resTypeOfDirs) +{ + ResourceModule resourceModule(input, output, moduleName_); + if (resourceModule.ScanResource() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + resTypeOfDirs = resourceModule.GetScanDirectorys(); + MergeResourceItem(resourceModule.GetOwner()); + return RESTOOL_SUCCESS; +} + +uint32_t FileManager::MergeResourceItem(const map> &resourceInfos) +{ + return ResourceModule::MergeResourceItem(alls_, resourceInfos); +} + +uint32_t FileManager::ParseReference(const string &output, const vector &sxmlFolders) +{ + ReferenceParser referenceParser; + if (referenceParser.ParseRefInSolidXml(sxmlFolders) != RESTOOL_SUCCESS || + referenceParser.ParseRefInElement(alls_) != RESTOOL_SUCCESS || + referenceParser.ParseRefInProfile(output) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +bool FileManager::NeedParseReferenceInSolidXml(ResType resType) const +{ + if (resType == ResType::LAYOUT || resType == ResType::ANIMATION || resType == ResType::GRAPHIC) { + return true; + } + return false; +} + +void FileManager::FilterRefSolidXml(const string &output, vector &outputPaths, + const map> &resTypeOfDirs) const +{ + for (const auto &iter : resTypeOfDirs) { + if (!NeedParseReferenceInSolidXml(iter.first)) { + continue; + } + for (const auto &resourceDir : iter.second) { + string outputPath = filesystem::path(output).append(RESOURCES_DIR).append(resourceDir.limitKey) + .append(resourceDir.fileCluster).string(); + if (find(outputPaths.begin(), outputPaths.end(), outputPath) == outputPaths.end()) { + outputPaths.push_back(outputPath); + } + } + } +} +} +} +} diff --git a/src/generic_compiler.cpp b/src/generic_compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..727c72d3995fdea7816c7eac3b0b410d7e7a5411 --- /dev/null +++ b/src/generic_compiler.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "generic_compiler.h" +#include +#include +#include "restool_errors.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +GenericCompiler::GenericCompiler(ResType type, const string &output) + : IResourceCompiler(type, output) +{ +} +GenericCompiler::~GenericCompiler() +{ +} + +uint32_t GenericCompiler::CompileSingleFile(const FileInfo &fileInfo) +{ + if (IsIgnore(fileInfo)) { + return RESTOOL_SUCCESS; + } + + if (!CopyFile(fileInfo)) { + return RESTOOL_ERROR; + } + + if (!PostFile(fileInfo)) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +bool GenericCompiler::PostFile(const FileInfo &fileInfo) +{ + ResourceItem resourceItem(fileInfo.filename, fileInfo.keyParams, type_); + resourceItem.SetFilePath(fileInfo.filePath); + resourceItem.SetLimitKey(fileInfo.limitKey); + + string data = fileInfo.filename; + if (IsConvertToSolidXml(fileInfo)) { + data = filesystem::path(data).replace_extension(".sxml").string(); + } + data = moduleName_ + SEPARATOR + RESOURCES_DIR + SEPARATOR + \ + fileInfo.limitKey + SEPARATOR + fileInfo.fileCluster + SEPARATOR + data; + if (!resourceItem.SetData(reinterpret_cast(data.c_str()), data.length())) { + cerr << "Error: resource item set data fail, " << fileInfo.filePath << endl; + return false; + } + return MergeResourceItem(resourceItem); +} + +string GenericCompiler::GetOutputFilePath(const FileInfo &fileInfo) const +{ + string outputFolder = GetOutputFolder(fileInfo); + string outputFilePath = filesystem::path(outputFolder).append(fileInfo.filename).string(); + return outputFilePath; +} + +bool GenericCompiler::IsIgnore(const FileInfo &fileInfo) const +{ + if (IsConvertToSolidXml(fileInfo)) { + if (HasConvertedToSolidXml(fileInfo)) { + return true; + } + return false; + } + return ResourceUtil::FileExist(GetOutputFilePath(fileInfo)); +} + +bool GenericCompiler::CopyFile(const FileInfo &fileInfo) const +{ + if (previewMode_) { + return true; + } + if (IsConvertToSolidXml(fileInfo)) { + return true; + } + + string outputFolder = GetOutputFolder(fileInfo); + if (!ResourceUtil::CreateDirs(outputFolder)) { + return false; + } + return ResourceUtil::CopyFleInner(fileInfo.filePath, GetOutputFilePath(fileInfo)); +} + +bool GenericCompiler::IsConvertToSolidXml(const FileInfo &fileInfo) const +{ + if (NeedIfConvertToSolidXml() && IsXmlFile(fileInfo)) { + return true; + } + return false; +} +} +} +} \ No newline at end of file diff --git a/src/header.cpp b/src/header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d86de9c04a3b8cf2e88259d7f868c79076455866 --- /dev/null +++ b/src/header.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "header.h" +#include +#include +#include +#include + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const std::string Header::LICENSE_HEADER = "/*\n\ + * Copyright (c) 2021 Huawei Device Co., Ltd.\n\ + * Licensed under the Apache License, Version 2.0 (the \"License\");\n\ + * you may not use this file except in compliance with the License.\n\ + * You may obtain a copy of the License at\n\ + *\n\ + * http://www.apache.org/licenses/LICENSE-2.0\n\ + *\n\ + * Unless required by applicable law or agreed to in writing, software\n\ + * distributed under the License is distributed on an \"AS IS\" BASIS,\n\ + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n\ + * See the License for the specific language governing permissions and\n\ + * limitations under the License.\n\ + */\n"; + +Header::Header(const string &outputPath) : outputPath_(outputPath) +{ +} + +Header::~Header() +{ +} + +uint32_t Header::Create(HandleHeaderTail headerHandler, HandleBody bodyHandler, HandleHeaderTail tailHandler) const +{ + IdWorker &idWorker = IdWorker::GetInstance(); + vector resourceIds = idWorker.GetHeaderId(); + + ofstream out(outputPath_, ofstream::out | ofstream::binary); + if (!out.is_open()) { + cerr << "Error: open fail '" << outputPath_ << "'" << endl; + return RESTOOL_ERROR; + } + + stringstream buffer; + headerHandler(buffer); + for (const auto &resourceId : resourceIds) { + bodyHandler(buffer, resourceId); + } + tailHandler(buffer); + out << buffer.rdbuf(); + out.close(); + return RESTOOL_SUCCESS; +} +} +} +} \ No newline at end of file diff --git a/src/i_resource_compiler.cpp b/src/i_resource_compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2956486dd4bc875d2b0a4860128d56b9a159c7f4 --- /dev/null +++ b/src/i_resource_compiler.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "i_resource_compiler.h" +#include +#include +#include "id_worker.h" +#include "resource_util.h" +#include "restool_errors.h" +#include "sqlite_database.h" +#include "xml_converter.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +IResourceCompiler::IResourceCompiler(ResType type, const string &output) + :type_(type), output_(output) +{ +} + +IResourceCompiler::~IResourceCompiler() +{ + nameInfos_.clear(); + resourceInfos_.clear(); +} + +uint32_t IResourceCompiler::Compile(const vector &directoryInfos) +{ + vector fileInfos; + map> setsByDirectory; + for (const auto &directoryInfo : directoryInfos) { + string outputFolder = GetOutputFolder(directoryInfo); + for (const auto &it : filesystem::directory_iterator(directoryInfo.dirPath)) { + if (ResourceUtil::IsIgnoreFile(it.path().filename().string(), it.status().type())) { + continue; + } + + if (it.is_directory()) { + cout << "Error: '" << it.path().string() << "' not regular." << endl; + return RESTOOL_ERROR; + } + + FileInfo fileInfo = { directoryInfo, it.path().string(), it.path().filename().string() }; + fileInfos.push_back(fileInfo); + setsByDirectory[outputFolder].push_back(fileInfo); + } + } + + sort(fileInfos.begin(), fileInfos.end(), [](const auto &a, const auto &b) { + return a.filePath < b.filePath; + }); + for (const auto &fileInfo : fileInfos) { + if (CompileSingleFile(fileInfo) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + + if (previewMode_) { + return RESTOOL_SUCCESS; + } + if (NeedIfConvertToSolidXml() && ConvertToSolidXml(setsByDirectory) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return PostCommit(); +} + +const map> &IResourceCompiler::GetResult() const +{ + return resourceInfos_; +} + +uint32_t IResourceCompiler::Compile(const FileInfo &fileInfo) +{ + if (CompileSingleFile(fileInfo) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (previewMode_) { + return RESTOOL_SUCCESS; + } + map> setsByDirectory; + if (NeedIfConvertToSolidXml()) { + string outputFolder = filesystem::path(output_).append(RESOURCES_DIR) + .append(fileInfo.limitKey).append(fileInfo.fileCluster).string(); + setsByDirectory[outputFolder].push_back(fileInfo); + } + + if (ConvertToSolidXml(setsByDirectory) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return PostCommit(); +} + +void IResourceCompiler::SetModuleName(const string &moduleName) +{ + moduleName_ = moduleName; +} + +uint32_t IResourceCompiler::ConvertToSolidXml(const map> &setsByDirectory) +{ + for (const auto &iter : setsByDirectory) { + vector xmlPaths; + ListXmlFile(iter.second, xmlPaths); + if (xmlPaths.empty()) { + continue; + } + + string xmlOutPath = iter.first; + if (!ResourceUtil::CreateDirs(xmlOutPath)) { + return RESTOOL_ERROR; + } + + sort(xmlPaths.begin(), xmlPaths.end()); + XmlConverter xmlConverter(xmlPaths, xmlOutPath); + if (!xmlConverter.GenerateSolidXml()) { + return RESTOOL_ERROR; + } + + if (!xmlConverter.GenerateKey()) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t IResourceCompiler::CompileSingleFile(const FileInfo &fileInfo) +{ + return RESTOOL_SUCCESS; +} + +uint32_t IResourceCompiler::PostCommit() +{ + IdWorker &idWorker = IdWorker::GetInstance(); + for (const auto &nameInfo : nameInfos_) { + int32_t id = idWorker.GenerateId(nameInfo.first.first, nameInfo.first.second); + if (id < 0) { + cerr << "Error: restype='" << ResourceUtil::ResTypeToString(nameInfo.first.first) << "' name='"; + cerr << nameInfo.first.second << "' id not be defined." << endl; + return RESTOOL_ERROR; + } + resourceInfos_.emplace(id, nameInfo.second); + } + return RESTOOL_SUCCESS; +} + +bool IResourceCompiler::MergeResourceItem(const ResourceItem &resourceItem) +{ + if (previewMode_) { + return SqliteDatabase::GetInstance().Insert(resourceItem); + } + string idName = ResourceUtil::GetIdName(resourceItem.GetName(), resourceItem.GetResType()); + if (!IdWorker::GetInstance().IsValidName(idName)) { + cerr << "Error: in " << resourceItem.GetFilePath() << endl; + return false; + } + auto item = nameInfos_.find(make_pair(resourceItem.GetResType(), idName)); + if (item == nameInfos_.end()) { + nameInfos_[make_pair(resourceItem.GetResType(), idName)].push_back(resourceItem); + return true; + } + + auto ret = find_if(item->second.begin(), item->second.end(), [resourceItem](auto &iter) { + return resourceItem.GetLimitKey() == iter.GetLimitKey(); + }); + if (ret != item->second.end()) { + cerr << "Error: resource '" << idName << "' first declared in " << ret->GetFilePath(); + cerr << ", but declare again in " << resourceItem.GetFilePath() << endl; + return false; + } + + nameInfos_[make_pair(resourceItem.GetResType(), idName)].push_back(resourceItem); + return true; +} + +void IResourceCompiler::ListXmlFile(const vector &fileInfos, vector &xmlPaths) const +{ + for (const auto &fileInfo : fileInfos) { + if (!IsXmlFile(fileInfo)) { + continue; + } + + if (HasConvertedToSolidXml(fileInfo)) { + continue; + } + xmlPaths.push_back(fileInfo.filePath); + } +} + +bool IResourceCompiler::IsXmlFile(const FileInfo &fileInfo) const +{ + if (filesystem::path(fileInfo.filePath).extension() != ".xml") { + return false; + } + return true; +} + +bool IResourceCompiler::HasConvertedToSolidXml(const FileInfo &fileInfo) const +{ + string solidXmlPath = filesystem::path(output_).append(RESOURCES_DIR).append(fileInfo.limitKey) + .append(fileInfo.fileCluster).append(fileInfo.filename).replace_extension(".sxml").string(); + if (ResourceUtil::FileExist(solidXmlPath)) { + return true; + } + return false; +} + +bool IResourceCompiler::NeedIfConvertToSolidXml() const +{ + return ResourceUtil::NeedConverToSolidXml(type_); +} + +string IResourceCompiler::GetOutputFolder(const DirectoryInfo &directoryInfo) const +{ + string outputFolder = filesystem::path(output_).append(RESOURCES_DIR) + .append(directoryInfo.limitKey).append(directoryInfo.fileCluster).string(); + return outputFolder; +} +} +} +} \ No newline at end of file diff --git a/src/id_worker.cpp b/src/id_worker.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4bc0827022e3ec00f0f26f7b5715018093c00fde --- /dev/null +++ b/src/id_worker.cpp @@ -0,0 +1,349 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "id_worker.h" +#include +#include +#include +#include "cmd_parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const int32_t IdWorker::START_SYS_ID = 0x07800000; +uint32_t IdWorker::Init(ResourceIdCluster type, int32_t startId) +{ + type_ = type; + if (InitIdDefined() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (type == ResourceIdCluster::RES_ID_APP) { + appId_ = startId; + maxId_ = GetMaxId(startId); + } + return RESTOOL_SUCCESS; +} + +int32_t IdWorker::GenerateId(ResType resType, const string &name) +{ + if (type_ == ResourceIdCluster::RES_ID_APP) { + return GenerateAppId(resType, name); + } + return GenerateSysId(resType, name); +} + +vector IdWorker::GetHeaderId() const +{ + map> idClassify; + for (const auto &it : ids_) { + ResourceId resourceId; + resourceId.id = it.second; + resourceId.type = ResourceUtil::ResTypeToString(it.first.first); + resourceId.name = it.first.second; + idClassify[it.first.first].push_back(resourceId); + } + + vector ids; + for (const auto &item : idClassify) { + ids.insert(ids.end(), item.second.begin(), item.second.end()); + } + return ids; +} + +int32_t IdWorker::GetId(ResType resType, const string &name) const +{ + auto result = ids_.find(make_pair(resType, name)); + if (result == ids_.end()) { + return -1; + } + return result->second; +} + +int32_t IdWorker::GetSystemId(ResType resType, const string &name) const +{ + auto result = definedIds_.find(make_pair(resType, name)); + if (result == definedIds_.end()) { + return -1; + } + return result->second.id; +} + +bool IdWorker::IsValidName(const string &name) const +{ + if (!regex_match(name, regex("[a-zA-z0-9_]+"))) { + cerr << "Error: '" << name << "' only contain [a-zA-z0-9_]." << endl; + return false; + } + if (type_ != ResourceIdCluster::RES_ID_SYS) { + return true; + } + return IsValidSystemName(name); +} + +bool IdWorker::PushCache(ResType resType, const string &name, int32_t id) +{ + auto result = cacheIds_.emplace(make_pair(resType, name), id); + if (!result.second) { + return false; + } + if (appId_ == id) { + appId_ = id + 1; + return true; + } + + if (id < appId_) { + return false; + } + + for (int32_t i = appId_; i < id; i++) { + delIds_.push_back(i); + } + appId_ = id + 1; + return true; +} + +void IdWorker::PushDelId(int32_t id) +{ + delIds_.push_back(id); +} + +int32_t IdWorker::GenerateAppId(ResType resType, const string &name) +{ + auto result = ids_.find(make_pair(resType, name)); + if (result != ids_.end()) { + return result->second; + } + + result = cacheIds_.find(make_pair(resType, name)); + if (result != cacheIds_.end()) { + ids_.emplace(make_pair(resType, name), result->second); + return result->second; + } + + if (appId_ > maxId_) { + cerr << "Error: id count exceed " << appId_ << ">" << maxId_ << endl; + return -1; + } + int32_t id = 0; + if (!delIds_.empty()) { + id = delIds_.front(); + delIds_.erase(delIds_.begin()); + } else { + id = appId_; + appId_++; + } + ids_.emplace(make_pair(resType, name), id); + return id; +} + +int32_t IdWorker::GenerateSysId(ResType resType, const string &name) +{ + auto result = ids_.find(make_pair(resType, name)); + if (result != ids_.end()) { + return result->second; + } + + auto defined = definedIds_.find(make_pair(resType, name)); + if (defined != definedIds_.end()) { + ids_.emplace(make_pair(resType, name), defined->second.id); + return defined->second.id; + } + return -1; +} + +uint32_t IdWorker::InitIdDefined() +{ + InitParser(); + CmdParser &parser = CmdParser::GetInstance(); + PackageParser &packageParser = parser.GetCmdParser(); + string idDefinedPath; + if (type_ == ResourceIdCluster::RES_ID_SYS) { + for (const auto &inputPath : packageParser.GetInputs()) { + idDefinedPath = filesystem::path(inputPath).append(RESOURCES_DIR) + .append("base").append("element").append(ID_DEFINED_FILE).string(); + if (InitIdDefined(idDefinedPath) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; + } + + idDefinedPath = filesystem::path(packageParser.GetRestoolPath()).parent_path().append(ID_DEFINED_FILE).string(); + if (InitIdDefined(idDefinedPath) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +uint32_t IdWorker::InitIdDefined(const std::string &filePath) +{ + if (!ResourceUtil::FileExist(filePath)) { + return RESTOOL_SUCCESS; + } + + Json::Value root; + if (!ResourceUtil::OpenJsonFile(filePath, root)) { + return RESTOOL_ERROR; + } + + int32_t startSysId = GetStartId(root); + if (startSysId < 0) { + return RESTOOL_ERROR; + } + + auto record = root["record"]; + if (record.empty()) { + cerr << "Error: id_defined.json record empty." << endl; + return RESTOOL_ERROR; + } + if (!record.isArray()) { + cerr << "Error: id_defined.json record not array." << endl; + return RESTOOL_ERROR; + } + + for (Json::ArrayIndex index = 0; index < record.size(); index++) { + auto arrayItem = record[index]; + ResourceId resourceId; + resourceId.seq = index; + resourceId.id = startSysId; + if (!arrayItem.isObject()) { + return RESTOOL_ERROR; + } + for (const auto &handle : handles_) { + if (!handle.second(arrayItem[handle.first], resourceId)) { + return RESTOOL_ERROR; + } + } + if (!PushResourceId(resourceId)) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +void IdWorker::InitParser() +{ + using namespace placeholders; + handles_.emplace("type", bind(&IdWorker::ParseType, this, _1, _2)); + handles_.emplace("name", bind(&IdWorker::ParseName, this, _1, _2)); + handles_.emplace("order", bind(&IdWorker::ParseOrder, this, _1, _2)); +} + +bool IdWorker::ParseType(const Json::Value &type, ResourceId &resourceId) +{ + if (type.empty()) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " type empty." << endl; + return false; + } + if (!type.isString()) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " type not string." << endl; + return false; + } + if (ResourceUtil::GetResTypeFromString(type.asString()) == ResType::INVALID_RES_TYPE) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " type '"; + cerr << type.asString() << "' invalid." << endl; + return false; + } + resourceId.type = type.asString(); + return true; +} + +bool IdWorker::ParseName(const Json::Value &name, ResourceId &resourceId) +{ + if (name.empty()) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " name empty." << endl; + return false; + } + if (!name.isString()) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " name not string." << endl; + return false; + } + resourceId.name = name.asString(); + if ((resourceId.id & START_SYS_ID) == START_SYS_ID && !IsValidSystemName(resourceId.name)) { + cerr << "Error: id_defined.json."<< endl; + return false; + } + return true; +} + +bool IdWorker::ParseOrder(const Json::Value &order, ResourceId &resourceId) +{ + if (order.empty()) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " order empty." << endl; + return false; + } + if (!order.isInt()) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " order not int." << endl; + return false; + } + if (order.asInt() != resourceId.seq) { + cerr << "Error: id_defined.json seq=" << resourceId.seq << " order value "; + cerr << order.asInt() << " vs expect " << resourceId.seq << endl; + return false; + } + resourceId.id = resourceId.id + order.asInt(); + return true; +} + +bool IdWorker::PushResourceId(const ResourceId &resourceId) +{ + ResType resType = ResourceUtil::GetResTypeFromString(resourceId.type); + auto result = definedIds_.emplace(make_pair(resType, resourceId.name), resourceId); + if (!result.second) { + cerr << "Error: '" << resourceId.type << "' '" << resourceId.name << "' duplicated." << endl; + return false; + } + return true; +} + +bool IdWorker::IsValidSystemName(const string &name) const +{ + if (regex_match(name, regex("^ohos.+"))) { + return true; + } + cerr << "Error: '" << name << "' must start with 'ohos'" << endl; + return false; +} + +int32_t IdWorker::GetStartId(const Json::Value &root) const +{ + auto startId = root["startId"]; + if (startId.empty()) { + cerr << "Error: id_defined.json 'startId' empty." << endl; + return -1; + } + + if (!startId.isString()) { + cerr << "Error: id_defined.json 'startId' not string." << endl; + return -1; + } + + int32_t id = strtol(startId.asString().c_str(), nullptr, 16); + return id; +} + +int32_t IdWorker::GetMaxId(int32_t startId) const +{ + int32_t flag = 1; + while ((flag & startId) == 0) { + flag = flag << 1; + } + return (startId + flag - 1); +} +} +} +} \ No newline at end of file diff --git a/src/increment_index.cpp b/src/increment_index.cpp new file mode 100644 index 0000000000000000000000000000000000000000..27a7c58facac7c4c825600324c6e15ae1c5c2c06 --- /dev/null +++ b/src/increment_index.cpp @@ -0,0 +1,229 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "increment_index.h" +#include +#include +#include "key_parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const string IncrementIndex::INDEX_FILE = "index.json"; +IncrementIndex::IncrementIndex(const string &indexPath, const vector &folder) + : indexPath_(indexPath), folder_(folder) +{ +} + +bool IncrementIndex::Save(const map> &items) const +{ + Json::Value root; + root["header"] = Json::Value(Json::ValueType::objectValue); + root["header"]["folder"] = Json::Value(Json::ValueType::arrayValue); + for (const auto &folder : folder_) { + root["header"]["folder"].append(folder); + } + + root["index"] = Json::Value(Json::ValueType::objectValue); + for (const auto &item : items) { + string id = to_string(item.first); + root["index"][id] = Json::Value(Json::ValueType::objectValue); + for (const auto &resourceItem : item.second) { + root["index"][id][resourceItem.GetFilePath()] = Json::Value(Json::ValueType::objectValue); + auto &record = root["index"][id][resourceItem.GetFilePath()]; + string data(reinterpret_cast(resourceItem.GetData()), resourceItem.GetDataLength()); + record["data"] = data; + record["name"] = resourceItem.GetName(); + record["limitkey"] = resourceItem.GetLimitKey(); + record["type"] = ResourceUtil::ResTypeToString(resourceItem.GetResType()); + } + } + + if (!ResourceUtil::SaveToJsonFile(indexPath_, root)) { + return false; + } + return true; +} + +bool IncrementIndex::Load(map> &items) const +{ + Json::Value indexJson; + if (!ResourceUtil::OpenJsonFile(indexPath_, indexJson)) { + return false; + } + + auto headerInfo = indexJson["header"]; + if (headerInfo.empty() || !headerInfo.isObject()) { + cerr << "Error: " << indexPath_ << " header info." << endl; + return true; + } + auto folderInfo = headerInfo["folder"]; + if (folderInfo.empty() || !folderInfo.isArray()) { + cerr << "Error: " << indexPath_ << " folder info." << endl; + return false; + } + if (folder_.size() != folderInfo.size()) { + cerr << "Error: add/delete dependency, don't support increment compile." << endl; + return false; + } + + for (size_t i = 0; i < folder_.size(); i++) { + if (folder_[i] != folderInfo[static_cast(i)].asString()) { + cerr << "Error: dependency change, don't support increment compile." << endl; + return true; + } + } + + if (!LoadIndex(indexJson["index"], items)) { + return false; + } + return true; +} + +void IncrementIndex::SetSkipPaths(const vector &skipPaths) +{ + skipPaths_ = skipPaths; +} + +// below private +bool IncrementIndex::LoadIndex(const Json::Value &indexInfo, map> &items) const +{ + if (indexInfo.empty() || !indexInfo.isObject()) { + cerr << "Error: " << indexPath_ << " index info." << endl; + return false; + } + + for (const auto &idMember : indexInfo.getMemberNames()) { + int32_t id = strtol(idMember.c_str(), nullptr, 10); + if (id < 0) { + cerr << "Error: " << indexPath_ << " '" << idMember << "' not integer string." << endl; + return false; + } + if (items.count(id) != 0) { + cerr << "Error: " << indexPath_ << " '" << idMember << "' duplicated." << endl; + return false; + } + if (!indexInfo[idMember].isObject()) { + cerr << "Error: " << indexPath_ << " '" << idMember << "' not object." << endl; + return false; + } + for (const auto &pathMember : indexInfo[idMember].getMemberNames()) { + if (IsIgnore(pathMember)) { + continue; + } + auto item = indexInfo[idMember][pathMember]; + if (!item.isObject()) { + cerr << "Error: " << indexPath_ << " [" << idMember << "][" << pathMember<<"] not object." << endl; + return false; + } + ResourceItem resourceItem; + if (!ParseResourceItem(item, pathMember, resourceItem)) { + cerr << "Error: " << indexPath_ << " [" << idMember << "][" << pathMember<<"]." << endl; + return false; + } + if (!PushResourceItem(resourceItem, id, items)) { + return false; + } + } + } + return true; +} + +bool IncrementIndex::ParseResourceItem(const Json::Value &item, const string &filePath, + ResourceItem &resourceItem) const +{ + string name; + string type; + string limitKey; + string data; + if (!GetResourceItemProp(item, "name", name) || !GetResourceItemProp(item, "type", type) || + !GetResourceItemProp(item, "limitkey", limitKey) || !GetResourceItemProp(item, "data", data)) { + cerr << "Error: 'name' 'type' 'limitkey' 'data' invalid." << endl; + return false; + } + ResType resType = ResourceUtil::GetResTypeFromString(type); + if (resType == ResType::INVALID_RES_TYPE) { + cerr << "Error: " << indexPath_ << " invaid ResType '" << type << "'" << endl; + return false; + } + vector keyParams; + if (!KeyParser::Parse(limitKey, keyParams)) { + return false; + } + ResourceItem temp(name, keyParams, resType); + if (resType != ResType::ID && !temp.SetData(reinterpret_cast(data.c_str()), data.length())) { + cerr << "Error: resource set data fail." << endl; + return false; + } + temp.SetFilePath(filePath); + temp.SetLimitKey(limitKey); + resourceItem = temp; + return true; +} + +bool IncrementIndex::GetResourceItemProp(const Json::Value &item, const string &key, string &value) const +{ + if (item[key].empty() || !item[key].isString()) { + return false; + } + value = item[key].asString(); + return true; +} + +bool IncrementIndex::PushResourceItem(const ResourceItem &resourceItem, int32_t id, + map> &items) const +{ + if (items.find(id) == items.end()) { + items[id].push_back(resourceItem); + return true; + } + + const auto &first = items[id].begin(); + if (resourceItem.GetName() != first->GetName()) { + cerr << "Error: " << indexPath_ << " '" << resourceItem.GetName(); + cerr << "', expect '" << first->GetName() << "'"<< endl; + return false; + } + if (resourceItem.GetResType() != first->GetResType()) { + cerr << "Error: " << indexPath_ << " '" << ResourceUtil::ResTypeToString(resourceItem.GetResType()); + cerr << "', expect '" << ResourceUtil::ResTypeToString(first->GetResType()) << "'"<< endl; + return false; + } + auto result = find_if(items[id].begin(), items[id].end(), [&resourceItem](const auto &iter) { + return resourceItem.GetLimitKey() == iter.GetLimitKey(); + }); + if (result != items[id].end()) { + cerr << "Error: " << indexPath_ << " '" << resourceItem.GetLimitKey() << "' conflict." << endl; + return false; + } + items[id].push_back(resourceItem); + return true; +} + +bool IncrementIndex::IsIgnore(const string &filePath) const +{ + if (skipPaths_.empty()) { + return false; + } + + if (find(skipPaths_.begin(), skipPaths_.end(), filePath) != skipPaths_.end()) { + return true; + } + return false; +} +} +} +} \ No newline at end of file diff --git a/src/increment_list.cpp b/src/increment_list.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1f9c65927b8e122792c3ef075ffd4daa9687bba2 --- /dev/null +++ b/src/increment_list.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "increment_list.h" +#include +#include +#include +#include "key_parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const string IncrementList::RESTOOL_LIST_FILE = "restool_list.json"; +IncrementList::IncrementList(const string &listPath, const vector &folder) + : listPath_(listPath), folder_(folder) +{ +} + +bool IncrementList::Parse(std::vector &fileList) const +{ + Json::Value listJson; + if (!ResourceUtil::OpenJsonFile(listPath_, listJson)) { + return false; + } + + if (ParseArray(listJson["del"], fileList, true) && + ParseArray(listJson["fix"], fileList, false)) { + return true; + } + return false; +} + +// below private +bool IncrementList::GetFromPath(const string &filePath, FileIncrement &info) const +{ + int32_t priority = GetPriority(filePath); + if (priority < 0) { + cerr << "Error: " << RESTOOL_LIST_FILE << " '" << filePath << "' invalid." << endl; + return false; + } + info.rootPath = folder_[priority]; + string rootPath = filesystem::path(info.rootPath).append("").string(); + info.relativePath = filePath.substr(rootPath.length()); + vector segments; + if (!ParseSegment(info.relativePath, segments)) { + return false; + } + + info.dirPath = filesystem::path(filePath).parent_path().string(); + info.filePath = filePath; + info.limitKey = segments[SEG_LIMIT_KEY]; + if (info.limitKey == RAW_FILE_DIR) { + info.dirType = ResType::INVALID_RES_TYPE; + return true; + } + if (!KeyParser::Parse(info.limitKey, info.keyParams)) { + cerr << "Error: '" << filePath << "' '" << info.limitKey << "' invalid limit key." << endl; + return false; + } + + info.fileCluster = segments[SEG_FILE_CLUSTER]; + info.dirType = ResourceUtil::GetResTypeByDir(info.fileCluster); + if (info.dirType == ResType::INVALID_RES_TYPE) { + cerr << "Error: '" << filePath << "' '" << info.fileCluster << "' invalid ResType." << endl; + return false; + } + info.filename = segments[SEG_FILE_NAME]; + return true; +} + +int32_t IncrementList::GetPriority(const string &filePath) const +{ + auto result = find_if(folder_.begin(), folder_.end(), [&filePath](auto &iter) { + string rootPath = filesystem::path(iter).append("").string(); + if (filePath.length() <= rootPath.length()) { + return false; + } + if (filePath.compare(0, rootPath.length(), rootPath.c_str()) == 0) { + return true; + } + return true; + }); + if (result == folder_.end()) { + return -1; + } + return (result - folder_.begin()); +} + +bool IncrementList::ParseSegment(const string &filePath, vector &segments) const +{ + for (const auto &it : filesystem::path(filePath)) { + segments.push_back(it.string()); + } + + if (segments.size() >= (SEG_RESOURCE + 1) && segments[SEG_RESOURCE] != RESOURCES_DIR) { + cerr << "Error: '" << filePath << "' don't contain '" << RESOURCES_DIR << "'" << endl; + return false; + } + + if (segments.size() >= (SEG_LIMIT_KEY + 1) && segments[SEG_LIMIT_KEY] == RAW_FILE_DIR) { + return true; + } + + if (segments.size() != SEG_MAX) { + cerr << "Error: '" << filePath << "' segments != " << SEG_MAX << endl; + return false; + } + return true; +} + +bool IncrementList::IteratorArray(const Json::Value &array, function callback) const +{ + if (array.empty()) { + return true; + } + + if (!array.isArray()) { + cerr << "Error: "<< RESTOOL_LIST_FILE << ",not array." << endl; + return false; + } + + for (Json::ArrayIndex i = 0; i < array.size(); i++) { + if (!array[i].isString()) { + cerr << "Error: " << RESTOOL_LIST_FILE << ",not string." << endl; + return false; + } + if (callback && !callback(array[i].asString())) { + return false; + } + } + return true; +} + +bool IncrementList::ParseArray(const Json::Value &array, vector &fileList, bool isDeleted) const +{ + return IteratorArray(array, [this, &fileList, &isDeleted](const string &filePath) { + FileIncrement info; + info.isDeleted = isDeleted; + if (!GetFromPath(filePath, info)) { + return false; + } + fileList.push_back(info); + return true; + }); +} +} +} +} \ No newline at end of file diff --git a/src/increment_manager.cpp b/src/increment_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..625f7d559d1d3294819197e3e06b61adfc5a9f78 --- /dev/null +++ b/src/increment_manager.cpp @@ -0,0 +1,308 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "increment_manager.h" +#include +#include +#include "id_worker.h" +#include "key_parser.h" +#include "restool_errors.h" +#include "xml_key_node.h" + +#include "resource_module_inc.h" +#include "module_combine.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const string IncrementManager::ID_JSON_FILE = "ids.json"; +IncrementManager::~IncrementManager() +{ +} + +uint32_t IncrementManager::Init(const string &cachePath, const vector &folder, + const string &outputPath, const string &moduleName) +{ + cachePath_ = cachePath; + folder_ = folder; + outputPath_ = outputPath; + moduleName_ = moduleName; + + if (!InitIdJson()) { + return RESTOOL_ERROR; + } + + if (!ClearSolidXml()) { + return RESTOOL_ERROR; + } + + vector dels; + if (!InitList(dels)) { + return RESTOOL_ERROR; + } + + DeleteRawFile(dels); + if (!ScanModules(dels)) { + return RESTOOL_ERROR; + } + enalbe_= true; + return RESTOOL_SUCCESS; +} + +// below private +bool IncrementManager::InitIdJson() +{ + string idJsonPath = filesystem::path(cachePath_).append(ID_JSON_FILE).string(); + if (!ResourceUtil::FileExist(idJsonPath)) { + return true; + } + if (!LoadIdJson()) { + return false; + } + firstIncrement_ = false; + return true; +} + +bool IncrementManager::ScanModules(const vector &dels) +{ + vector moduleInfos; + for (const auto &folder : folder_) { + ModuleInfo moduleInfo; + moduleInfo.rootPath = folder; + for_each(dels.begin(), dels.end(), [&moduleInfo](const auto &iter) { + if (moduleInfo.rootPath != iter.rootPath) { + return; + } + moduleInfo.fileIncrements.push_back(iter); + }); + moduleInfos.push_back(moduleInfo); + } + + for (auto &iter : moduleInfos) { + string pathHash = ResourceUtil::GenerateHash(iter.rootPath); + string moduleCachePath = filesystem::path(cachePath_).append(pathHash).string(); + ResourceModuleInc resourceModuleInc(iter.rootPath, moduleCachePath, moduleName_, folder_); + if (FirstIncrement()) { + if (resourceModuleInc.ResourceModule::ScanResource() != RESTOOL_SUCCESS) { + return false; + } + } else { + if (resourceModuleInc.ScanResource(iter.fileIncrements) != RESTOOL_SUCCESS) { + return false; + } + } + + PushScanDir(resourceModuleInc.GetScanDirectorys()); + if (ResourceModule::MergeResourceItem(items_, resourceModuleInc.GetOwner()) != RESTOOL_SUCCESS) { + return false; + } + if (resourceModuleInc.SaveIndex() != RESTOOL_SUCCESS) { + return false; + } + + ModuleCombine moduleCombine(moduleCachePath, outputPath_); + if (!moduleCombine.Combine()) { + return false; + } + } + FlushId(); + SaveIdJson(); + return true; +} + +bool IncrementManager::InitList(vector &dels) const +{ + string listPath = filesystem::path(cachePath_).append(IncrementList::RESTOOL_LIST_FILE).string(); + if (!ResourceUtil::FileExist(listPath)) { + return true; + } + + IncrementList incrementList(listPath, folder_); + if (!incrementList.Parse(dels)) { + return false; + } + return true; +} + +void IncrementManager::FlushId() +{ + for_each(items_.begin(), items_.end(), [](const auto &iter) { + auto &idWorker = IdWorker::GetInstance(); + ResType resType = iter.second.begin()->GetResType(); + string name = ResourceUtil::GetIdName(iter.second.begin()->GetName(), resType); + idWorker.GenerateId(resType, name); + }); +} + +bool IncrementManager::SaveIdJson() const +{ + Json::Value root; + for (const auto &iter : items_) { + Json::Value node; + ResType resType = iter.second.begin()->GetResType(); + node["name"] = ResourceUtil::GetIdName(iter.second.begin()->GetName(), resType); + node["type"] = ResourceUtil::ResTypeToString(resType); + root[to_string(iter.first)] = node; + } + + string idJsonPath = filesystem::path(cachePath_).append(ID_JSON_FILE).string(); + if (!ResourceUtil::SaveToJsonFile(idJsonPath, root)) { + return false; + } + return true; +} + +bool IncrementManager::LoadIdJson() +{ + Json::Value root; + string idJsonPath = filesystem::path(cachePath_).append(ID_JSON_FILE).string(); + if (!ResourceUtil::OpenJsonFile(idJsonPath, root)) { + return false; + } + + if (!root.isObject()) { + cerr << "Error: '" << idJsonPath << "' invalid, not object." << endl; + return false; + } + + auto &idWorker = IdWorker::GetInstance(); + for (const auto &member : root.getMemberNames()) { + int32_t id = strtol(member.c_str(), nullptr, 10); + if (id < 0) { + cerr << "Error: '" << idJsonPath << "' invalid '" << member << "'" << endl; + return false; + } + + const auto &node = root[member]; + if (!node.isObject()) { + cerr << "Error: '" << idJsonPath << "' '" << member << "' not object." << endl; + return false; + } + if (!node["name"].isString()) { + cerr << "Error: '" << idJsonPath << "' '" << member << "' name not string." << endl; + return false; + } + string name = node["name"].asString(); + + if (!node["type"].isString()) { + cerr << "Error: '" << idJsonPath << "' '" << member << "' type not string." << endl; + return false; + } + ResType resType = ResourceUtil::GetResTypeFromString(node["type"].asString()); + if (resType == ResType::INVALID_RES_TYPE) { + cerr << "Error: '" << idJsonPath << "' '" << member << "' '" << node["type"] << "' invalid." << endl; + return false; + } + if (!idWorker.PushCache(resType, name, id)) { + return false; + } + } + return true; +} + +void IncrementManager::PushScanDir(const map> &scanDirs) +{ + for (const auto &iter : scanDirs) { + for (const auto &directoryInfo : iter.second) { + scanDirs_[iter.first].push_back(directoryInfo); + } + } +} + +void IncrementManager::DeleteRawFile(vector &dels) const +{ + for (auto it = dels.begin(); it != dels.end();) { + if (it->dirType != ResType::INVALID_RES_TYPE) { + it++; + continue; + } + string rawFilePath = filesystem::path(outputPath_).append(it->relativePath).string(); + filesystem::remove(rawFilePath); + it = dels.erase(it); + } +} + +bool IncrementManager::ClearSolidXml() const +{ + string resourceDir = filesystem::path(outputPath_).append(RESOURCES_DIR).string(); + if (!ResourceUtil::FileExist(resourceDir)) { + return true; + } + + ResourceDirectory resourceDirectory; + if (!resourceDirectory.ScanResources(resourceDir, [](const DirectoryInfo &info) { + if (!ResourceUtil::NeedConverToSolidXml(info.dirType)) { + return true; + } + + for (const auto &entry : filesystem::directory_iterator(info.dirPath)) { + if (entry.is_directory()) { + cerr << "Error: '" << entry.path().string() << "' is directroy." << endl; + return false; + } + + string extension = entry.path().extension().string(); + if (extension != ".sxml" && extension != ".key" && extension != ".json") { + continue; + } + + if (!filesystem::remove(entry.path().string())) { + cerr << "Error: remove '" << entry.path().string() << "' fail." << endl; + return false; + } + } + return true; + })) { + return false; + } + return true; +} +/* +{ + "0x01000000": + { + "name":"xxxxx", + "type":"string" + } +} +{ + "header":{ + "folder":["xxxx", "xxxx", "xxxx", "xxxx"] + }, + "index":{ + "0x01000000":{ + "filepath":{ + "data":"xxxx", + "name":"xxxx", + "type":"xxxx", + "limitkey":"xxxx" + } + }, + } +} + +{ + "del":[ + "xx/xx/xx/xxx" + ], + "fix":[ + "xxx/xxx/xx" + ] +} +*/ +} +} +} \ No newline at end of file diff --git a/src/json_compiler.cpp b/src/json_compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b69b9a79bfc2a89459e1dfc58a6743c47d60067 --- /dev/null +++ b/src/json_compiler.cpp @@ -0,0 +1,469 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "json_compiler.h" +#include +#include +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const string JsonCompiler::TAG_NAME = "name"; +const string JsonCompiler::TAG_VALUE = "value"; +const string JsonCompiler::TAG_PARENT = "parent"; +const string JsonCompiler::TAG_QUANTITY = "quantity"; +const vector JsonCompiler::QUANTITY_ATTRS = { "zero", "one", "two", "few", "many", "other" }; + +JsonCompiler::JsonCompiler(ResType type, const string &output) + : IResourceCompiler(type, output) +{ + InitParser(); +} + +JsonCompiler::~JsonCompiler() +{ +} + +uint32_t JsonCompiler::CompileSingleFile(const FileInfo &fileInfo) +{ + if (fileInfo.limitKey == "base" && + fileInfo.fileCluster == "element" && + fileInfo.filename == ID_DEFINED_FILE) { + return RESTOOL_SUCCESS; + } + + Json::Value root; + if (!ResourceUtil::OpenJsonFile(fileInfo.filePath, root)) { + return RESTOOL_ERROR; + } + + if (!root.isObject()) { + cerr << "Error: root node must object," << fileInfo.filePath << endl; + return RESTOOL_ERROR; + } + + if (root.getMemberNames().size() != 1) { + cerr << "Error: root node must only one member," << fileInfo.filePath << endl; + return RESTOOL_ERROR; + } + + string tag = root.getMemberNames()[0]; + auto ret = g_contentClusterMap.find(tag); + if (ret == g_contentClusterMap.end()) { + cerr << "Error: invalid tag name '" << tag << "'," << fileInfo.filePath << endl; + return RESTOOL_ERROR; + } + + FileInfo copy = fileInfo; + copy.fileType = ret->second; + if (!ParseJsonArrayLevel(root[tag], copy)) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +//below private +void JsonCompiler::InitParser() +{ + using namespace placeholders; + handles_.emplace(ResType::STRING, bind(&JsonCompiler::HandleString, this, _1, _2)); + handles_.emplace(ResType::INTEGER, bind(&JsonCompiler::HandleInteger, this, _1, _2)); + handles_.emplace(ResType::BOOLEAN, bind(&JsonCompiler::HandleBoolean, this, _1, _2)); + handles_.emplace(ResType::COLOR, bind(&JsonCompiler::HandleColor, this, _1, _2)); + handles_.emplace(ResType::FLOAT, bind(&JsonCompiler::HandleFloat, this, _1, _2)); + handles_.emplace(ResType::STRARRAY, bind(&JsonCompiler::HandleStringArray, this, _1, _2)); + handles_.emplace(ResType::INTARRAY, bind(&JsonCompiler::HandleIntegerArray, this, _1, _2)); + handles_.emplace(ResType::THEME, bind(&JsonCompiler::HandleTheme, this, _1, _2)); + handles_.emplace(ResType::PATTERN, bind(&JsonCompiler::HandlePattern, this, _1, _2)); + handles_.emplace(ResType::PLURAL, bind(&JsonCompiler::HandlePlural, this, _1, _2)); +} + +bool JsonCompiler::ParseJsonArrayLevel(const Json::Value &arrayNode, const FileInfo &fileInfo) +{ + if (!arrayNode.isArray()) { + cerr << "Error: '" << ResourceUtil::ResTypeToString(fileInfo.fileType) << "' must be array,"; + cerr << fileInfo.filePath << endl; + return false; + } + + if (arrayNode.empty()) { + cerr << "Error: '" << ResourceUtil::ResTypeToString(fileInfo.fileType) << "' empty,"; + cerr << fileInfo.filePath << endl; + return false; + } + + for (Json::ArrayIndex index = 0; index < arrayNode.size(); index++) { + if (!arrayNode[index].isObject()) { + cerr << "Error: the seq=" << index << " item must be object," << fileInfo.filePath << endl; + return false; + } + if (!ParseJsonObjectLevel(arrayNode[index], fileInfo)) { + return false; + } + } + return true; +} + +bool JsonCompiler::ParseJsonObjectLevel(const Json::Value &objectNode, const FileInfo &fileInfo) +{ + auto nameNode = objectNode[TAG_NAME]; + if (nameNode.empty()) { + cerr << "Error: name empty," << fileInfo.filePath << endl; + return false; + } + + if (!nameNode.isString()) { + cerr << "Error: name must string," << fileInfo.filePath << endl; + return false; + } + + ResourceItem resourceItem(nameNode.asString(), fileInfo.keyParams, fileInfo.fileType); + resourceItem.SetFilePath(fileInfo.filePath); + resourceItem.SetLimitKey(fileInfo.limitKey); + auto ret = handles_.find(fileInfo.fileType); + if (ret == handles_.end()) { + cerr << "Error: json parser don't support " << ResourceUtil::ResTypeToString(fileInfo.fileType) << endl; + return false; + } + + if (!ret->second(objectNode, resourceItem)) { + return false; + } + + return MergeResourceItem(resourceItem); +} + +bool JsonCompiler::HandleString(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + Json::Value valueNode = objectNode[TAG_VALUE]; + if (!CheckJsonStringValue(valueNode, resourceItem)) { + return false; + } + return PushString(valueNode.asString(), resourceItem); +} + +bool JsonCompiler::HandleInteger(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + Json::Value valueNode = objectNode[TAG_VALUE]; + if (!CheckJsonIntegerValue(valueNode, resourceItem)) { + return false; + } + return PushString(valueNode.asString(), resourceItem); +} + +bool JsonCompiler::HandleBoolean(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + Json::Value valueNode = objectNode[TAG_VALUE]; + if (valueNode.isString()) { + regex ref("^\\$boolean:.*"); + if (!regex_match(valueNode.asString(), ref)) { + cerr << "Error: '" << valueNode.asString() << "' only refer '$boolean:xxx',"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + } else if (!valueNode.isBool()) { + cerr << "Error: '" << resourceItem.GetName() << "' value not boolean," << resourceItem.GetFilePath() << endl; + return false; + } + return PushString(valueNode.asString(), resourceItem); +} + +bool JsonCompiler::HandleColor(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + return HandleString(objectNode, resourceItem); +} + +bool JsonCompiler::HandleFloat(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + return HandleString(objectNode, resourceItem); +} + +bool JsonCompiler::HandleStringArray(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + vector extra; + return ParseValueArray(objectNode, resourceItem, extra, + [this](const Json::Value &arrayItem, const ResourceItem &resourceItem, vector &values) -> bool { + if (!arrayItem.isObject()) { + cerr << "Error: '" << resourceItem.GetName() << "' value array item not object,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + auto value = arrayItem[TAG_VALUE]; + if (!CheckJsonStringValue(value, resourceItem)) { + return false; + } + values.push_back(value.asString()); + return true; + }); +} + +bool JsonCompiler::HandleIntegerArray(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + vector extra; + return ParseValueArray(objectNode, resourceItem, extra, + [this](const Json::Value &arrayItem, const ResourceItem &resourceItem, vector &values) -> bool { + if (!CheckJsonIntegerValue(arrayItem, resourceItem)) { + return false; + } + values.push_back(arrayItem.asString()); + return true; + }); +} + +bool JsonCompiler::HandleTheme(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + vector extra; + if (!ParseParent(objectNode, resourceItem, extra)) { + return false; + } + return ParseValueArray(objectNode, resourceItem, extra, + [this](const Json::Value &arrayItem, const ResourceItem &resourceItem, vector &values) { + return ParseAttribute(arrayItem, resourceItem, values); + }); +} + +bool JsonCompiler::HandlePattern(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + return HandleTheme(objectNode, resourceItem); +} + +bool JsonCompiler::HandlePlural(const Json::Value &objectNode, ResourceItem &resourceItem) const +{ + vector extra; + vector attrs; + bool result = ParseValueArray(objectNode, resourceItem, extra, + [&attrs, this](const Json::Value &arrayItem, const ResourceItem &resourceItem, vector &values) { + if (!CheckPluralValue(arrayItem, resourceItem)) { + return false; + } + string quantityValue = arrayItem[TAG_QUANTITY].asString(); + if (find(attrs.begin(), attrs.end(), quantityValue) != attrs.end()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; + cerr << "' duplicated," << resourceItem.GetFilePath() << endl; + return false; + } + attrs.push_back(quantityValue); + values.push_back(quantityValue); + values.push_back(arrayItem[TAG_VALUE].asString()); + return true; + }); + if (!result) { + return false; + } + if (find(attrs.begin(), attrs.end(), "other") == attrs.end()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity must contains 'other',"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} + +bool JsonCompiler::PushString(const string &value, ResourceItem &resourceItem) const +{ + if (!resourceItem.SetData(reinterpret_cast(value.c_str()), value.length())) { + cerr << "Error: resourceItem setdata fail,'" << resourceItem.GetName() << "',"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} + +bool JsonCompiler::CheckJsonStringValue(const Json::Value &valueNode, const ResourceItem &resourceItem) const +{ + if (!valueNode.isString()) { + cerr << "Error: '" << resourceItem.GetName() << "' value not string," << resourceItem.GetFilePath() << endl; + return false; + } + + const map REFS = { + { ResType::STRING, "$string:" }, + { ResType::STRARRAY, "$string:" }, + { ResType::COLOR, "$color:" }, + { ResType::FLOAT, "$float:" } + }; + + string value = valueNode.asString(); + ResType type = resourceItem.GetResType(); + regex ref("^\\$.+:"); + smatch result; + if (regex_search(value, result, ref) && result[0] != REFS.at(type)) { + cerr << "Error: '" << value << "' only refer '"<< REFS.at(type) << "xxx',"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} + +bool JsonCompiler::CheckJsonIntegerValue(const Json::Value &valueNode, const ResourceItem &resourceItem) const +{ + if (valueNode.isString()) { + regex ref("^\\$integer:.*"); + if (!regex_match(valueNode.asString(), ref)) { + cerr << "Error: '" << valueNode.asString() << "' only refer '$integer:xxx',"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + } else if (!valueNode.isInt()) { + cerr << "Error: '" << resourceItem.GetName() << "' value not integer," << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} + +bool JsonCompiler::ParseValueArray(const Json::Value &objectNode, ResourceItem &resourceItem, + const vector &extra, HandleValue callback) const +{ + Json::Value arrayNode = objectNode[TAG_VALUE]; + if (!arrayNode.isArray()) { + cerr << "Error: '" << resourceItem.GetName() << "' value not array," << resourceItem.GetFilePath() << endl; + return false; + } + + if (arrayNode.empty()) { + cerr << "Error: '" << resourceItem.GetName() << "' value empty," << resourceItem.GetFilePath() << endl; + return false; + } + + vector contents; + if (!extra.empty()) { + contents.assign(extra.begin(), extra.end()); + } + for (Json::ArrayIndex index = 0; index < arrayNode.size(); index++) { + vector values; + if (!callback(arrayNode[index], resourceItem, values)) { + return false; + } + contents.insert(contents.end(), values.begin(), values.end()); + } + + string data = ResourceUtil::ComposeStrings(contents); + if (data.empty()) { + cerr << "Error: '" << resourceItem.GetName() << "' array too large,"<< resourceItem.GetFilePath() << endl; + return false; + } + return PushString(data, resourceItem); +} + +bool JsonCompiler::ParseParent(const Json::Value &objectNode, const ResourceItem &resourceItem, + vector &extra) const +{ + auto parent = objectNode[TAG_PARENT]; + string type = ResourceUtil::ResTypeToString(resourceItem.GetResType()); + if (!parent.isNull()) { + if (!parent.isString()) { + cerr << "Error: " << type << " '" << resourceItem.GetName() << "' parent not string,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + if (parent.empty()) { + cerr << "Error: " << type << " '"<< resourceItem.GetName() << "' parent empty,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + string parentValue = parent.asString(); + if (regex_match(parentValue, regex("^ohos:" + type + ":.+"))) { + parentValue = "$" + parentValue; + } else { + parentValue = "$" + type + ":" + parentValue; + } + extra.push_back(parentValue); + } + return true; +} + +bool JsonCompiler::ParseAttribute(const Json::Value &arrayItem, const ResourceItem &resourceItem, + vector &values) const +{ + string type = ResourceUtil::ResTypeToString(resourceItem.GetResType()); + if (!arrayItem.isObject()) { + cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute not object,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + auto name = arrayItem[TAG_NAME]; + if (name.empty()) { + cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute name empty,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + if (!name.isString()) { + cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute name not string,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + values.push_back(name.asString()); + + auto value = arrayItem[TAG_VALUE]; + if (value.isNull()) { + cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute '" << name.asString(); + cerr << "' value empty," << resourceItem.GetFilePath() << endl; + return false; + } + if (!value.isString()) { + cerr << "Error: " << type << " '" << resourceItem.GetName() << "' attribute '" << name.asString(); + cerr << "' value not string," << resourceItem.GetFilePath() << endl; + return false; + } + values.push_back(value.asString()); + return true; +} + +bool JsonCompiler::CheckPluralValue(const Json::Value &arrayItem, const ResourceItem &resourceItem) const +{ + if (!arrayItem.isObject()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' array item not object,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + auto quantity = arrayItem[TAG_QUANTITY]; + if (quantity.empty()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity empty,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + if (!quantity.isString()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity not string,"; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + string quantityValue = quantity.asString(); + if (find(QUANTITY_ATTRS.begin(), QUANTITY_ATTRS.end(), quantityValue) == QUANTITY_ATTRS.end()) { + string buffer(" "); + for_each(QUANTITY_ATTRS.begin(), QUANTITY_ATTRS.end(), [&buffer](auto iter) { + buffer.append(iter).append(" "); + }); + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; + cerr << "' not in [" << buffer << "]," << resourceItem.GetFilePath() << endl; + return false; + } + + auto value = arrayItem[TAG_VALUE]; + if (value.isNull()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; + cerr << "' value empty" << resourceItem.GetFilePath() << endl; + return false; + } + if (!value.isString()) { + cerr << "Error: Plural '" << resourceItem.GetName() << "' quantity '" << quantityValue; + cerr << "' value not string" << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/key_parser.cpp b/src/key_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3368d738c90ba6b01dcae4d14be43ef16011a349 --- /dev/null +++ b/src/key_parser.cpp @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "key_parser.h" +#include +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +map> KeyParser::caches_ = {}; +bool KeyParser::Parse(const string &folderName, vector &keyparams) +{ + if (folderName == "base") { + return true; + } + + if (caches_.count(folderName) != 0) { + keyparams = caches_[folderName]; + return true; + } + vector keyParts; + ResourceUtil::Split(folderName, keyParts, "-"); + + vector founctions = { + ParseMccMnc, + ParseLSR, + ParseOrientation, + ParseDeviceType, + ParseNightMode, + ParseResolution, + }; + + if (!ParseMatch(keyParts, keyparams, founctions)) { + return false; + } + caches_.emplace(folderName, keyparams); + return true; +} + +bool KeyParser::ParseMatch(const vector &keys, vector &keyparams, const vector &founctions) +{ + size_t next = 0; + for (const auto &key : keys) { + bool parseMatch = false; + for (size_t i = next; i < founctions.size(); i++) { + if (founctions[i](key, keyparams)) { + parseMatch = true; + next = i; + break; + } + } + + if (!parseMatch) { + return false; + } + } + return true; +} + +bool KeyParser::ParseMatchBySeq(const vector &keys, vector &keyparams, const vector &founctions) +{ + for (size_t i = 0; i < keys.size(); i++) { + if (!founctions[i](keys[i], keyparams)) { + return false; + } + } + return true; +} + +bool KeyParser::ParseMccMnc(const string &folderName, vector &keyparams) +{ + vector founctions = { + ParseMcc, + ParseMnc, + }; + + vector keyParts; + ResourceUtil::Split(folderName, keyParts, "_"); + if (keyParts.size() > founctions.size()) { + return false; + } + return ParseMatchBySeq(keyParts, keyparams, founctions); +} + +bool KeyParser::ParseMcc(const string &folderName, vector &keyparams) +{ + regex mcc("mcc(\\d{3})"); + if (!regex_match(folderName, mcc)) { + return false; + } + + PushMccMnc(folderName, KeyType::MCC, keyparams); + return true; +} + +bool KeyParser::ParseMnc(const string &folderName, vector &keyparams) +{ + regex mcc("mnc(\\d{2,3})"); + if (!regex_match(folderName, mcc)) { + return false; + } + + PushMccMnc(folderName, KeyType::MNC, keyparams); + return true; +} + +bool KeyParser::ParseLSR(const string &folderName, vector &keyparams) +{ + map> founctionModels = { + { "all", { ParseLanguage, ParseScript, ParseRegion } }, + { "language script", { ParseLanguage, ParseScript} }, + { "language region", { ParseLanguage, ParseRegion } }, + }; + + vector keyParts; + ResourceUtil::Split(folderName, keyParts, "_"); + if (keyParts.size() > founctionModels["all"].size()) { + return false; + } + + for (auto model : founctionModels) { + vector tmp; + if (ParseMatchBySeq(keyParts, tmp, model.second)) { + keyparams.insert(keyparams.end(), tmp.begin(), tmp.end()); + return true; + } + } + return false; +} + +bool KeyParser::ParseLanguage(const string &folderName, vector &keyparams) +{ + if (g_deviceMap.find(folderName) != g_deviceMap.end()) { + return false; + } + + regex language("[a-z]{2,3}"); + if (!regex_match(folderName, language)) { + return false; + } + + PushLSR(folderName, KeyType::LANGUAGE, keyparams); + return true; +} + +bool KeyParser::ParseScript(const string &folderName, vector &keyparams) +{ + if (folderName.length() != SCRIPT_LENGHT) { + return false; + } + + regex script("^[A-Z][a-z]{3}"); + if (!regex_match(folderName, script)) { + return false; + } + + PushLSR(folderName, KeyType::SCRIPT, keyparams); + return true; +} + +bool KeyParser::ParseRegion(const string &folderName, vector &keyparams) +{ + if (folderName.length() < MIN_REGION_LENGHT || folderName.length() > MAX_REGION_LENGHT) { + return false; + } + + regex regionOfNumber("[0-9]{3}"); + regex regionOfSupper("[A-Z]{2,3}"); + + if (!regex_match(folderName, regionOfNumber) && !regex_match(folderName, regionOfSupper)) { + return false; + } + + PushLSR(folderName, KeyType::REGION, keyparams); + return true; +} + +bool KeyParser::ParseOrientation(const string &folderName, vector &keyparams) +{ + auto it = g_orientaionMap.find(folderName); + if (it == g_orientaionMap.end()) { + return false; + } + + PushValue(static_cast(it->second), KeyType::ORIENTATION, keyparams); + return true; +} + +bool KeyParser::ParseDeviceType(const string &folderName, vector &keyparams) +{ + auto it = g_deviceMap.find(folderName); + if (it == g_deviceMap.end()) { + return false; + } + + PushValue(static_cast(it->second), KeyType::DEVICETYPE, keyparams); + return true; +} + +bool KeyParser::ParseNightMode(const string &folderName, vector &keyparams) +{ + auto it = g_nightModeMap.find(folderName); + if (it == g_nightModeMap.end()) { + return false; + } + + PushValue(static_cast(it->second), KeyType::NIGHTMODE, keyparams); + return true; +} + +bool KeyParser::ParseResolution(const string &folderName, vector &keyparams) +{ + auto it = g_resolutionMap.find(folderName); + if (it == g_resolutionMap.end()) { + return false; + } + + PushValue(static_cast(it->second), KeyType::RESOLUTION, keyparams); + return true; +} + +void KeyParser::PushMccMnc(const string &folderName, KeyType type, vector &keyparams) +{ + KeyParam keyParam; + keyParam.keyType = type; + keyParam.value = atoi(folderName.substr(MCC_MNC_KEY_LENGHT).c_str()); + keyparams.push_back(keyParam); +} + +void KeyParser::PushLSR(const string &folderName, KeyType type, vector &keyparams) +{ + KeyParam keyParam; + keyParam.keyType = type; + keyParam.value = 0; + for (size_t i = 0; i < folderName.size(); i++) { + keyParam.value = (keyParam.value << 8) | (folderName[i] & 0xff); + } + keyparams.push_back(keyParam); +} + +void KeyParser::PushValue(uint32_t value, KeyType type, vector &keyparams) +{ + KeyParam keyParam; + keyParam.keyType = type; + keyParam.value = value; + keyparams.push_back(keyParam); +} +} +} +} \ No newline at end of file diff --git a/src/module_combine.cpp b/src/module_combine.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5cfaa9bf2fc93b8e44fd3d5637b66cefc8c6654d --- /dev/null +++ b/src/module_combine.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "module_combine.h" +#include +#include +#include +#include "key_manager.h" +#include "resource_util.h" +#include "solid_xml.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +ModuleCombine::ModuleCombine(const string &modulePath, const string &outputPath) + : modulePath_(modulePath), outputPath_(outputPath) +{ +} + +bool ModuleCombine::Combine() +{ + string resourceDir = filesystem::path(modulePath_).append(RESOURCES_DIR).string(); + ResourceDirectory resourceDirectory; + if (!resourceDirectory.ScanResources(resourceDir, [this](const DirectoryInfo &info) -> bool { + return CombineDirectory(info); + })) { + return false; + } + return true; +} + +// below private +bool ModuleCombine::CombineDirectory(const DirectoryInfo &directoryInfo) +{ + string outputFolder = filesystem::path(outputPath_).append(RESOURCES_DIR) + .append(directoryInfo.limitKey).append(directoryInfo.fileCluster).string(); + if (!ResourceUtil::CreateDirs(outputFolder)) { + return false; + } + + map sxmlPaths; + for (const auto &entry : filesystem::directory_iterator(directoryInfo.dirPath)) { + string src = entry.path().string(); + if (entry.is_directory()) { + cerr << "Error: " << src << " is directory." << endl; + return false; + } + + string filename = entry.path().filename().string(); + string dst = filesystem::path(outputFolder).append(filename).string(); + if (ResourceUtil::FileExist(dst)) { + continue; + } + + if (entry.path().extension().string() == ".sxml") { + sxmlPaths.emplace(src, dst); + continue; + } + + auto result = find_if (XmlKeyNode::KEY_TO_FILE_NAME.begin(), XmlKeyNode::KEY_TO_FILE_NAME.end(), + [&filename](const auto &iter) { + return filename == iter.second; + }); + if (result != XmlKeyNode::KEY_TO_FILE_NAME.end()) { + continue; + } + + if (!ResourceUtil::CopyFleInner(src, dst)) { + return true; + } + } + return CombineSolidXml(directoryInfo.dirPath, outputFolder, sxmlPaths); +} + +bool ModuleCombine::CombineSolidXml(const string &src, const string &dst, const map &sxmlPaths) +{ + if (sxmlPaths.empty()) { + return true; + } + + KeyManager oldKeyManager; + if (!oldKeyManager.LoadKey(src)) { + return false; + } + + KeyManager newKeyManager; + if (!newKeyManager.LoadKey(dst)) { + return false; + } + + for (const auto &sxmlPath : sxmlPaths) { + SolidXml solidXml(sxmlPath.first, oldKeyManager.GetKeys()); + if (!solidXml.FlushNodeKeys(sxmlPath.second, newKeyManager.GetKeys())) { + return false; + } + } + + if (!newKeyManager.SaveKey(dst)) { + cerr << "Error: GenerateToOther " << modulePath_ << " fail." << endl; + return false; + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/preview_manager.cpp b/src/preview_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..099265e7f62908305c371a09aaedd8382d15a90a --- /dev/null +++ b/src/preview_manager.cpp @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "preview_manager.h" +#include +#include +#include "factory_resource_compiler.h" +#include "key_parser.h" +#include "resource_module.h" +#include "resource_util.h" +#include "sqlite_database.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +PreviewManager::~PreviewManager() +{ + SqliteDatabase &database = SqliteDatabase::GetInstance(); + database.CloseDatabase(); +} + +uint32_t PreviewManager::ScanModules(const vector &modulePaths, const string &output) +{ + + SqliteDatabase &database = SqliteDatabase::GetInstance(); + string dbPath = filesystem::path(output).append("resources.db").string(); + database.Init(dbPath); + if(!database.OpenDatabase()) { + return RESTOOL_ERROR; + } + + int32_t priority = 0; + if (priority_ >= 0) { + priority = priority_; + } + + for (const auto &iter : modulePaths) { + if (filesystem::is_directory(iter)) { + ResourceModule resourceMoudle(iter, output, ""); + resourceMoudle.SetPreviewMode(true); + database.SetPriority(priority); + if (resourceMoudle.ScanResource() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } else if (!ScanFile(iter, priority)) { + return RESTOOL_ERROR; + } + if (priority_ >= 0) { + continue; + } + priority++; + } + return RESTOOL_SUCCESS; +} + +bool PreviewManager::ScanFile(const string &filePath, int32_t priority) +{ + if (!ResourceUtil::FileExist(filePath)) { + cerr << "Error: " << filePath << " non't exist." << endl; + return false; + } + FileInfo fileInfo; + fileInfo.filePath = filePath; + fileInfo.filename = filesystem::path(filePath).filename().string(); + fileInfo.dirPath = filesystem::path(filePath).parent_path().string(); + fileInfo.fileCluster = filesystem::path(fileInfo.dirPath).filename().string(); + fileInfo.limitKey = filesystem::path(fileInfo.dirPath).parent_path().filename().string(); + + fileInfo.dirType = ResourceUtil::GetResTypeByDir(fileInfo.fileCluster); + if (fileInfo.dirType == ResType::INVALID_RES_TYPE) { + return false; + } + + if (!KeyParser::Parse(fileInfo.limitKey, fileInfo.keyParams)) { + return false; + } + + unique_ptr resourceCompiler = + FactoryResourceCompiler::CreateCompiler(fileInfo.dirType, ""); + resourceCompiler->SetPreviewMode(true); + resourceCompiler->SetModuleName(""); + if (resourceCompiler->Compile(fileInfo) != RESTOOL_SUCCESS) { + return false; + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/reference_parser.cpp b/src/reference_parser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..530c9444aa7817a381a9fe5fedf8b1edc5dadd35 --- /dev/null +++ b/src/reference_parser.cpp @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "reference_parser.h" +#include +#include +#include "restool_errors.h" +#include "xml_key_node.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const map ReferenceParser::ID_REFS = { + { "^\\$id:", ResType::ID }, + { "^\\$boolean:", ResType::BOOLEAN }, + { "^\\$color:", ResType::COLOR }, + { "^\\$float:", ResType::FLOAT }, + { "^\\$media:", ResType::MEDIA }, + { "^\\$profile:", ResType::PROF }, + { "^\\$integer:", ResType::INTEGER }, + { "^\\$string:", ResType::STRING }, + { "^\\$layout:", ResType::LAYOUT }, + { "^\\$pattern:", ResType::PATTERN }, + { "^\\$plural:", ResType::PLURAL }, + { "^\\$graphic:", ResType::GRAPHIC }, + { "^\\$theme:", ResType::THEME } +}; + +const map ReferenceParser::ID_OHOS_REFS = { + { "^\\$ohos:id:", ResType::ID }, + { "^\\$ohos:boolean:", ResType::BOOLEAN }, + { "^\\$ohos:color:", ResType::COLOR }, + { "^\\$ohos:float:", ResType::FLOAT }, + { "^\\$ohos:media:", ResType::MEDIA }, + { "^\\$ohos:profile:", ResType::PROF }, + { "^\\$ohos:integer:", ResType::INTEGER }, + { "^\\$ohos:string:", ResType::STRING }, + { "^\\$ohos:layout:", ResType::LAYOUT }, + { "^\\$ohos:pattern:", ResType::PATTERN }, + { "^\\$ohos:plural:", ResType::PLURAL }, + { "^\\$ohos:graphic:", ResType::GRAPHIC }, + { "^\\$ohos:theme:", ResType::THEME } +}; + +ReferenceParser::ReferenceParser() : idWorker_(IdWorker::GetInstance()) +{ +} + +ReferenceParser::~ReferenceParser() +{ +} + +uint32_t ReferenceParser::ParseRefInSolidXml(const vector &solidXmlFolders) const +{ + for (const auto &solidXmlFolder : solidXmlFolders) { + string filePath = filesystem::path(solidXmlFolder) + .append(XmlKeyNode::KEY_TO_FILE_NAME.at(XmlKeyNode::KeyType::CONSTANT)).string(); + if (!ResourceUtil::FileExist(filePath)) { + continue; + } + + XmlKeyNode xmlKeyNode; + if (!xmlKeyNode.LoadFromFile(filePath, [this](auto &key) -> bool { + return ParseRefString(key); + })) { + return RESTOOL_ERROR; + } + + if (!xmlKeyNode.SaveToFile(filePath)) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ReferenceParser::ParseRefInElement(map> &alls) const +{ + for (auto &iter : alls) { + for (auto &resourceItem : iter.second) { + if (IsNotElement(resourceItem.GetResType())) { + break; + } + if (!ParseRefResourceItem(resourceItem)) { + return RESTOOL_ERROR; + } + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ReferenceParser::ParseRefInString(string &value, bool &update) const +{ + if (ParseRefString(value, update)) { + return RESTOOL_SUCCESS; + } + return RESTOOL_ERROR; +} + +uint32_t ReferenceParser::ParseRefInProfile(const string &output) const +{ + string profileFolder = filesystem::path(output).append(RESOURCES_DIR).append("base").append("profile").string(); + if (!ResourceUtil::FileExist(profileFolder)) { + return RESTOOL_SUCCESS; + } + + for (const auto &entry : filesystem::directory_iterator(profileFolder)) { + if (entry.is_directory()) { + cerr << "Error: '" << entry.path().string() << "' is directory." << endl; + return false; + } + + if (entry.path().extension() != ".json" ) { + continue; + } + + if (ParseRefInJson(entry.path().string()) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ReferenceParser::ParseRefInJson(const string &filePath) const +{ + Json::Value root; + if (!ResourceUtil::OpenJsonFile(filePath, root)) { + return RESTOOL_ERROR; + } + + if (!ParseRefJsonImpl(root)) { + return RESTOOL_ERROR; + } + + if (!ResourceUtil::SaveToJsonFile(filePath, root)) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +bool ReferenceParser::ParseRefResourceItem(ResourceItem &resourceItem) const +{ + ResType resType = resourceItem.GetResType(); + string data; + bool update = false; + if (IsStringOfResourceItem(resType)) { + data= string(reinterpret_cast(resourceItem.GetData()), resourceItem.GetDataLength()); + if (!ParseRefString(data, update)) { + cerr << "Error: in " << resourceItem.GetFilePath() << endl; + return false; + } + if (!update) { + return true; + } + } else if (IsArrayOfResourceItem(resType)) { + if (!ParseRefResourceItemData(resourceItem, data, update)) { + return false; + } + if (!update) { + return true; + } + } + if (update && !resourceItem.SetData(reinterpret_cast(data.c_str()), data.length())) { + cerr << "Error: set data fail '" << resourceItem.GetName() << "' in " << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} + +bool ReferenceParser::ParseRefResourceItemData(const ResourceItem &resourceItem, string &data, bool &update) const +{ + data = string(reinterpret_cast(resourceItem.GetData()), resourceItem.GetDataLength()); + vector contents = ResourceUtil::DecomposeStrings(data); + if (contents.empty()) { + cerr << "Error: DecomposeStrings fail '" << resourceItem.GetName() << "' in "; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + + for (auto &content : contents) { + bool flag = false; + if (!ParseRefString(content, flag)) { + cerr << "Error: in " << resourceItem.GetFilePath() << endl; + return false; + } + update = (update || flag); + } + + if (!update) { + return true; + } + + data = ResourceUtil::ComposeStrings(contents); + if (data.empty()) { + cerr << "Error: ComposeStrings fail '" << resourceItem.GetName() << "' in "; + cerr << resourceItem.GetFilePath() << endl; + return false; + } + return true; +} + +bool ReferenceParser::IsStringOfResourceItem(ResType resType) const +{ + if (resType == ResType::STRING || + resType == ResType::INTEGER || + resType == ResType::BOOLEAN || + resType == ResType::COLOR || + resType == ResType::FLOAT) { + return true; + } + return false; +} + +bool ReferenceParser::IsArrayOfResourceItem(ResType resType) const +{ + if (resType == ResType::STRARRAY || + resType == ResType::INTARRAY || + resType == ResType::PLURAL || + resType == ResType::THEME || + resType == ResType::PATTERN) { + return true; + } + return false; +} + +bool ReferenceParser::IsNotElement(ResType resType) const +{ + auto result = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [resType](const auto &iter) { + return resType == iter.second; + }); + if (result == g_contentClusterMap.end()) { + return true; + } + return false; +} + +bool ReferenceParser::ParseRefString(string &key) const +{ + bool update = false; + return ParseRefString(key, update); +} + +bool ReferenceParser::ParseRefString(std::string &key, bool &update) const +{ + update = false; + if (regex_match(key, regex("^\\$ohos:[a-z]+:.+"))) { + update = true; + return ParseRefImpl(key, ID_OHOS_REFS, true); + } else if (regex_match(key, regex("^\\$[a-z]+:.+"))) { + update = true; + return ParseRefImpl(key, ID_REFS, false); + } + return true; +} + +bool ReferenceParser::ParseRefImpl(string &key, const map &refs, bool isSystem) const +{ + for (const auto &ref : refs) { + smatch result; + if (regex_search(key, result, regex(ref.first))) { + string name = key.substr(result[0].str().length()); + int32_t id = idWorker_.GetId(ref.second, name); + if (isSystem) { + id = idWorker_.GetSystemId(ref.second, name); + } else { + id = idWorker_.GetId(ref.second, name); + } + if (id < 0) { + cerr << "Error: ref '" << key << "' don't be defined." << endl; + return false; + } + + key = to_string(id); + if (ref.second != ResType::ID) { + key = key = "$" + ResourceUtil::ResTypeToString(ref.second) + ":" + to_string(id); + } + return true; + } + } + cerr << "Error: reference '" << key << "' invalid." << endl; + return false; +} + +bool ReferenceParser::ParseRefJsonImpl(Json::Value &node) const +{ + if (node.isObject()) { + for (const auto &member : node.getMemberNames()) { + if (!ParseRefJsonImpl(node[member])) { + return false; + } + } + } else if (node.isArray()) { + for (Json::ArrayIndex i = 0; i < node.size(); i++) { + if (!ParseRefJsonImpl(node[i])) { + return false; + } + } + } else if (node.isString()) { + string value = node.asString(); + if (!ParseRefString(value)) { + return false; + } + node = value; + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/resource_directory.cpp b/src/resource_directory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a92b3f9051b752a95c2d29c5e8d1cb752d7fb44d --- /dev/null +++ b/src/resource_directory.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_directory.h" +#include +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +bool ResourceDirectory::ScanResources(const string &resourcesDir, function callback) const +{ + for (auto &it : filesystem::directory_iterator(resourcesDir)) { + string limitKey = it.path().filename().string(); + if (ResourceUtil::IsIgnoreFile(limitKey, it.status().type())) { + continue; + } + + if (!it.is_directory()) { + cerr << "Error: '" << it.path().string() << "' not directory." << endl; + return false; + } + + if (limitKey == RAW_FILE_DIR) { + continue; + } + + if (!ScanResourceLimitKeyDir(it.path().string(), limitKey, callback)) { + return false; + } + } + return true; +} + +// below private +bool ResourceDirectory::ScanResourceLimitKeyDir(const string &resourceTypeDir, const string &limitKey, + function callback) const +{ + vector keyParams; + if (!KeyParser::Parse(limitKey, keyParams)) { + cerr << "Error: " << resourceTypeDir << ",invalid limit key '" << limitKey << "'" << endl; + return false; + } + + for (auto &it : filesystem::directory_iterator(resourceTypeDir)) { + string dirPath = it.path().string(); + string fileCluster = it.path().filename().string(); + if (ResourceUtil::IsIgnoreFile(fileCluster, it.status().type())) { + continue; + } + + if (!it.is_directory()) { + cerr << "Error: '" << dirPath << "' not directory." << endl; + return false; + } + + ResType type = ResourceUtil::GetResTypeByDir(fileCluster); + if (type == ResType::INVALID_RES_TYPE) { + string array("[ "); + for (auto item : g_fileClusterMap) { + array.append("'" + item.first + "' "); + } + array.append("]"); + cerr << "Error: " << dirPath << " ,invalid directory name '"; + cerr << fileCluster << "', must in " << array << endl; + return false; + } + DirectoryInfo info = { limitKey, fileCluster, dirPath, keyParams, type }; + if (callback && !callback(info)) { + return false; + } + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/resource_item.cpp b/src/resource_item.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d11b6d03da0d07c91190404123d647a5e74600a4 --- /dev/null +++ b/src/resource_item.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_item.h" +#include +#include "securec.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +ResourceItem::ResourceItem() +{ +} + +ResourceItem::ResourceItem(const ResourceItem &other) +{ + CopyFrom(other); +} + +ResourceItem::ResourceItem(const string &name, const vector &keyparams, ResType type) + :data_(nullptr), dataLen_(0), name_(name),keyparams_(keyparams), type_(type) +{ +} + +ResourceItem::~ResourceItem() +{ + ReleaseData(); +} + +bool ResourceItem::SetData(const string &data) +{ + return SetData(reinterpret_cast(data.c_str()), data.length() + 1); +} + +bool ResourceItem::SetData(const int8_t *data, uint32_t length) +{ + if (data == nullptr || length <= 0) { + return false; + } + + ReleaseData(); + int8_t *buffer = reinterpret_cast(new (nothrow) int8_t[length]); + if (buffer == nullptr) { + return false; + } + + bool result = (memset_s(buffer, length, 0, length) == EOK); + result = result && (memcpy_s(buffer, length, data, length) == EOK); + data_ = buffer; + dataLen_ = length; + return result; +} + +void ResourceItem::SetFilePath(const string &filePath) +{ + filePath_ = filePath; +} + +void ResourceItem::SetLimitKey(const string &limitKey) +{ + limitKey_ = limitKey; +} + +const int8_t *ResourceItem::GetData() const +{ + return data_; +} + +const uint32_t ResourceItem::GetDataLength() const +{ + return dataLen_; +} + +const string &ResourceItem::GetName() const +{ + return name_; +} + +const ResType &ResourceItem::GetResType() const +{ + return type_; +} + +const vector &ResourceItem::GetKeyParam() const +{ + return keyparams_; +} + +const string &ResourceItem::GetFilePath() const +{ + return filePath_; +} + +const string &ResourceItem::GetLimitKey() const +{ + return limitKey_; +} + +ResourceItem &ResourceItem::operator=(const ResourceItem &other) +{ + if (this == &other) { + return *this; + } + CopyFrom(other); + return *this; +} + +//below private founction +void ResourceItem::ReleaseData() +{ + if (data_ != nullptr) { + delete[] data_; + data_ = nullptr; + dataLen_ = 0; + } +} + +void ResourceItem::CopyFrom(const ResourceItem &other) +{ + name_ = other.name_; + keyparams_ = other.keyparams_; + type_ = other.type_; + dataLen_ = other.dataLen_; + filePath_ = other.filePath_; + limitKey_ = other.limitKey_; + if (!SetData(other.data_, other.dataLen_)) { + ReleaseData(); + } +} +} +} +} \ No newline at end of file diff --git a/src/resource_merge.cpp b/src/resource_merge.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac62b0980908eab656fd61ffaf35738f22da80fd --- /dev/null +++ b/src/resource_merge.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_merge.h" +#include "cmd_parser.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const vector ResourceMerge::ORDERS = { + ConfigParser::ModuleType::NONE, + ConfigParser::ModuleType::ENTRY, + ConfigParser::ModuleType::FEATURE, + ConfigParser::ModuleType::HAR +}; + +ResourceMerge::ResourceMerge() +{ +} + +ResourceMerge::~ResourceMerge() +{ +} + +uint32_t ResourceMerge::Init() +{ + auto &cmdParser = CmdParser::GetInstance().GetCmdParser(); + const vector &inputs = cmdParser.GetInputs(); + if (cmdParser.IsFileList()) { + inputsOrder_ = inputs; + return RESTOOL_SUCCESS; + } + + map> inputTypes; + for (auto it = inputs.crbegin(); it != inputs.crend(); it++) { + string filePath = filesystem::path(*it).append(ConfigParser::GetConfigName()).string(); + string resourceDir = filesystem::path(*it).append(RESOURCES_DIR).string(); + ConfigParser::ModuleType moduleType = ConfigParser::ModuleType::NONE; + if (!ResourceUtil::FileExist(filePath)) { + inputTypes[moduleType].push_back(resourceDir); + continue; + } + ConfigParser configParser(filePath); + if (configParser.Init() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + moduleType = configParser.GetModuleType(); + inputTypes[moduleType].push_back(resourceDir); + } + + for (const auto &type : ORDERS) { + if (inputTypes.find(type) == inputTypes.end()) { + continue; + } + inputsOrder_.insert(inputsOrder_.end(), inputTypes[type].begin(), inputTypes[type].end()); + } + return RESTOOL_SUCCESS; +} + +const vector &ResourceMerge::GetInputs() const +{ + return inputsOrder_; +} +} +} +} \ No newline at end of file diff --git a/src/resource_module.cpp b/src/resource_module.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f21322c23e7c5ee0bb7af0e63d7fa609e98e53da --- /dev/null +++ b/src/resource_module.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_module.h" +#include +#include +#include "factory_resource_compiler.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const vector ResourceModule::SCAN_SEQ = { + ResType::ELEMENT, + ResType::MEDIA, + ResType::PROF, + ResType::ANIMATION, + ResType::GRAPHIC, + ResType::LAYOUT, +}; +ResourceModule::ResourceModule(const string &modulePath, const string &moduleOutput, const string &moduleName) + : modulePath_(modulePath), moduleOutput_(moduleOutput), moduleName_(moduleName) +{ +} + +uint32_t ResourceModule::ScanResource() +{ + if (!ResourceUtil::FileExist(modulePath_)) { + return RESTOOL_SUCCESS; + } + + ResourceDirectory directory; + if (!directory.ScanResources(modulePath_,[this](const DirectoryInfo &info) -> bool { + scanDirs_[info.dirType].push_back(info); + return true; + })) { + return RESTOOL_ERROR; + } + + for (const auto &type : SCAN_SEQ) { + const auto &item = scanDirs_.find(type); + if (item == scanDirs_.end() || item->second.empty()) { + continue; + } + + unique_ptr resourceCompiler = + FactoryResourceCompiler::CreateCompiler(type, moduleOutput_); + resourceCompiler->SetModuleName(moduleName_); + resourceCompiler->SetPreviewMode(previewMode_); + if (resourceCompiler->Compile(item->second) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + Push(resourceCompiler->GetResult()); + } + return RESTOOL_SUCCESS; +} + +const map> &ResourceModule::GetOwner() const +{ + return owner_; +} + +const map> &ResourceModule::GetScanDirectorys() const +{ + return scanDirs_; +} + +uint32_t ResourceModule::MergeResourceItem(map> &alls, + const map> &other, bool tipError) +{ + for (const auto &iter : other) { + auto result = alls.emplace(iter.first, iter.second); + if (result.second) { + continue; + } + + for (const auto &resourceItem : iter.second) { + auto ret = find_if(result.first->second.begin(), result.first->second.end(), [&resourceItem](auto &iter) { + return resourceItem.GetLimitKey() == iter.GetLimitKey(); + }); + if (ret == result.first->second.end()) { + result.first->second.push_back(resourceItem); + continue; + } + string error = resourceItem.GetName() + "' conflict, first declared in " + \ + ret->GetFilePath() + ", but declared again in " + resourceItem.GetFilePath(); + if (tipError) { + cerr << "Error: " << error << endl; + return RESTOOL_ERROR; + } + cout << "Warning: " << error << endl; + } + } + return RESTOOL_SUCCESS; +} +// below private +void ResourceModule::Push(const map> &other) +{ + if (previewMode_) { + return; + } + + for (const auto &iter : other) { + owner_.emplace(iter.first, iter.second); + } +} +} +} +} \ No newline at end of file diff --git a/src/resource_module_inc.cpp b/src/resource_module_inc.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c1b503852a0f6338910553a694dd70386f89d1af --- /dev/null +++ b/src/resource_module_inc.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_module_inc.h" +#include +#include +#include "factory_resource_compiler.h" +#include "increment_index.h" +#include "restool_errors.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +ResourceModuleInc::ResourceModuleInc(const string &modulePath, const string &moduleOutput, + const string &moduleName, const vector &folder) + : ResourceModule(modulePath, moduleOutput, moduleName), folder_(folder) +{ +} + +uint32_t ResourceModuleInc::ScanResource(const vector &fileIncrements) +{ + vector skips; + for (const auto &fileIncrement : fileIncrements) { + skips.push_back(fileIncrement.filePath); + if (fileIncrement.dirType == ResType::ELEMENT) { + continue; + } + string filePathDel = filesystem::path(moduleOutput_).append(RESOURCES_DIR) + .append(fileIncrement.limitKey).append(fileIncrement.fileCluster).append(fileIncrement.filename).string(); + if (ResourceUtil::NeedConverToSolidXml(fileIncrement.dirType) && + filesystem::path(filePathDel).extension().string() == ".xml") { + filePathDel = filesystem::path(filePathDel).replace_extension(".sxml").string(); + } + if (!filesystem::remove(filePathDel)) { + cerr << "Error: delete '" << filePathDel << "' fail" << endl; + return RESTOOL_ERROR; + } + } + + string indexPath = filesystem::path(moduleOutput_).append(IncrementIndex::INDEX_FILE).string(); + IncrementIndex moduleIndex(indexPath, folder_); + moduleIndex.SetSkipPaths(skips); + if (!moduleIndex.Load(owner_)) { + return RESTOOL_ERROR; + } + + for (const auto &fileIncrement : fileIncrements) { + unique_ptr resourceCompiler = + FactoryResourceCompiler::CreateCompiler(fileIncrement.dirType, moduleOutput_); + resourceCompiler->SetModuleName(moduleName_); + if (resourceCompiler->Compile(fileIncrement) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (MergeResourceItem(owner_, resourceCompiler->GetResult(), true) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourceModuleInc::SaveIndex() const +{ + string indexPath = filesystem::path(moduleOutput_).append(IncrementIndex::INDEX_FILE).string(); + IncrementIndex moduleIndex(indexPath, folder_); + if (!moduleIndex.Save(owner_)) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} +} +} +} \ No newline at end of file diff --git a/src/resource_pack.cpp b/src/resource_pack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..94792d0fb53c36f157efbf44bff60684c48e18e0 --- /dev/null +++ b/src/resource_pack.cpp @@ -0,0 +1,357 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_pack.h" +#include +#include +#include "file_manager.h" +#include "header.h" +#include "increment_manager.h" +#include "resource_merge.h" +#include "resource_table.h" + +#include "preview_manager.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +ResourcePack::ResourcePack(const PackageParser &packageParser):packageParser_(packageParser) +{ +} + +uint32_t ResourcePack::Package() +{ + if (packageParser_.GetPreviewMode()) { + PreviewManager preview; + preview.SetPriority(packageParser_.GetPriority()); + return preview.ScanModules(packageParser_.GetInputs(), packageParser_.GetOutput()); + } + if (Init() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + ResourceMerge resourceMerge; + if (resourceMerge.Init() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (ScanResources(resourceMerge.GetInputs(), packageParser_.GetOutput()) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (GenerateHeader() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (CopyRawFile(resourceMerge.GetInputs()) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (GenerateConfigJson() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + ResourceTable resourceTable; + if (resourceTable.CreateResourceTable() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +//below private founction +uint32_t ResourcePack::Init() +{ + InitHeaderCreater(); + if (InitOutput() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (InitConfigJson() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + + if (InitModule() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::InitModule() +{ + IdWorker::ResourceIdCluster hapType = IdWorker::ResourceIdCluster::RES_ID_APP; + string packageName = packageParser_.GetPackageName(); + if (packageName == "ohos.global.systemres") { + hapType = IdWorker::ResourceIdCluster::RES_ID_SYS; + } + + moduleName_ = configJson_.GetModuleName(); + vector moduleNames = packageParser_.GetModuleNames(); + IdWorker &idWorker = IdWorker::GetInstance(); + int32_t startId = packageParser_.GetStartId(); + if (startId > 0) { + return idWorker.Init(hapType, startId); + } + + if (moduleNames.empty()) { + return idWorker.Init(hapType); + } else { + sort(moduleNames.begin(), moduleNames.end()); + auto it = find_if(moduleNames.begin(), moduleNames.end(), [this](auto iter) { + return moduleName_ == iter; + }); + if (it == moduleNames.end()) { + string buffer(" "); + for_each(moduleNames.begin(), moduleNames.end(), [&buffer](auto &iter) { + buffer.append(" " + iter + " "); + }); + cerr << "Error: module name '" << moduleName_ << "' not in [" << buffer << "]" << endl; + return RESTOOL_ERROR; + } + + int32_t startId = ((it - moduleNames.begin()) + 1) * 0x01000000; + if (startId == 0x07000000) { + startId = startId + 0x01000000; + } + return idWorker.Init(hapType, startId); + } + return RESTOOL_SUCCESS; +} + +void ResourcePack::InitHeaderCreater() +{ + using namespace placeholders; + headerCreaters_.emplace(".txt", bind(&ResourcePack::GenerateTextHeader, this, _1)); + headerCreaters_.emplace(".js", bind(&ResourcePack::GenerateJsHeader, this, _1)); + headerCreaters_.emplace(".h", bind(&ResourcePack::GenerateCplusHeader, this, _1)); +} + +uint32_t ResourcePack::InitOutput() const +{ + string cachePath = packageParser_.GetCachePath(); + string indexPath = filesystem::path(cachePath).append(IncrementManager::ID_JSON_FILE).string(); + if (!cachePath.empty() && ResourceUtil::FileExist(indexPath)) { + return RESTOOL_SUCCESS; + } + + bool forceWrite = packageParser_.GetForceWrite(); + string output = packageParser_.GetOutput(); + string resourcesPath = filesystem::path(output).append(RESOURCES_DIR).string(); + if (ResourceUtil::FileExist(resourcesPath)) { + if (!forceWrite) { + cerr << "Error: output path '" << resourcesPath << "' exists." << endl; + return RESTOOL_ERROR; + } + + if (!ResourceUtil::RmoveAllDir(resourcesPath)) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::GenerateHeader() const +{ + auto headerPaths = packageParser_.GetResourceHeaders(); + string textPath = filesystem::path(packageParser_.GetOutput()).append("ResourceTable.txt").string(); + headerPaths.push_back(textPath); + for (const auto &headerPath : headerPaths) { + string extension = filesystem::path(headerPath).extension().string(); + auto it = headerCreaters_.find(extension); + if (it == headerCreaters_.end()) { + cout << "Warning: don't support header file format '" << headerPath << "'" << endl; + continue; + } + if (it->second(headerPath) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::InitConfigJson() +{ + string config = packageParser_.GetConfig(); + if (config.empty()) { + if( packageParser_.GetInputs().size() > 1) { + cerr << "Error: more input path, -j config.json empty" << endl; + return RESTOOL_ERROR; + } + config = filesystem::path(packageParser_.GetInputs()[0]).append(CONFIG_JSON).string(); + if (!ResourceUtil::FileExist(config)) { + config = filesystem::path(packageParser_.GetInputs()[0]).append(MODULE_JSON).string(); + } + } + + if (filesystem::path(config).filename().string() == MODULE_JSON) { + ConfigParser::SetUseModule(); + } + configJson_ = ConfigParser(config); + if (configJson_.Init() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::GenerateTextHeader(const string &headerPath) const +{ + Header textHeader(headerPath); + bool first = true; + uint32_t result = textHeader.Create([](stringstream &buffer) {}, + [&first](stringstream &buffer, const IdWorker::ResourceId& resourceId) { + if (first) { + first = false; + } else { + buffer << "\n"; + } + buffer << resourceId.type << " " << resourceId.name; + buffer << " 0x" << hex << setw(8) << setfill('0') << resourceId.id; + }, [](stringstream &buffer) {}); + if (result != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::GenerateCplusHeader(const string &headerPath) const +{ + Header cplusHeader(headerPath); + uint32_t result = cplusHeader.Create([](stringstream &buffer) { + buffer << Header::LICENSE_HEADER << "\n"; + buffer << "#ifndef RESOURCE_TABLE_H\n"; + buffer << "#define RESOURCE_TABLE_H\n\n"; + buffer << "#include\n\n"; + buffer << "namespace OHOS {\n"; + }, + [](stringstream &buffer, const IdWorker::ResourceId& resourceId) { + string name = resourceId.type + "_" + resourceId.name; + transform(name.begin(), name.end(), name.begin(), ::toupper); + buffer << "const int32_t " << name << " = "; + buffer << "0x" << hex << setw(8) << setfill('0') << resourceId.id << ";\n"; + }, [](stringstream &buffer){ + buffer << "}\n"; + buffer << "#endif"; + }); + return result; +} + +uint32_t ResourcePack::GenerateJsHeader(const std::string &headerPath) const +{ + Header JsHeader(headerPath); + string itemType; + uint32_t result = JsHeader.Create([](stringstream &buffer) { + buffer << Header::LICENSE_HEADER << "\n"; + buffer << "export default {\n"; + }, + [&itemType](stringstream &buffer, const IdWorker::ResourceId& resourceId) { + if (itemType != resourceId.type) { + if (!itemType.empty()) { + buffer << "\n" << " " << "},\n"; + } + buffer << " " << resourceId.type << " : {\n"; + itemType = resourceId.type; + } else { + buffer << ",\n"; + } + buffer << " " << resourceId.name << " : " << resourceId.id; + }, [](stringstream &buffer){ + buffer << "\n" << " " << "}\n"; + buffer << "}\n"; + }); + return result; +} + +uint32_t ResourcePack::CopyRawFile(const vector &inputs) const +{ + for (const auto &input : inputs) { + string rawfilePath = filesystem::path(input).append(RAW_FILE_DIR).string(); + if (!ResourceUtil::FileExist(rawfilePath)) { + continue; + } + + if (!filesystem::is_directory(rawfilePath)) { + cerr << "Error: '" << rawfilePath << "' not directory." << endl; + return RESTOOL_ERROR; + } + + string dst = filesystem::path(packageParser_.GetOutput()).append(RESOURCES_DIR).append(RAW_FILE_DIR).string(); + if (CopyRawFileImpl(rawfilePath, dst) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::CopyRawFileImpl(const string &src, const string &dst) const +{ + if (!ResourceUtil::CreateDirs(dst)) { + return RESTOOL_ERROR; + } + for (const auto &entry : filesystem::directory_iterator(src)) { + string filename = entry.path().filename().string(); + if (ResourceUtil::IsIgnoreFile(filename, entry.status().type())) { + continue; + } + + string subPath = filesystem::path(dst).append(filename).string(); + if (entry.is_directory()) { + if (CopyRawFileImpl(entry.path().string(), subPath) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + } else { + if (ResourceUtil::FileExist(subPath)) { + continue; + } + if (!ResourceUtil::CopyFleInner(entry.path().string(), subPath)) { + return RESTOOL_ERROR; + } + } + } + return RESTOOL_SUCCESS; +} + +uint32_t ResourcePack::GenerateConfigJson() +{ + if (configJson_.ParseRefence() != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + string outputPath = filesystem::path(packageParser_.GetOutput()).append(ConfigParser::GetConfigName()).string(); + return configJson_.Save(outputPath); +} + +uint32_t ResourcePack::ScanResources(const vector &inputs, const string &output) +{ + auto &fileManager = FileManager::GetInstance(); + fileManager.SetModuleName(moduleName_); + string cachePath = packageParser_.GetCachePath(); + if (cachePath.empty()) { + if (fileManager.ScanModules(inputs, output) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; + } + + auto &incrementManager = IncrementManager::GetInstance(); + if (incrementManager.Init(cachePath, inputs, output, moduleName_) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + if (fileManager.ScanIncrement(output) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} +} +} +} \ No newline at end of file diff --git a/src/resource_table.cpp b/src/resource_table.cpp new file mode 100644 index 0000000000000000000000000000000000000000..abfa1b774120a175a6bd4f9fe08297914305d578 --- /dev/null +++ b/src/resource_table.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_table.h" +#include +#include "securec.h" +#include "cmd_parser.h" +#include "file_manager.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +ResourceTable::ResourceTable() +{ + auto &parser =CmdParser::GetInstance(); + auto &packageParser = parser.GetCmdParser(); + indexFilePath_ = filesystem::path(packageParser.GetOutput()).append(RESOURCE_INDEX_FILE).string(); +} + +ResourceTable::~ResourceTable() +{ +} + +uint32_t ResourceTable::CreateResourceTable() +{ + FileManager &fileManager = FileManager::GetInstance(); + auto &allResource = fileManager.GetResources(); + map> configs; + for (const auto &item : allResource) { + for (const auto &resourceItem : item.second) { + if (resourceItem.GetResType() == ResType::ID) { + break; + } + TableData tableData; + tableData.id = item.first; + tableData.resourceItem = resourceItem; + configs[resourceItem.GetLimitKey()].push_back(tableData); + } + } + + if (SaveToResouorceIndex(configs) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +//below private +uint32_t ResourceTable::SaveToResouorceIndex(const map> &configs) const +{ + uint32_t pos = 0; + IndexHeader indexHeader; + if (!InitIndexHeader(indexHeader, configs.size())) { + return RESTOOL_ERROR; + } + pos += sizeof(IndexHeader); + + map limitKeyConfigs; + map idSets; + if (!Prepare(configs, limitKeyConfigs, idSets, pos)) { + return RESTOOL_ERROR; + } + + ofstream out(indexFilePath_, ofstream::out | ofstream::binary); + if (!out.is_open()) { + cerr << "Error: open fail " << indexFilePath_ << endl; + return RESTOOL_ERROR; + } + + if (!SaveRecordItem(configs, out, idSets, pos)) { + return RESTOOL_ERROR; + } + + indexHeader.fileSize = pos; + SaveHeader(indexHeader, out); + SaveLimitKeyConfigs(limitKeyConfigs, out); + SaveIdSets(idSets, out); + return RESTOOL_SUCCESS; +} + +bool ResourceTable::InitIndexHeader(IndexHeader &indexHeader, uint32_t count) const +{ + if (memcpy_s(indexHeader.version, VERSION_MAX_LEN, RESTOOL_VERSION, VERSION_MAX_LEN) != EOK) { + cerr << "Error: InitIndexHeader memcpy_s fail." << endl; + return false; + } + indexHeader.limitKeyConfigSize = count; + return true; +} + +bool ResourceTable::Prepare(const map> &configs, + map &limitKeyConfigs, + map &idSets, uint32_t &pos) const +{ + for (const auto &config : configs) { + LimitKeyConfig limitKeyConfig; + const auto &keyParams = config.second.at(0).resourceItem.GetKeyParam(); + limitKeyConfig.keyCount = keyParams.size(); + pos += sizeof(limitKeyConfig.keyTag) + sizeof(limitKeyConfig.offset) + sizeof(limitKeyConfig.keyCount); + for (const auto &keyParam : keyParams) { + limitKeyConfig.data.push_back(static_cast(keyParam.keyType)); + limitKeyConfig.data.push_back(static_cast(keyParam.value)); + pos += sizeof(KeyParam); + } + limitKeyConfigs.emplace(config.first, limitKeyConfig); + } + + for (const auto &config : configs) { + auto limitKeyConfig = limitKeyConfigs.find(config.first); + if (limitKeyConfig == limitKeyConfigs.end()) { + cerr << "Error: limit key config don't find '" << config.first << "'" << endl; + return false; + } + limitKeyConfig->second.offset = pos; + + IdSet idSet; + idSet.idCount = config.second.size(); + pos += sizeof(idSet.idTag) + sizeof(idSet.idCount); + for (const auto &tableData : config.second) { + idSet.data.emplace(tableData.id, 0); + pos += sizeof(uint32_t) + sizeof(uint32_t); + } + idSets.emplace(config.first, idSet); + } + return true; +} + +bool ResourceTable::SaveRecordItem(const map> &configs, + ofstream &out, map &idSets, uint32_t &pos) const +{ + out.seekp(pos); + for (const auto &config : configs) { + auto idSet = idSets.find(config.first); + if (idSet == idSets.end()) { + cerr << "Error: id set don't find '" << config.first << "'" << endl; + return false; + } + + for (const auto &tableData : config.second) { + if (idSet->second.data.find(tableData.id) == idSet->second.data.end()) { + cerr << "Error: resource table don't find id '" << tableData.id << "'" << endl; + return false; + } + idSet->second.data[tableData.id] = pos; + RecordItem recordItem; + recordItem.id = tableData.id; + recordItem.resType = static_cast(tableData.resourceItem.GetResType()); + vector contents; + string value(reinterpret_cast(tableData.resourceItem.GetData()), + tableData.resourceItem.GetDataLength()); + contents.push_back(value); + string name = ResourceUtil::GetIdName(tableData.resourceItem.GetName(), + tableData.resourceItem.GetResType()); + contents.push_back(name); + string data = ResourceUtil::ComposeStrings(contents, true); + recordItem.size = sizeof(RecordItem) + data.length() - sizeof(uint32_t); + pos += recordItem.size + sizeof(uint32_t); + + out.write(reinterpret_cast(&recordItem.size), sizeof(uint32_t)); + out.write(reinterpret_cast(&recordItem.resType), sizeof(uint32_t)); + out.write(reinterpret_cast(&recordItem.id), sizeof(uint32_t)); + out.write(reinterpret_cast(data.c_str()), data.length()); + } + } + return true; +} + +void ResourceTable::SaveHeader(const IndexHeader &indexHeader, std::ofstream &out) const +{ + out.seekp(0); + out.write(reinterpret_cast(&indexHeader.version), VERSION_MAX_LEN); + out.write(reinterpret_cast(&indexHeader.fileSize), sizeof(uint32_t)); + out.write(reinterpret_cast(&indexHeader.limitKeyConfigSize), sizeof(uint32_t)); +} + +void ResourceTable::SaveLimitKeyConfigs(const map &limitKeyConfigs, ofstream &out) const +{ + for (const auto &iter : limitKeyConfigs) { + out.write(reinterpret_cast(iter.second.keyTag), TAG_LEN); + out.write(reinterpret_cast(&iter.second.offset), sizeof(uint32_t)); + out.write(reinterpret_cast(&iter.second.keyCount), sizeof(uint32_t)); + for (const auto &value : iter.second.data) { + out.write(reinterpret_cast(&value), sizeof(int32_t)); + } + } +} + +void ResourceTable::SaveIdSets(const map &idSets, ofstream &out) const +{ + for (const auto &iter : idSets) { + out.write(reinterpret_cast(iter.second.idTag), TAG_LEN); + out.write(reinterpret_cast(&iter.second.idCount), sizeof(uint32_t)); + for (const auto &keyValue : iter.second.data) { + out.write(reinterpret_cast(&keyValue.first), sizeof(uint32_t)); + out.write(reinterpret_cast(&keyValue.second), sizeof(uint32_t)); + } + } +} +} +} +} diff --git a/src/resource_util.cpp b/src/resource_util.cpp new file mode 100644 index 0000000000000000000000000000000000000000..530fabe01237134f2a30641c0c388203d3d0ebb0 --- /dev/null +++ b/src/resource_util.cpp @@ -0,0 +1,286 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "resource_util.h" +#include +#include +#include +#include +#ifdef __WIN32 +#include "windows.h" +#endif + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const map ResourceUtil::IGNORE_FILE_REGEX = { + { "\\.git", IgnoreType::IGNORE_ALL }, + { "\\.svn", IgnoreType::IGNORE_ALL }, + { ".+\\.scc", IgnoreType::IGNORE_ALL }, + { "\\.ds_store", IgnoreType::IGNORE_ALL }, + { "desktop\\.ini", IgnoreType::IGNORE_ALL }, + { "picasa\\.ini", IgnoreType::IGNORE_ALL }, + { "\\..+", IgnoreType::IGNORE_ALL }, + { "_.+",IgnoreType::IGNORE_DIR }, + { "cvs", IgnoreType::IGNORE_ALL }, + { "thumbs\\.db", IgnoreType::IGNORE_ALL }, + { ".+~", IgnoreType::IGNORE_ALL } +}; + +void ResourceUtil::Split(const string &str, vector &out, const string &splitter) +{ + string::size_type len = str.size(); + string::size_type begin = 0; + string::size_type end = str.find(splitter, begin); + while (end != string::npos) { + string sub = str.substr(begin, end - begin); + out.push_back(sub); + begin = end + splitter.size(); + if (begin >= len) { + break; + } + end = str.find(splitter, begin); + } + + if (begin < len) { + out.push_back(str.substr(begin)); + } +} + +bool ResourceUtil::FileExist(const string &path) +{ + return filesystem::exists(path); +} + +bool ResourceUtil::RmoveAllDir(const string &path) +{ + error_code err; + filesystem::remove_all(path, err); + if (err) { + cerr << "Error: remove all " << path << " failed, msg :=" << err.message() << endl; + return false; + } + return true; +} + +bool ResourceUtil::OpenJsonFile(const string &path, Json::Value &root) +{ + ifstream ifs(path, ios::binary); + if (!ifs) { + cerr << "Error: open json faild '" << path << "'" << endl; + return false; + } + + Json::CharReaderBuilder readBuilder; + readBuilder["collectComments"] = false; + readBuilder["failIfExtra"] = true; + JSONCPP_STRING errs; + if(!parseFromStream(readBuilder, ifs, &root, &errs)) { + cerr << "Error: parseFromStream '" << path; + cerr << "\n" << errs << endl; + ifs.close(); + return false; + } + ifs.close(); + return true; +} + +bool ResourceUtil::SaveToJsonFile(const string &path, const Json::Value &root) +{ + Json::StreamWriterBuilder writerBuilder; + writerBuilder["indentation"] = " "; + writerBuilder["emitUTF8"] = true; + unique_ptr writer(writerBuilder.newStreamWriter()); + ofstream out(path, ofstream::out | ofstream::binary); + if (!out.is_open()) { + cerr << "Error: open fail " << path << endl; + return false; + } + writer->write(root, &out); + out.close(); + return true; +} + +ResType ResourceUtil::GetResTypeByDir(const string &name) +{ + auto ret = g_fileClusterMap.find(name); + if (ret == g_fileClusterMap.end()) { + return ResType::INVALID_RES_TYPE; + } + return ret->second; +} + +string ResourceUtil::ResTypeToString(ResType type) +{ + auto ret = find_if(g_fileClusterMap.begin(), g_fileClusterMap.end(), [type](auto iter) { + return iter.second == type; + }); + if (ret != g_fileClusterMap.end()) { + return ret->first; + } + + ret = find_if(g_contentClusterMap.begin(), g_contentClusterMap.end(), [type](auto iter) { + return iter.second == type; + }); + if (ret != g_contentClusterMap.end()) { + return ret->first; + } + return ""; +} + +string ResourceUtil::GetIdName(const string &name, ResType type) +{ + if (type != ResType::MEDIA && type != ResType::LAYOUT && type != ResType::PROF && + type != ResType::ANIMATION && type != ResType::GRAPHIC ) { + return name; + } + + string::size_type pos = name.find_last_of("."); + if (pos != string::npos) { + return name.substr(0, pos); + } + return name; +} + +string ResourceUtil::ComposeStrings(const vector &contents, bool addNull) +{ + string result; + for (const auto &iter : contents) { + if (iter.length() > UINT16_MAX) { + return ""; + } + + uint16_t size = iter.length(); + if (addNull) { + size += sizeof(char); + } + result.append(sizeof(char), (size & 0xff)); + result.append(sizeof(char), (size >> 8)); + result.append(iter); + result.append(sizeof(char), '\0'); + if (result.length() > UINT16_MAX) { + return ""; + } + } + return result; +} + +vector ResourceUtil::DecomposeStrings(const string &content) +{ + vector result; + size_t length = content.length(); + size_t pos = 0; + const size_t HEAD_LENGTH = 2; + while (pos < length) { + if (pos + HEAD_LENGTH >= length) { + result.clear(); + return result; + } + uint16_t size = (content[pos] & 0xff) | ((content[pos + 1] & 0xff) << 8); + pos += HEAD_LENGTH; + + if (pos + size >= length) { + result.clear(); + return result; + } + string buffer = content.substr(pos, size); + result.push_back(buffer); + pos += size + sizeof(char); + } + return result; +} + +ResType ResourceUtil::GetResTypeFromString(const string &type) +{ + ResType resType = GetResTypeByDir(type); + if (resType != ResType::INVALID_RES_TYPE) { + return resType; + } + + auto ret = g_contentClusterMap.find(type); + if (ret != g_contentClusterMap.end()) { + return ret->second; + } + return ResType::INVALID_RES_TYPE; +} + +bool ResourceUtil::CopyFleInner(const string &src, const string &dst) +{ +#ifdef __WIN32 + if (!CopyFileA(src.c_str(), dst.c_str(), false)) { + cerr << "Error: copy file fail from '" << src << "' to '" << dst << "'" << endl; + return false; + } +#else + error_code err; + filesystem::path from(src); + filesystem::path to(dst); + if (!filesystem::copy_file(from, to, filesystem::copy_options::overwrite_existing, err)) { + cerr << "Error: copy file fail from '" << src << "' to '" << dst << "'" << endl; + cerr << err.message() << endl; + return false; + } +#endif + return true; +} + +bool ResourceUtil::CreateDirs(const string &filePath) +{ + if (FileExist(filePath)) { + return true; + } + + error_code err; + if (!filesystem::create_directories(filePath, err)) { + cerr << "Error: create directory fail '" << filePath << "'" << endl; + return false; + } + return true; +} + +bool ResourceUtil::IsIgnoreFile(const string &filename, filesystem::file_type type) +{ + string key = filename; + transform(key.begin(), key.end(), key.begin(), ::tolower); + for (const auto &iter : IGNORE_FILE_REGEX) { + if ((iter.second == IgnoreType::IGNORE_FILE && type != filesystem::file_type::regular) || + (iter.second == IgnoreType::IGNORE_DIR && type != filesystem::file_type::directory)) { + continue; + } + if (regex_match(key, regex(iter.first))) { + return true; + } + } + return false; +} + +bool ResourceUtil::NeedConverToSolidXml(ResType resType) +{ + if (resType == ResType::LAYOUT || resType == ResType::ANIMATION || + resType == ResType::GRAPHIC) { + return true; + } + return false; +} + +string ResourceUtil::GenerateHash(const std::string key) +{ + hash hash_function; + return to_string(hash_function(key)); +} +} +} +} diff --git a/src/restool.cpp b/src/restool.cpp new file mode 100644 index 0000000000000000000000000000000000000000..979e2888d7d85576df4dc49275a717083ab2c568 --- /dev/null +++ b/src/restool.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmd_parser.h" +#include "task_handle.h" + +using namespace std; +using namespace OHOS::Global::Restool; + +uint32_t ProccssHap(PackageParser &packageParser) { + TaskHandle taskHandle; + return taskHandle.HandlePackage(packageParser); +} + +uint32_t PackCmdHandle(PackageParser &packageParser) +{ + return ProccssHap(packageParser); +} + +int main(int argc, char *argv[]) +{ + auto &parser = CmdParser::GetInstance(); + if (parser.Parse(argc, argv) != RESTOOL_SUCCESS) { + parser.ShowUseage(); + return RESTOOL_ERROR; + } + + auto &packageParser = parser.GetCmdParser(); + if (PackCmdHandle(packageParser) != RESTOOL_SUCCESS) { + return RESTOOL_ERROR; + } + cout << "Info: restool resources compile success." << endl; + return RESTOOL_SUCCESS; +} \ No newline at end of file diff --git a/src/solid_xml_compiler.cpp b/src/solid_xml_compiler.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8efbbde76aa90af8072d853a64673920bcb55b96 --- /dev/null +++ b/src/solid_xml_compiler.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "solid_xml_compiler.h" +#include +#include +#include +#include "restool_errors.h" +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +SolidXmlCompiler::SolidXmlCompiler(ResType type, const string &output) + : GenericCompiler(type, output) +{ +} + +SolidXmlCompiler::~SolidXmlCompiler() +{ +} + +uint32_t SolidXmlCompiler::CompileSingleFile(const FileInfo &fileInfo) +{ + if (!IsXmlFile(fileInfo)) { + cerr << "Error: '" << fileInfo.filePath << "' should be xml file." << endl; + return RESTOOL_ERROR; + } + + if (HasConvertedToSolidXml(fileInfo)) { + return RESTOOL_SUCCESS; + } + + if (!PostFile(fileInfo)) { + return RESTOOL_ERROR; + } + + if (!ParseXml(fileInfo)) { + return RESTOOL_ERROR; + } + return RESTOOL_SUCCESS; +} + +bool SolidXmlCompiler::ParseXml(const FileInfo &fileInfo) +{ + xmlKeepBlanksDefault(0); + xmlDocPtr doc = xmlParseFile(fileInfo.filePath.c_str()); + if (doc == nullptr) { + return false; + } + + vector ids; + bool result = ParseNodeId(fileInfo, xmlDocGetRootElement(doc), ids); + xmlFreeDoc(doc); + if (!result) { + return false; + } + + for (const auto &id : ids) { + ResourceItem resourceItem(id, fileInfo.keyParams, ResType::ID); + resourceItem.SetFilePath(fileInfo.filePath); + resourceItem.SetLimitKey(fileInfo.limitKey); + if (!MergeResourceItem(resourceItem)) { + return false; + } + } + return true; +} + +bool SolidXmlCompiler::ParseNodeId(const FileInfo &fileInfo, const xmlNodePtr &node, vector &ids) +{ + if (node == nullptr) { + return true; + } + + if (node->type == XML_COMMENT_NODE) { + return ParseNodeId(fileInfo, node->next, ids); + } + + string idValue; + xmlChar * xmlValue = xmlGetProp(node, BAD_CAST "id"); + if (xmlValue != nullptr) { + idValue = string(reinterpret_cast(xmlValue)); + xmlFree(xmlValue); + } + + regex ref("^\\$\\+id:"); + smatch result; + if (regex_search(idValue, result, ref)) { + string name = idValue.substr(result[0].str().size()); + if (find(ids.begin(), ids.end(), name) != ids.end()) { + cerr << "Error: '" << idValue << "' duplicated in " << fileInfo.filePath << endl; + return false; + } + ids.push_back(name); + } + + if (!ParseNodeId(fileInfo, node->children, ids)) { + return false; + } + + if (!ParseNodeId(fileInfo, node->next, ids)) { + return false; + } + return true; +} +} +} +} diff --git a/src/sqlite_database.cpp b/src/sqlite_database.cpp new file mode 100644 index 0000000000000000000000000000000000000000..21563fed3395652e8a1d89a2f8b5eb711564fba4 --- /dev/null +++ b/src/sqlite_database.cpp @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "sqlite_database.h" +#include + +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +int32_t SqliteDatabase::id_ = 0; +void SqliteDatabase::Init(const string &dbPath) +{ + dbPath_ = dbPath; +} + +bool SqliteDatabase::OpenDatabase() +{ + int result = sqlite3_open(dbPath_.c_str(), &db_); + if (result) { + cerr << "Can't open database: " << sqlite3_errmsg(db_) << endl; + return false; + } + + if (!CreateTable()) { + return false; + } + + if (!FindMaxId()) { + return false; + } + return true; +} + +void SqliteDatabase::CloseDatabase() +{ + if (db_ == nullptr) { + return; + } + sqlite3_close(db_); + db_ = nullptr; +} + +bool SqliteDatabase::Insert(const ResourceItem &resourceItem) +{ + if (resourceItem.GetResType() == ResType::ID) { + return true; + } + + int32_t id = -1; + if (!Query(resourceItem, id)) { + return false; + } + + if (id >= 0 ) { + return true; + } + + string data = GetValue(resourceItem); + string sql = "insert into resource_index values(" + to_string(id_) + ",'" + resourceItem.GetName() + "','" + \ + data + "'," + \ + to_string((int32_t)resourceItem.GetResType()) + ",'" + resourceItem.GetFilePath() + \ + "','" + resourceItem.GetLimitKey() + "'," + to_string(priority_) + ")"; + auto callback = [](void *owner, int argc, char **argv, char **azColName) -> int { + return 0; + }; + + char *zErrMsg = 0; + int result = sqlite3_exec(db_, sql.c_str(), callback, nullptr, &zErrMsg); + if (result) { + cerr << "insert sql error: " << zErrMsg << endl; + sqlite3_free(zErrMsg); + return false; + } + id_++; + return true; +} + +bool SqliteDatabase::Query(const ResourceItem &resourceItem, int32_t &id) +{ + string sql = "select id from resource_index where name='" + resourceItem.GetName() + \ + "' and type='" + to_string((int32_t)resourceItem.GetResType()) + \ + "' and limitkey='" + resourceItem.GetLimitKey() + \ + "' and priority=" + to_string(priority_); + auto callback = [](void *id, int argc, char **argv, char **azColName) -> int { + if (argc > 0 && id) { + (*static_cast(id)) = atoi(argv[0]); + } + return 0; + }; + + id = -1; + char *zErrMsg = 0; + int result = sqlite3_exec(db_, sql.c_str(), callback, &id, &zErrMsg); + if (result) { + cerr << "query sql error: " << zErrMsg << endl; + sqlite3_free(zErrMsg); + return false; + } + + if (id < 0) { + return true; + } + + sql = "update resource_index set value='" + GetValue(resourceItem) + \ + "', path='" + resourceItem.GetFilePath() + \ + "' where id = " + to_string(id); + result = sqlite3_exec(db_, sql.c_str(), callback, nullptr, &zErrMsg); + if (result) { + cerr << "query sql error: " << zErrMsg << endl; + sqlite3_free(zErrMsg); + return false; + } + return true; +} + +bool SqliteDatabase::FindMaxId() +{ + string sql = "select max(id) from resource_index"; + auto callback = [](void *owner, int argc, char **argv, char **azColName) -> int { + if (argc > 0 && argv[0]) { + id_ = atoi(argv[0]) + 1; + } + return 0; + }; + + char *zErrMsg = 0; + int result = sqlite3_exec(db_, sql.c_str(), callback, nullptr, &zErrMsg); + if (result) { + cerr << "find max id sql error: " << zErrMsg << endl; + sqlite3_free(zErrMsg); + return false; + } + return true; +} + +bool SqliteDatabase::CreateTable() +{ + string sql = "select * from sqlite_master where name = 'resource_index'"; + auto callback = [](void *find, int argc, char **argv, char **azColName) -> int { + if (argc > 0 && find) { + (*static_cast(find)) = true; + } + return 0; + }; + + bool find = false; + char *zErrMsg = 0; + int result = sqlite3_exec(db_, sql.c_str(), callback, &find, &zErrMsg); + if (result) { + cerr << "search table error: " << zErrMsg << endl; + sqlite3_free(zErrMsg); + return false; + } + + if (find) { + return true; + } + + sql = "create table resource_index(id int, name, value image, type int, path, limitkey, priority int)"; + result = sqlite3_exec(db_, sql.c_str(), callback, nullptr, &zErrMsg); + if (result) { + cerr << "create table error: " << zErrMsg << endl; + sqlite3_free(zErrMsg); + return false; + } + return true; +} + +string SqliteDatabase::GetValue(const ResourceItem &resourceItem) const +{ + string data(reinterpret_cast(resourceItem.GetData()), resourceItem.GetDataLength()); + if (resourceItem.GetResType() == ResType::STRARRAY || resourceItem.GetResType() == ResType::INTARRAY || + resourceItem.GetResType() == ResType::THEME || resourceItem.GetResType() == ResType::PATTERN || + resourceItem.GetResType() == ResType::PLURAL ) { + vector contents = ResourceUtil::DecomposeStrings(data); + Json::Value array(Json::arrayValue); + for (const auto &iter : contents) { + array.append(iter); + } + data = array.toStyledString(); + } + return data; +} +} +} +} \ No newline at end of file diff --git a/src/task_handle.cpp b/src/task_handle.cpp new file mode 100644 index 0000000000000000000000000000000000000000..bd329b9c4086211048448ad1005efc07f74b938b --- /dev/null +++ b/src/task_handle.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "task_handle.h" + +#include "resource_pack.h" + +namespace OHOS { +namespace Global { +namespace Restool { +uint32_t TaskHandle::HandlePackage(const PackageParser &packageParser) +{ + ResourcePack pack(packageParser); + return pack.Package(); +} +} +} +} \ No newline at end of file diff --git a/src/xml/key_manager.cpp b/src/xml/key_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c3c6c5cb74819d1ab2ecc2e9b06c8dea7c7d46d3 --- /dev/null +++ b/src/xml/key_manager.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "key_manager.h" +#include +#include "resource_util.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +KeyManager::KeyManager() +{ + keys_.emplace(XmlKeyNode::KeyType::NODE, make_shared()); + keys_.emplace(XmlKeyNode::KeyType::ATTRIBUTE, make_shared()); + keys_.emplace(XmlKeyNode::KeyType::CONSTANT, make_shared()); + keys_.emplace(XmlKeyNode::KeyType::CONTENT, make_shared()); +} + +bool KeyManager::LoadKey(const string &keysPath) +{ + for (auto &key : keys_) { + string keyPath = filesystem::path(keysPath).append(XmlKeyNode::KEY_TO_FILE_NAME.at(key.first)).string(); + if (!ResourceUtil::FileExist(keyPath)) { + continue; + } + if (!key.second->LoadFromFile(keyPath)) { + return false; + } + } + return true; +} + +bool KeyManager::SaveKey(const string &keysPath) +{ + for (const auto &iter : keys_) { + string keyPath = filesystem::path(keysPath).append(XmlKeyNode::KEY_TO_FILE_NAME.at(iter.first)).string(); + if (!iter.second->SaveToFile(keyPath)) { + return false; + } + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/xml/solid_xml.cpp b/src/xml/solid_xml.cpp new file mode 100644 index 0000000000000000000000000000000000000000..26cfe5c1f314fabd91b5ea72237311e25ba07900 --- /dev/null +++ b/src/xml/solid_xml.cpp @@ -0,0 +1,380 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "solid_xml.h" +#include +#include +#include "securec.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const uint8_t SolidXml::SOLID_XML_MAGIC[] = "SolidXml"; +const uint32_t SolidXml::SOLID_XML_MAGIC_LENGTH = + (sizeof(SolidXml::SOLID_XML_MAGIC) / sizeof(uint32_t) + 1) * sizeof(uint32_t); + +SolidXml::SolidXml(const string &xmlPath, map> &keys) + : xmlPath_(xmlPath), keys_(keys) +{ +} + +SolidXml::~SolidXml() +{ +} + +bool SolidXml::GenerateSolidXml(const string &filePath) +{ + xmlKeepBlanksDefault(0); + xmlDocPtr doc = xmlParseFile(xmlPath_.c_str()); + if (doc == nullptr) { + return false; + } + + auto root = make_shared(); + nodes_.push_back(root); + Compile(xmlDocGetRootElement(doc), root); + xmlFreeDoc(doc); + return SaveToFile(filePath); +} + +bool SolidXml::FlushNodeKeys(const string &filePath, map> &newKeys) +{ + if (!LoadFromFile(xmlPath_)) { + cerr << "Error: load " << xmlPath_ << " fail." << endl; + return false; + } + + bool firstNode = true; + for (auto &node : nodes_) { + if (!node->FlushIndex(keys_, newKeys)) { + cerr << "Error: flush node key fail, '" << xmlPath_ << "'" << endl; + return false; + } + if (firstNode && !FlushXmlnsKey(newKeys)) { + return false; + } + firstNode = false; + } + + for (auto &attr : attributes_) { + if (!attr->FlushIndex(keys_, newKeys)) { + cerr << "Error: flush attibutes key fail, '" << xmlPath_ << "'" << endl; + return false; + } + } + return SaveToFile(filePath); +} + +//below private +void SolidXml::Compile(const xmlNodePtr nodePtr, shared_ptr &node) +{ + if (nodePtr->type == XML_COMMENT_NODE) { + if (nodePtr->next) { + Compile(nodePtr->next, node); + } + return; + } + + string name(reinterpret_cast(nodePtr->name)); + node->SetName(keys_[XmlKeyNode::KeyType::NODE]->PushKey(name)); + CompileNameSpace(nodePtr, node); + CompileAttr(nodePtr->properties, node); + + if (nodePtr->children) { + if (nodePtr->children->type == XML_TEXT_NODE) { + string content(reinterpret_cast(nodePtr->children->content)); + node->SetValue(keys_[XmlKeyNode::KeyType::CONTENT]->PushKey(content)); + } else { + auto child = make_shared(); + nodes_.push_back(child); + node->SetChild(nodes_.size() - 1); + Compile(nodePtr->children, child); + } + } + + if (nodePtr->next) { + auto brother = make_shared(); + nodes_.push_back(brother); + node->SetBrother(nodes_.size() - 1); + Compile(nodePtr->next, brother); + } +} + +void SolidXml::CompileAttr(const xmlAttrPtr attrPtr, shared_ptr &node) +{ + if (attrPtr == nullptr) { + return; + } + + xmlChar * xmlValue = xmlNodeListGetString(attrPtr->doc, attrPtr->children, 1); + string value(reinterpret_cast(xmlValue)); + PretreatmentAttr(value); + xmlFree(xmlValue); + string name(reinterpret_cast(attrPtr->name)); + auto attr = make_shared(); + attributes_.push_back(attr); + attr->SetName(keys_[XmlKeyNode::KeyType::ATTRIBUTE]->PushKey(name)); + attr->SetValue(keys_[XmlKeyNode::KeyType::CONSTANT]->PushKey(value)); + if (attrPtr->ns != nullptr && attrPtr->ns->prefix != nullptr) { + string nameSpace(reinterpret_cast(attrPtr->ns->prefix)); + attr->SetNameSpace(keys_[XmlKeyNode::KeyType::NODE]->PushKey(nameSpace)); + } + node->AddAttribute(attributes_.size() - 1); + CompileAttr(attrPtr->next, node); +} + +void SolidXml::CompileNameSpace(const xmlNodePtr nodePtr, shared_ptr &node) +{ + if (nodePtr->ns && nodePtr->ns->prefix) { + string nameSpace(reinterpret_cast(nodePtr->ns->prefix)); + node->SetNameSpace(keys_[XmlKeyNode::KeyType::NODE]->PushKey(nameSpace)); + } + + auto nsDef = nodePtr->nsDef; + while (nsDef) { + string nameSpace; + string href; + if (nsDef->prefix) { + nameSpace = string(reinterpret_cast(nsDef->prefix)); + } + if (nsDef->href) { + href = string(reinterpret_cast(nsDef->href)); + } + int32_t nameSpaceIndex = keys_[XmlKeyNode::KeyType::NODE]->PushKey(nameSpace); + int32_t herfIndex = keys_[XmlKeyNode::KeyType::NODE]->PushKey(href); + AddNampeSpaceDef(nameSpaceIndex, herfIndex); + nsDef = nsDef->next; + } +} + +void SolidXml::Node::RawData(ofstream &out) const +{ + out.write(reinterpret_cast(&nameSpace_), sizeof(int32_t)); + out.write(reinterpret_cast(&name_), sizeof(int32_t)); + out.write(reinterpret_cast(&value_), sizeof(int32_t)); +} + +void SolidXml::XmlNode::RawData(ofstream &out) const +{ + SolidXml::Node::RawData(out); + out.write(reinterpret_cast(&child_), sizeof(int32_t)); + out.write(reinterpret_cast(&brother_), sizeof(int32_t)); + int32_t attrStart = attributes_.size(); + int32_t attrCount = attributes_.size(); + if (!attributes_.empty()) { + attrStart = attributes_.at(0); + } + out.write(reinterpret_cast(&attrStart), sizeof(int32_t)); + out.write(reinterpret_cast(&attrCount), sizeof(int32_t)); +} + +bool SolidXml::Node::LoadFrom(ifstream &in) +{ + CHECK_IO(in.read(reinterpret_cast(&nameSpace_), sizeof(int32_t))) + CHECK_IO(in.read(reinterpret_cast(&name_), sizeof(int32_t))); + CHECK_IO(in.read(reinterpret_cast(&value_), sizeof(int32_t))); + return true; +} + +bool SolidXml::XmlNode::LoadFrom(ifstream &in) +{ + if (!SolidXml::Node::LoadFrom(in)) { + return false; + } + CHECK_IO(in.read(reinterpret_cast(&child_), sizeof(int32_t))); + CHECK_IO(in.read(reinterpret_cast(&brother_), sizeof(int32_t))); + int32_t attrStart = 0; + int32_t attrCount = 0; + CHECK_IO(in.read(reinterpret_cast(&attrStart), sizeof(int32_t))); + CHECK_IO(in.read(reinterpret_cast(&attrCount), sizeof(int32_t))); + for (int32_t i = attrStart; i < attrStart + attrCount; i++) { + attributes_.push_back(i); + } + return true; +} + +bool SolidXml::Node::FlushIndex(const map> &oldKeys, + map> &newKeys) +{ + if (!ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::NODE, nameSpace_) || + !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::ATTRIBUTE, name_) || + !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::CONSTANT, value_)) { + return false; + } + return true; +} + +bool SolidXml::XmlNode::FlushIndex(const map> &oldKeys, + map> &newKeys) +{ + if (!ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::NODE, nameSpace_) || + !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::NODE, name_) || + !ChangeToNewKey(oldKeys, newKeys, XmlKeyNode::KeyType::CONTENT, value_)) { + return false; + } + return true; +} + +void SolidXml::AddNampeSpaceDef(int32_t nameSpace, int32_t href) +{ + nameSpaces_.push_back(nameSpace); + hrefs_.push_back(href); +} + +bool SolidXml::SaveToFile(const std::string &filePath) const +{ + ofstream out(filePath, ofstream::out | ofstream::binary); + if (!out.is_open()) { + cerr << "Error: open fail," << filePath << endl; + return false; + } + + // write solid xml header + uint8_t magic[SOLID_XML_MAGIC_LENGTH] = {0}; + if (memcpy_s(magic, SOLID_XML_MAGIC_LENGTH, SOLID_XML_MAGIC, sizeof(SOLID_XML_MAGIC)) != EOK) { + cerr << "Error: SolidXml::SaveToFile memcpy_s fail." << endl; + return false; + } + uint32_t version = 1; + uint32_t numOfNodes = nodes_.size(); + uint32_t numOfAttributes = attributes_.size(); + uint32_t numOfNameSpaces = nameSpaces_.size(); + out.write(reinterpret_cast(magic), SOLID_XML_MAGIC_LENGTH); + out.write(reinterpret_cast(&version), sizeof(uint32_t)); + out.write(reinterpret_cast(&numOfNodes), sizeof(uint32_t)); + out.write(reinterpret_cast(&numOfAttributes), sizeof(uint32_t)); + out.write(reinterpret_cast(&numOfNameSpaces), sizeof(uint32_t)); + + // write node + for (const auto &node : nodes_) { + node->RawData(out); + } + + // write attribute + for (const auto &attribute : attributes_) { + attribute->RawData(out); + } + + // write namespace + for (const auto &nameSpace : nameSpaces_) { + out.write(reinterpret_cast(&nameSpace), sizeof(int32_t)); + } + + // write href + for (const auto &href : hrefs_) { + out.write(reinterpret_cast(&href), sizeof(int32_t)); + } + return true; +} + +void SolidXml::PretreatmentAttr(string &value) const +{ + regex ref("^\\$\\+id:"); + smatch result; + if (!regex_search(value, result, ref)) { + return; + } + value.replace(0, result[0].str().length(), "$id:"); +} + +bool SolidXml::LoadFromFile(const string &sxmlPath) +{ + ifstream in(sxmlPath, ifstream::in | ifstream::binary); + if (!in.is_open()) { + cerr << "Error: open fail," << sxmlPath << endl; + return false; + } + + char header[SOLID_XML_MAGIC_LENGTH]; + CHECK_IO(in.read(header, SOLID_XML_MAGIC_LENGTH)); + + uint32_t version = 0; + CHECK_IO(in.read(reinterpret_cast(&version), sizeof(uint32_t))); + + uint32_t numOfNodes = 0; + CHECK_IO(in.read(reinterpret_cast(&numOfNodes), sizeof(uint32_t))); + + uint32_t numOfAttributes = 0; + CHECK_IO(in.read(reinterpret_cast(&numOfAttributes), sizeof(uint32_t))); + + uint32_t numOfNameSpaces = 0; + CHECK_IO(in.read(reinterpret_cast(&numOfNameSpaces), sizeof(uint32_t))); + + for (uint32_t i = 0; i < numOfNodes; i++) { + auto xmlNode = make_shared(); + if (!xmlNode->LoadFrom(in)) { + return false; + } + nodes_.push_back(xmlNode); + } + + for (uint32_t i = 0; i < numOfAttributes; i++) { + auto attr = make_shared(); + if (!attr->LoadFrom(in)) { + return false; + } + attributes_.push_back(attr); + } + + for (uint32_t i = 0; i < numOfNameSpaces; i++) { + int32_t nameSpace = -1; + CHECK_IO(in.read(reinterpret_cast(&nameSpace), sizeof(int32_t))); + nameSpaces_.push_back(nameSpace); + } + + for (uint32_t i = 0; i < numOfNameSpaces; i++) { + int32_t href = -1; + CHECK_IO(in.read(reinterpret_cast(&href), sizeof(int32_t))); + hrefs_.push_back(href); + } + return true; +} + +bool SolidXml::ChangeToNewKey(const map> &oldKeys, + map> &newKeys, + XmlKeyNode::KeyType keyType, int32_t &keyId) +{ + if (keyId <= 0) { + return true; + } + + string value; + if (!oldKeys.at(keyType)->GetKeyValue(keyId, value)) { + return false; + } + + keyId = newKeys[keyType]->PushKey(value); + return true; +} + +bool SolidXml::FlushXmlnsKey(map> &newKeys) +{ + if (nameSpaces_.size() != hrefs_.size()) { + return false; + } + + for (uint32_t i = 0; i < nameSpaces_.size(); i++) { + if (!ChangeToNewKey(keys_, newKeys, XmlKeyNode::KeyType::NODE, nameSpaces_[i]) || + !ChangeToNewKey(keys_, newKeys, XmlKeyNode::KeyType::NODE, hrefs_[i])) { + cerr << "Error: flush namespace key fail, '" << xmlPath_ << "'" << endl; + return false; + } + } + return true; +} +} +} +} \ No newline at end of file diff --git a/src/xml/xml_converter.cpp b/src/xml/xml_converter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0bd983fe5f22736691bbc567070481733c24354c --- /dev/null +++ b/src/xml/xml_converter.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "xml_converter.h" +#include +#include "resource_util.h" +#include "solid_xml.h" + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +XmlConverter::XmlConverter(const vector &xmlPaths, const string &outputPath) + : xmlPaths_(xmlPaths), outputPath_(outputPath) +{ +} + +XmlConverter::~XmlConverter() +{ +} + +bool XmlConverter::GenerateSolidXml() +{ + if (!LoadKeys(outputPath_)) { + return false; + } + for (const auto &xmlPath : xmlPaths_) { + SolidXml solidXml(xmlPath, keyManager.GetKeys()); + string filename = filesystem::path(xmlPath).filename().string(); + string filePath = filesystem::path(outputPath_).append(filename).replace_extension(".sxml").string(); + if (!solidXml.GenerateSolidXml(filePath)) { + return false; + } + } + return true; +} + +bool XmlConverter::GenerateKey() +{ + return keyManager.SaveKey(outputPath_); +} + +bool XmlConverter::LoadKeys(const std::string &folderPath) +{ + return keyManager.LoadKey(folderPath); +} +} +} +} \ No newline at end of file diff --git a/src/xml/xml_key_node.cpp b/src/xml/xml_key_node.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f77638a1d81bbff0c128c73f2b44ee60f7d046c4 --- /dev/null +++ b/src/xml/xml_key_node.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "xml_key_node.h" +#include +#include +#include +#include + +namespace OHOS { +namespace Global { +namespace Restool { +using namespace std; +const map XmlKeyNode::KEY_TO_FILE_NAME = { + {KeyType::NODE, "nodes.key" }, + {KeyType::ATTRIBUTE, "attributes.key" }, + {KeyType::CONSTANT, "constants.key" }, + {KeyType::CONTENT, "contents.key" } +}; +XmlKeyNode::XmlKeyNode() : keyId_(0) +{ + PushKey(""); +} + +XmlKeyNode::~XmlKeyNode() +{ +} + +int32_t XmlKeyNode::PushKey(const string &name) +{ + auto result = keyMap_.emplace(name, keyId_); + if (result.second) { + return keyId_++; + } + return result.first->second; +} + +bool XmlKeyNode::SaveToFile(const string &filePath) const +{ + ofstream out(filePath, ofstream::out | ofstream::binary); + if (!out.is_open()) { + cerr << "Error: open fail," << filePath << endl; + return false; + } + + vector> sets(keyMap_.begin(), keyMap_.end()); + sort(sets.begin(), sets.end(),[](const auto &a, const auto &b) { + return a.second < b.second; + }); + + char null = 0; + for (const auto &iter : sets) { + out.write(reinterpret_cast(iter.first.c_str()), iter.first.length()); + out.write(&null, sizeof(char)); + } + return true; +} + +bool XmlKeyNode::LoadFromFile(const string &filePath) +{ + return LoadFromFile(filePath, nullptr); +} + +bool XmlKeyNode::LoadFromFile(const std::string &filePath, RefParser parser) +{ + ifstream in(filePath, ifstream::in | ifstream::binary); + if (!in.is_open()) { + cerr << "Error: open fail," << filePath << endl; + return false; + } + + string inputLine; + getline(in, inputLine); + if (inputLine.empty()) { + return true; + } + + string::size_type offset = 0; + while (offset < inputLine.length()) { + string item(inputLine.c_str() + offset); + offset = offset + item.length() + sizeof(char); + if (parser && !parser(item)) { + return false; + } + PushKey(item); + } + return true; +} + +bool XmlKeyNode::GetKeyValue(int32_t keyId, std::string &value) const +{ + auto result = find_if(keyMap_.begin(), keyMap_.end(), [&keyId](const auto &iter) { + return keyId == iter.second; + }); + if (result == keyMap_.end()) { + return false; + } + value = result->first; + return true; +} +} +} +} \ No newline at end of file diff --git a/third_party/bounds_checking_function/CMakeLists.txt b/third_party/bounds_checking_function/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f588c4157d7d04b92a56b5fd834ae2b1309ef4be --- /dev/null +++ b/third_party/bounds_checking_function/CMakeLists.txt @@ -0,0 +1,2 @@ +aux_source_directory(${bound_checking_function_dir}/src lib_sec_source) +add_library(securec STATIC ${lib_sec_source}) \ No newline at end of file diff --git a/third_party/jsoncpp/CMakeLists.txt b/third_party/jsoncpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..3017644489a3e0969266a96ebb1a4e1aa6d0b256 --- /dev/null +++ b/third_party/jsoncpp/CMakeLists.txt @@ -0,0 +1,3 @@ +aux_source_directory(${jsoncpp_dir}/src/lib_json json_source) + +add_library(jsoncpp STATIC ${json_source}) \ No newline at end of file diff --git a/third_party/libxml2/CMakeLists.txt b/third_party/libxml2/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fee84689f4df2b1694cc48230b9d21ceecc40b6a --- /dev/null +++ b/third_party/libxml2/CMakeLists.txt @@ -0,0 +1,348 @@ +include(CheckCSourceCompiles) +include(CheckIncludeFiles) +include(CheckStructHasMember) +include(CheckFunctionExists) +include(CheckLibraryExists) +include(CheckSymbolExists) + +option(BUILD_SHARED_LIBS "Build shared libraries" OFF) +set(LIBXML2_WITH_AUTOMATA ON) +option(LIBXML2_WITH_C14N "Add the Canonicalization support" ON) +option(LIBXML2_WITH_CATALOG "Add the Catalog support" ON) +option(LIBXML2_WITH_DEBUG "Add the debugging module" ON) +option(LIBXML2_WITH_DOCB "Add Docbook SGML support" ON) +set(LIBXML2_WITH_EXPR ON) +option(LIBXML2_WITH_FTP "Add the FTP support" ON) +option(LIBXML2_WITH_HTML "Add the HTML support" ON) +option(LIBXML2_WITH_HTTP "Add the HTTP support" ON) +option(LIBXML2_WITH_ICONV "Add ICONV support" OFF) +option(LIBXML2_WITH_ICU "Add ICU support" OFF) +option(LIBXML2_WITH_ISO8859X "Add ISO8859X support if no iconv" ON) +option(LIBXML2_WITH_LEGACY "Add deprecated APIs for compatibility" ON) +option(LIBXML2_WITH_LZMA "Use liblzma" OFF) +option(LIBXML2_WITH_MEM_DEBUG "Add the memory debugging module" OFF) +option(LIBXML2_WITH_MODULES "Add the dynamic modules support" ON) +option(LIBXML2_WITH_OUTPUT "Add the serialization support" ON) +option(LIBXML2_WITH_PATTERN "Add the xmlPattern selection interface" ON) +option(LIBXML2_WITH_PROGRAMS "Build programs" ON) +option(LIBXML2_WITH_PUSH "Add the PUSH parser interfaces" ON) +option(LIBXML2_WITH_PYTHON "Build Python bindings" OFF) +option(LIBXML2_WITH_READER "Add the xmlReader parsing interface" ON) +option(LIBXML2_WITH_REGEXPS "Add Regular Expressions support" ON) +option(LIBXML2_WITH_RUN_DEBUG "Add the runtime debugging module" OFF) +option(LIBXML2_WITH_SAX1 "Add the older SAX1 interface" ON) +option(LIBXML2_WITH_SCHEMAS "Add Relax-NG and Schemas support" ON) +option(LIBXML2_WITH_SCHEMATRON "Add Schematron support" ON) +option(LIBXML2_WITH_THREADS "Add multithread support" ON) +option(LIBXML2_WITH_THREAD_ALLOC "Add per-thread memory" OFF) +option(LIBXML2_WITH_TREE "Add the DOM like tree manipulation APIs" ON) +set(LIBXML2_WITH_TRIO OFF) +set(LIBXML2_WITH_UNICODE ON) +option(LIBXML2_WITH_VALID "Add the DTD validation support" ON) +option(LIBXML2_WITH_WRITER "Add the xmlWriter saving interface" ON) +option(LIBXML2_WITH_XINCLUDE "Add the XInclude support" ON) +option(LIBXML2_WITH_XPATH "Add the XPATH support" ON) +option(LIBXML2_WITH_XPTR "Add the XPointer support" ON) +option(LIBXML2_WITH_ZLIB "Use libz" OFF) + +set(LIBXML_MAJOR_VERSION 2) +set(LIBXML_MINOR_VERSION 9) +set(LIBXML_MICRO_VERSION 10) + +set(VERSION "${LIBXML_MAJOR_VERSION}.${LIBXML_MINOR_VERSION}.${LIBXML_MICRO_VERSION}") +set(LIBXML_VERSION ${LIBXML_MAJOR_VERSION}0${LIBXML_MINOR_VERSION}0${LIBXML_MICRO_VERSION}) +set(LIBXML_VERSION_STRING "${LIBXML_VERSION}") +set(LIBXML_VERSION_EXTRA "") +set(LIBXML_VERSION_NUMBER ${LIBXML_VERSION}) + +foreach(VARIABLE IN ITEMS WITH_AUTOMATA WITH_C14N WITH_CATALOG WITH_DEBUG WITH_DOCB WITH_EXPR WITH_FTP WITH_HTML WITH_HTTP WITH_ICONV WITH_ICU WITH_ISO8859X WITH_SAX1 WITH_LEGACY WITH_LZMA WITH_MEM_DEBUG WITH_MODULES WITH_OUTPUT WITH_PATTERN WITH_PUSH WITH_READER WITH_REGEXPS WITH_RUN_DEBUG WITH_SCHEMAS WITH_SCHEMATRON WITH_THREADS WITH_THREAD_ALLOC WITH_TREE WITH_TRIO WITH_UNICODE WITH_VALID WITH_WRITER WITH_XINCLUDE WITH_XPATH WITH_XPTR WITH_ZLIB) + if (LIBXML2_${VARIABLE}) + set(${VARIABLE} 1) + else() + set(${VARIABLE} 0) + endif() +endforeach() + +check_c_source_compiles(" + void __attribute__((destructor)) + f(void) {} + int main(void) { return 0; } + " ATTRIBUTE_DESTRUCTOR) +check_c_source_compiles(" + #include + int main() { (void) gethostbyname((const char*) \"\"); return 0; } + " GETHOSTBYNAME_ARG_CAST_CONST) +if(NOT GETHOSTBYNAME_ARG_CAST_CONST) + set(GETHOSTBYNAME_ARG_CAST "(char *)") +else() + set(GETHOSTBYNAME_ARG_CAST "/**/") +endif() +check_include_files(arpa/inet.h HAVE_ARPA_INET_H) +check_include_files(arpa/nameser.h HAVE_ARPA_NAMESER_H) +check_struct_has_member("struct sockaddr_storage" ss_family "sys/socket.h;sys/types.h" HAVE_SS_FAMILY) +check_struct_has_member("struct sockaddr_storage" __ss_family "sys/socket.h;sys/types.h" HAVE_BROKEN_SS_FAMILY) +if(HAVE_BROKEN_SS_FAMILY) + set(ss_family __ss_family) +endif() +check_function_exists(class HAVE_CLASS) +check_include_files(ctype.h HAVE_CTYPE_H) +check_include_files(dirent.h HAVE_DIRENT_H) +check_include_files(dlfcn.h HAVE_DLFCN_H) +check_library_exists(dl dlopen "" HAVE_DLOPEN) +check_include_files(dl.h HAVE_DL_H) +check_include_files(errno.h HAVE_ERRNO_H) +check_include_files(fcntl.h HAVE_FCNTL_H) +check_function_exists(finite HAVE_FINITE) +check_include_files(float.h HAVE_FLOAT_H) +check_function_exists(fpclass HAVE_FPCLASS) +check_function_exists(fprintf HAVE_FPRINTF) +check_function_exists(fp_class HAVE_FP_CLASS) +check_function_exists(ftime HAVE_FTIME) +check_function_exists(getaddrinfo HAVE_GETADDRINFO) +check_function_exists(gettimeofday HAVE_GETTIMEOFDAY) +check_include_files(inttypes.h HAVE_INTTYPES_H) +check_function_exists(isascii HAVE_ISASCII) +check_function_exists(isinf HAVE_ISINF) +check_function_exists(isnan HAVE_ISNAN) +check_function_exists(isnand HAVE_ISNAND) +check_library_exists(history append_history "" HAVE_LIBHISTORY) +check_library_exists(lzma lzma_code "" HAVE_LIBLZMA) +check_library_exists(pthread pthread_join "" HAVE_LIBPTHREAD) +check_library_exists(readline readline "" HAVE_LIBREADLINE) +check_library_exists(z gzread "" HAVE_LIBZ) +check_include_files(limits.h HAVE_LIMITS_H) +check_function_exists(localtime HAVE_LOCALTIME) +check_include_files(lzma.h HAVE_LZMA_H) +check_include_files(malloc.h HAVE_MALLOC_H) +check_include_files(math.h HAVE_MATH_H) +check_include_files(memory.h HAVE_MEMORY_H) +check_function_exists(mmap HAVE_MMAP) +check_function_exists(munmap HAVE_MUNMAP) +check_symbol_exists(DIR ndir.h HAVE_NDIR_H) +check_include_files(netdb.h HAVE_NETDB_H) +check_include_files(netinet/in.h HAVE_NETINET_IN_H) +check_include_files(poll.h HAVE_POLL_H) +check_function_exists(printf HAVE_PRINTF) +check_include_files(pthread.h HAVE_PTHREAD_H) +check_function_exists(putenv HAVE_PUTENV) +check_function_exists(rand HAVE_RAND) +check_function_exists(rand_r HAVE_RAND_R) +check_include_files(resolv.h HAVE_RESOLV_H) +check_library_exists(dld shl_load "" HAVE_SHLLOAD) +check_function_exists(signal HAVE_SIGNAL) +check_include_files(signal.h HAVE_SIGNAL_H) +check_function_exists(snprintf HAVE_SNPRINTF) +check_function_exists(sprintf HAVE_SPRINTF) +check_function_exists(srand HAVE_SRAND) +check_function_exists(sscanf HAVE_SSCANF) +check_function_exists(stat HAVE_STAT) +check_include_files(stdarg.h HAVE_STDARG_H) +check_include_files(stdint.h HAVE_STDINT_H) +check_include_files(stdlib.h HAVE_STDLIB_H) +check_function_exists(strftime HAVE_STRFTIME) +check_include_files(strings.h HAVE_STRINGS_H) +check_include_files(string.h HAVE_STRING_H) +check_symbol_exists(DIR sys/dir.h HAVE_SYS_DIR_H) +check_include_files(sys/mman.h HAVE_SYS_MMAN_H) +check_symbol_exists(DIR sys/ndir.h HAVE_SYS_NDIR_H) +check_include_files(sys/select.h HAVE_SYS_SELECT_H) +check_include_files(sys/socket.h HAVE_SYS_SOCKET_H) +check_include_files(sys/stat.h HAVE_SYS_STAT_H) +check_include_files(sys/timeb.h HAVE_SYS_TIMEB_H) +check_include_files(sys/time.h HAVE_SYS_TIME_H) +check_include_files(sys/types.h HAVE_SYS_TYPES_H) +check_function_exists(time HAVE_TIME) +check_include_files(time.h HAVE_TIME_H) +check_include_files(unistd.h HAVE_UNISTD_H) +check_function_exists(va_copy HAVE_VA_COPY) +check_function_exists(vfprintf HAVE_VFPRINTF) +check_function_exists(vsnprintf HAVE_VSNPRINTF) +check_function_exists(vsprintf HAVE_VSPRINTF) +check_function_exists(__va_copy HAVE___VA_COPY) +check_c_source_compiles(" + #include + #include + extern + #ifdef __cplusplus + \"C\" + #endif + #if defined(__STDC__) || defined(__cplusplus) + size_t iconv(iconv_t cd, char** inbuf, size_t* inbytesleft, char** outbuf, size_t* outbytesleft); + #else + size_t iconv(); + #endif + int main() { return 0; } +" ICONV_CONST_TEST) +if(NOT ICONV_CONST_TEST) + set(ICONV_CONST "const") +endif() +set(LT_OBJDIR ".libs/") +check_c_source_compiles(" + #include + #include + int main() { (void) send(1, (const char*) \"\", 1, 1); return 0; } +" SEND_ARG2_CAST_CONST) +if(NOT SEND_ARG2_CAST_CONST) + set(SEND_ARG2_CAST "(char *)") +else() + set(SEND_ARG2_CAST "/**/") +endif() +check_include_files("float.h;stdarg.h;stdlib.h;string.h" STDC_HEADERS) +check_c_source_compiles(" + #include + void a(va_list* ap) {}; + int main() { va_list ap1, ap2; a(&ap1); ap2 = (va_list) ap1; return 0; } +" VA_LIST_IS_ARRAY_TEST) +if(VA_LIST_IS_ARRAY_TEST) + set(VA_LIST_IS_ARRAY FALSE) +else() + set(VA_LIST_IS_ARRAY TRUE) +endif() +check_c_source_compiles(" + #include + #include + #include + int main() { (void) getsockopt(1, 1, 1, NULL, (socklen_t*) NULL); return 0; } +" XML_SOCKLEN_T_SOCKLEN_T) +if(XML_SOCKLEN_T_SOCKLEN_T) + set(XML_SOCKLEN_T socklen_t) +else() + check_c_source_compiles(" + #include + #include + #include + int main() { (void) getsockopt(1, 1, 1, NULL, (size_t*) NULL); return 0; } + " XML_SOCKLEN_T_SIZE_T) + if(XML_SOCKLEN_T_SIZE_T) + set(XML_SOCKLEN_T size_t) + else() + check_c_source_compiles(" + #include + #include + #include + int main() { (void) getsockopt (1, 1, 1, NULL, (int*) NULL); return 0; } + " XML_SOCKLEN_T_INT) + set(XML_SOCKLEN_T int) + endif() +endif() + + +file(COPY ${libxml2_dir} DESTINATION ./) +set(libxml2_original ${CMAKE_CURRENT_BINARY_DIR}/libxml2) +include_directories(${libxml2_original}/include) +configure_file(config.h.cmake.in ${libxml2_original}/config.h) +set(libxml2_original_header + ${libxml2_original}/include/libxml/c14n.h + ${libxml2_original}/include/libxml/catalog.h + ${libxml2_original}/include/libxml/chvalid.h + ${libxml2_original}/include/libxml/debugXML.h + ${libxml2_original}/include/libxml/dict.h + ${libxml2_original}/include/libxml/DOCBparser.h + ${libxml2_original}/include/libxml/encoding.h + ${libxml2_original}/include/libxml/entities.h + ${libxml2_original}/include/libxml/globals.h + ${libxml2_original}/include/libxml/hash.h + ${libxml2_original}/include/libxml/HTMLparser.h + ${libxml2_original}/include/libxml/HTMLtree.h + ${libxml2_original}/include/libxml/list.h + ${libxml2_original}/include/libxml/nanoftp.h + ${libxml2_original}/include/libxml/nanohttp.h + ${libxml2_original}/include/libxml/parser.h + ${libxml2_original}/include/libxml/parserInternals.h + ${libxml2_original}/include/libxml/pattern.h + ${libxml2_original}/include/libxml/relaxng.h + ${libxml2_original}/include/libxml/SAX.h + ${libxml2_original}/include/libxml/SAX2.h + ${libxml2_original}/include/libxml/schemasInternals.h + ${libxml2_original}/include/libxml/schematron.h + ${libxml2_original}/include/libxml/threads.h + ${libxml2_original}/include/libxml/tree.h + ${libxml2_original}/include/libxml/uri.h + ${libxml2_original}/include/libxml/valid.h + ${libxml2_original}/include/libxml/xinclude.h + ${libxml2_original}/include/libxml/xlink.h + ${libxml2_original}/include/libxml/xmlIO.h + ${libxml2_original}/include/libxml/xmlautomata.h + ${libxml2_original}/include/libxml/xmlerror.h + ${libxml2_original}/include/libxml/xmlexports.h + ${libxml2_original}/include/libxml/xmlmemory.h + ${libxml2_original}/include/libxml/xmlmodule.h + ${libxml2_original}/include/libxml/xmlreader.h + ${libxml2_original}/include/libxml/xmlregexp.h + ${libxml2_original}/include/libxml/xmlsave.h + ${libxml2_original}/include/libxml/xmlschemas.h + ${libxml2_original}/include/libxml/xmlschemastypes.h + ${libxml2_original}/include/libxml/xmlstring.h + ${libxml2_original}/include/libxml/xmlunicode.h + ${libxml2_original}/include/libxml/xmlwriter.h + ${libxml2_original}/include/libxml/xpath.h + ${libxml2_original}/include/libxml/xpathInternals.h + ${libxml2_original}/include/libxml/xpointer.h + ${libxml2_original}/include/wsockcompat.h +) + +set(libxml2_original_other_header + ${libxml2_original}/buf.h + ${libxml2_original}/elfgcchack.h + ${libxml2_original}/enc.h + ${libxml2_original}/libxml.h + ${libxml2_original}/save.h + ${libxml2_original}/timsort.h +) + +set(libxml2_original_source + ${libxml2_original}/buf.c + ${libxml2_original}/c14n.c + ${libxml2_original}/catalog.c + ${libxml2_original}/chvalid.c + ${libxml2_original}/debugXML.c + ${libxml2_original}/dict.c + ${libxml2_original}/encoding.c + ${libxml2_original}/entities.c + ${libxml2_original}/error.c + ${libxml2_original}/globals.c + ${libxml2_original}/hash.c + ${libxml2_original}/HTMLparser.c + ${libxml2_original}/HTMLtree.c + ${libxml2_original}/legacy.c + ${libxml2_original}/list.c + ${libxml2_original}/nanoftp.c + ${libxml2_original}/nanohttp.c + ${libxml2_original}/parser.c + ${libxml2_original}/parserInternals.c + ${libxml2_original}/pattern.c + ${libxml2_original}/relaxng.c + ${libxml2_original}/SAX.c + ${libxml2_original}/SAX2.c + ${libxml2_original}/schematron.c + ${libxml2_original}/threads.c + ${libxml2_original}/tree.c + ${libxml2_original}/uri.c + ${libxml2_original}/valid.c + ${libxml2_original}/xinclude.c + ${libxml2_original}/xlink.c + ${libxml2_original}/xmlIO.c + ${libxml2_original}/xmlmemory.c + ${libxml2_original}/xmlmodule.c + ${libxml2_original}/xmlreader.c + ${libxml2_original}/xmlregexp.c + ${libxml2_original}/xmlsave.c + ${libxml2_original}/xmlschemas.c + ${libxml2_original}/xmlschemastypes.c + ${libxml2_original}/xmlstring.c + ${libxml2_original}/xmlunicode.c + ${libxml2_original}/xmlwriter.c + ${libxml2_original}/xpath.c + ${libxml2_original}/xpointer.c + ${libxml2_original}/xzlib.c +) + +find_package(Threads REQUIRED) +add_library(myxml2 STATIC ${libxml2_original_header} ${libxml2_original_other_header} ${libxml2_original_source}) +target_link_libraries(myxml2 PRIVATE Threads::Threads) + +if(WIN32) + target_link_libraries(myxml2 PRIVATE ws2_32) + set(WIN32_EXTRA_LIBADD "-lws2_32") +endif() +configure_file(${libxml2_original}/include/libxml/xmlversion.h.in ${libxml2_original}/include/libxml/xmlversion.h) \ No newline at end of file diff --git a/third_party/libxml2/config.h.cmake.in b/third_party/libxml2/config.h.cmake.in new file mode 100644 index 0000000000000000000000000000000000000000..22b3c9207a2d13c5581b3f32844ee2bfbacdeb19 --- /dev/null +++ b/third_party/libxml2/config.h.cmake.in @@ -0,0 +1,288 @@ +/* config.h. Generated from config.h.in by configure. */ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define if __attribute__((destructor)) is accepted */ +#cmakedefine ATTRIBUTE_DESTRUCTOR 1 + +/* Type cast for the gethostbyname() argument */ +#cmakedefine GETHOSTBYNAME_ARG_CAST @GETHOSTBYNAME_ARG_CAST@ + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ARPA_NAMESER_H 1 + +/* Whether struct sockaddr::__ss_family exists */ +#cmakedefine HAVE_BROKEN_SS_FAMILY 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_CTYPE_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DIRENT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H 1 + +/* Have dlopen based dso */ +#cmakedefine HAVE_DLOPEN 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FCNTL_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_FLOAT_H 1 + +/* Define to 1 if you have the `fprintf' function. */ +#cmakedefine HAVE_FPRINTF 1 + +/* Define to 1 if you have the `ftime' function. */ +#cmakedefine HAVE_FTIME 1 + +/* Define if getaddrinfo is there */ +#cmakedefine HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `gettimeofday' function. */ +#cmakedefine HAVE_GETTIMEOFDAY 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the `isascii' function. */ +#cmakedefine HAVE_ISASCII 1 + +/* Define if isinf is there */ +#cmakedefine HAVE_ISINF 1 + +/* Define if isnan is there */ +#cmakedefine HAVE_ISNAN 1 + +/* Define if history library is there (-lhistory) */ +#cmakedefine HAVE_LIBHISTORY 1 + +/* Define if pthread library is there (-lpthread) */ +#cmakedefine HAVE_LIBPTHREAD 1 + +/* Define if readline library is there (-lreadline) */ +#cmakedefine HAVE_LIBREADLINE 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LIMITS_H 1 + +/* Define to 1 if you have the `localtime' function. */ +#cmakedefine HAVE_LOCALTIME 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_LZMA_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MALLOC_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MATH_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `mmap' function. */ +#cmakedefine HAVE_MMAP 1 + +/* Define to 1 if you have the `munmap' function. */ +#cmakedefine HAVE_MUNMAP 1 + +/* mmap() is no good without munmap() */ +#if defined(HAVE_MMAP) && !defined(HAVE_MUNMAP) +# undef /**/ HAVE_MMAP +#endif + +/* Define to 1 if you have the header file, and it defines `DIR'. */ +#cmakedefine HAVE_NDIR_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_POLL_H 1 + +/* Define to 1 if you have the `printf' function. */ +#cmakedefine HAVE_PRINTF 1 + +/* Define if is there */ +#cmakedefine HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the `putenv' function. */ +#cmakedefine HAVE_PUTENV 1 + +/* Define to 1 if you have the `rand' function. */ +#cmakedefine HAVE_RAND 1 + +/* Define to 1 if you have the `rand_r' function. */ +#cmakedefine HAVE_RAND_R 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_RESOLV_H 1 + +/* Have shl_load based dso */ +#cmakedefine HAVE_SHLLOAD 1 + +/* Define to 1 if you have the `signal' function. */ +#cmakedefine HAVE_SIGNAL 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `snprintf' function. */ +#cmakedefine HAVE_SNPRINTF 1 + +/* Define to 1 if you have the `sprintf' function. */ +#cmakedefine HAVE_SPRINTF 1 + +/* Define to 1 if you have the `srand' function. */ +#cmakedefine HAVE_SRAND 1 + +/* Define to 1 if you have the `sscanf' function. */ +#cmakedefine HAVE_SSCANF 1 + +/* Define to 1 if you have the `stat' function. */ +#cmakedefine HAVE_STAT 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H 1 + +/* Define to 1 if you have the `strftime' function. */ +#cmakedefine HAVE_STRFTIME 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#cmakedefine HAVE_SYS_DIR_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file, and it defines `DIR'. + */ +#cmakedefine HAVE_SYS_NDIR_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIMEB_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the `time' function. */ +#cmakedefine HAVE_TIME 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H 1 + +/* Whether va_copy() is available */ +#cmakedefine HAVE_VA_COPY 1 + +/* Define to 1 if you have the `vfprintf' function. */ +#cmakedefine HAVE_VFPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#cmakedefine HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `vsprintf' function. */ +#cmakedefine HAVE_VSPRINTF 1 + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_ZLIB_H 1 + +/* Whether __va_copy() is available */ +#cmakedefine HAVE___VA_COPY 1 + +/* Define as const if the declaration of iconv() needs const. */ +#define ICONV_CONST @ICONV_CONST@ + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#cmakedefine LT_OBJDIR "@LT_OBJDIR@" + +/* Name of package */ +#define PACKAGE "@PACKAGE@" + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "@PACKAGE_BUGREPORT@" + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "@PACKAGE_STRING@" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "@PACKAGE_TARNAME@" + +/* Define to the home page for this package. */ +#define PACKAGE_URL "@PACKAGE_URL@" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "@PACKAGE_VERSION@" + +/* Type cast for the send() function 2nd arg */ +#cmakedefine SEND_ARG2_CAST @SEND_ARG2_CAST@ + +/* Define to 1 if you have the ANSI C header files. */ +#cmakedefine STDC_HEADERS 1 + +/* Support for IPv6 */ +#cmakedefine SUPPORT_IP6 1 + +/* Define if va_list is an array type */ +#cmakedefine VA_LIST_IS_ARRAY 1 + +/* Version number of package */ +#cmakedefine VERSION "@VERSION@" + +/* Determine what socket length (socklen_t) data type is */ +#cmakedefine XML_SOCKLEN_T @XML_SOCKLEN_T@ + +/* Define for Solaris 2.5.1 so the uint32_t typedef from , + , or is not used. If the typedef were allowed, the + #define below would cause a syntax error. */ +#cmakedefine _UINT32_T @_UINT32_T@ + +/* ss_family is not defined here, use __ss_family instead */ +#cmakedefine ss_family @ss_family@ + +/* Define to the type of an unsigned integer type of width exactly 32 bits if + such a type exists and the standard includes do not define it. */ +#cmakedefine uint32_t @uint32_t@ diff --git a/third_party/sqlite3/CMakeLists.txt b/third_party/sqlite3/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..4cffbf21790daf40897cba7e4533c466f8745cd2 --- /dev/null +++ b/third_party/sqlite3/CMakeLists.txt @@ -0,0 +1,7 @@ +set(sqlite3_source + ${sqlite3_dir}/src/sqlite3.c +) + +add_library(sqlite3 STATIC ${sqlite3_source}) +add_definitions(-DSQLITE_OMIT_LOAD_EXTENSION) +target_link_libraries(sqlite3 pthread m) \ No newline at end of file diff --git a/win32.cmake b/win32.cmake new file mode 100644 index 0000000000000000000000000000000000000000..4b77f77ad35f5f4920be2f4a623e2ff5bc660a23 --- /dev/null +++ b/win32.cmake @@ -0,0 +1,10 @@ +SET(CMAKE_SYSTEM_NAME Windows) +SET(CMAKE_C_COMPILER x86_64-w64-mingw32-gcc) +SET(CMAKE_CXX_COMPILER x86_64-w64-mingw32-g++) +SET(CMAKE_CXX_LINK_EXECUTABLE x86_64-w64-mingw32-ld) +SET(CMAKE_CXX_COMPILER_AR x86_64-w64-mingw32-ar) +SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + +SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) +SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) +SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)