diff --git a/src/plugins/pol/CMakeLists.txt b/src/plugins/pol/CMakeLists.txt
index 420f7f7..ed2b571 100644
--- a/src/plugins/pol/CMakeLists.txt
+++ b/src/plugins/pol/CMakeLists.txt
@@ -3,22 +3,21 @@ include_directories(${GPUI_INCLUDE_DIRS})
find_package(Qt5 COMPONENTS Core REQUIRED)
+set(CMAKE_CXX_STANDARD 17)
+
set(HEADERS
polformat.h
-
- pregdata.h
- pregparser.h
- iconvwrapper.h
+ common.h
+ encoding.h
+ parser.h
)
set(SOURCES
+ binary.cpp
+ parser.cpp
+
polplugin.cpp
polformat.cpp
-
- pregdata.cpp
- pregparser.cpp
- pregwriter.cpp
- iconvwrapper.cpp
)
add_gpui_plugin(pol-plugin ${SOURCES})
diff --git a/src/plugins/pol/binary.cpp b/src/plugins/pol/binary.cpp
new file mode 100644
index 0000000..b040400
--- /dev/null
+++ b/src/plugins/pol/binary.cpp
@@ -0,0 +1,171 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+
+#include "binary.h"
+#include "common.h"
+
+namespace pol {
+
+std::string readStringFromBuffer(std::istream &buffer, size_t size, iconv_t conv)
+{
+ bool custom_conv = false;
+ if (conv == nullptr) {
+ conv = iconv_open("UTF-8", "UTF-16LE");
+ custom_conv = true;
+ }
+
+ if (conv == ICONV_ERROR_DESCRIPTOR) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered with the inability to create a iconv descriptor.");
+ }
+
+ std::basic_string source((size / 2) - 1, '\0');
+
+ // std::the string contains '\0' at the end (C style), which means that the actual buffer size
+ // is `size`. We read `size` bytes to check that the buffer ends with '\0'.
+ // '\0' is included in `size`, so we read `size` bytes.
+ buffer.read(reinterpret_cast(source.data()), size);
+ check_stream(buffer);
+
+ // Check that the buffer ends with the two '\0'.
+ if (source.data()[(size / 2) - 1] != 0) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered with invalid UTF-16LE buffer.");
+ }
+
+ auto result = convert(source, conv);
+ if (custom_conv) {
+ iconv_close(conv);
+ }
+ return result;
+}
+
+size_t writeStringToBuffer(std::ostream &buffer, const std::string &source, iconv_t conv)
+{
+ bool custom_conv = false;
+ if (conv == nullptr) {
+ conv = iconv_open("UTF-16LE", "UTF-8");
+ custom_conv = true;
+ }
+
+ if (conv == ICONV_ERROR_DESCRIPTOR) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered with the inability to create a iconv descriptor.");
+ }
+
+ std::basic_string converted = convert(source, conv);
+
+ buffer.write(reinterpret_cast(converted.data()),
+ (converted.size() + 1) * sizeof(char16_t));
+ check_stream(buffer);
+
+ if (custom_conv) {
+ iconv_close(conv);
+ }
+ return (converted.size() + 1) * sizeof(char16_t);
+}
+
+std::vector readStringsFromBuffer(std::istream &buffer, size_t size, iconv_t conv)
+{
+ bool custom_conv = false;
+
+ if (size == 0) {
+ return {};
+ }
+ if (conv == nullptr) {
+ conv = iconv_open("UTF-8", "UTF-16LE");
+ custom_conv = true;
+ }
+
+ if (conv == ICONV_ERROR_DESCRIPTOR) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered with the inability to create a iconv descriptor.");
+ }
+
+ std::vector result;
+ std::basic_string tmp;
+ size_t current = 0;
+ size_t found = 0;
+
+ // std::string contains '\0' at the end (C style), which means that the actual buffer size
+ // is `size`. We read `size` bytes to check that the buffer ends with '\0'.
+ // '\0' is included in `size`, so we read `size` bytes.
+ tmp.resize((size / 2) - 1);
+ buffer.read(reinterpret_cast(tmp.data()), size);
+ check_stream(buffer);
+
+ while (found <= tmp.size()) {
+ found = tmp.find(char16_t(0), current);
+
+ if (found == std::string::npos) {
+ found = tmp.size();
+
+ if (tmp.data()[found] != 0) {
+ return {};
+ }
+ }
+
+ result.push_back(
+ convert(tmp.cbegin() + current, tmp.cbegin() + found, conv));
+
+ current = found + 1;
+ found = current;
+ }
+
+ if (custom_conv) {
+ iconv_close(conv);
+ }
+ return result;
+}
+
+size_t writeStringsFromBuffer(std::ostream &buffer, const std::vector &data, iconv_t conv)
+{
+ size_t size = 0;
+
+ for (const auto &str : data) {
+ auto tmp = writeStringToBuffer(buffer, str, conv);
+ size += tmp;
+ }
+
+ return size;
+}
+
+std::vector readVectorFromBuffer(std::istream &buffer, size_t size)
+{
+ std::vector result;
+ result.resize(size);
+
+ buffer.read(reinterpret_cast(result.data()), size);
+ check_stream(buffer);
+
+ return result;
+}
+
+void writeVectorToBuffer(std::ostream &buffer, const std::vector &data)
+{
+ buffer.write(reinterpret_cast(data.data()), data.size());
+ check_stream(buffer);
+}
+
+} // namespace pol
diff --git a/src/plugins/pol/binary.h b/src/plugins/pol/binary.h
new file mode 100644
index 0000000..d496891
--- /dev/null
+++ b/src/plugins/pol/binary.h
@@ -0,0 +1,135 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef PREGPARSER_BINARY
+#define PREGPARSER_BINARY
+
+#include
+#include
+#include
+#include
+
+#include "encoding.h"
+
+namespace pol {
+
+/*!
+ * \brief Get string from istream (binary)
+ * if conv == nullptr, then conv will be initialized inside by `iconv_open("UTF-8", "UTF-16LE")`
+ * \return on any error return empty optional
+ * \warning string in buffer must be ended with '\0'
+ * \warning `conv` must be initialized by `iconv_open("UTF-8", "UTF-16LE")`
+ * \warning if `conv` is (size_t)-1, then function will throw std::runtime_error
+ */
+std::string readStringFromBuffer(std::istream &buffer, size_t size, iconv_t conv = nullptr);
+/*!
+ * \brief Put string from istream (binary)
+ * if conv == nullptr, then conv will be initialized inside by `iconv_open("UTF-8", "UTF-16LE")`
+ * \return Size of writed string. On any error return (size_t)-1
+ * \warning string in buffer will be ended with '\0'
+ * \warning `conv` must be initialized by `iconv_open("UTF-16LE", "UTF-8")`
+ * \warning if `conv` is (size_t)-1, then function will throw std::runtime_error
+ */
+size_t writeStringToBuffer(std::ostream &buffer, const std::string &data, iconv_t conv = nullptr);
+
+/*!
+ * \brief Get strings from istream (binary)
+ * if conv == nullptr, then conv will be initialized inside by `iconv_open("UTF-8", "UTF-16LE")`
+ * \return on any error return empty optional
+ * \warning every strings in buffer must be ended with '\0' (last included)
+ * \warning `conv` must be initialized by `iconv_open("UTF-8", "UTF-16LE")`
+ * \warning if `conv` is (size_t)-1, then function will throw std::runtime_error
+ */
+std::vector readStringsFromBuffer(std::istream &buffer, size_t size, iconv_t conv = nullptr);
+/*!
+ * \brief Put string from istream (binary)
+ * if conv == nullptr, then conv will be initialized inside by `iconv_open("UTF-8", "UTF-16LE")`
+ * \return Size of writed strings. On any error return (size_t)-1
+ * \warning every string in buffer will be ended with '\0' (last included)
+ * \warning `conv` must be initialized by `iconv_open("UTF-16LE", "UTF-8")`
+ * \warning if `conv` is (size_t)-1, then function will throw std::runtime_error
+ */
+size_t writeStringsFromBuffer(std::ostream &buffer, const std::vector &data,
+ iconv_t conv = nullptr);
+/*!
+ * \brief Get vector of raw data from istream (binary)
+ */
+std::vector readVectorFromBuffer(std::istream &buffer, size_t size);
+
+/*!
+ * \brief Put vector of raw data to istream (binary)
+ */
+void writeVectorToBuffer(std::ostream &buffer, const std::vector &data);
+
+/*!
+ * \brief Get integral number from istream (binary)
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+T readIntegralFromBuffer(std::istream &buffer)
+{
+ T num = 0;
+
+ buffer.read(reinterpret_cast(&num), sizeof(T));
+ if (buffer.fail()) {
+ if (buffer.eof()) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to read integral number from buffer, EOF was encountered.");
+ }
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to read integral number from buffer, error was encountered.");
+ }
+ if constexpr (LE) {
+ return leToNative(num);
+ } else {
+ return beToNative(num);
+ }
+
+ return num;
+}
+
+/*!
+ * \brief Put integral number to ostream (binary)
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+void writeIntegralToBuffer(std::ostream &buffer, T num)
+{
+ if constexpr (LE) {
+ num = nativeToLe(num);
+ } else {
+ num = nativeToBe(num);
+ }
+
+ buffer.write(reinterpret_cast(&num), sizeof(T));
+ if (buffer.fail()) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to write integral number to buffer, error was encountered.");
+ }
+}
+
+} // namespace pol
+
+#endif // PREGPARSER_BINARY
diff --git a/src/plugins/pol/common.h b/src/plugins/pol/common.h
new file mode 100644
index 0000000..069c82a
--- /dev/null
+++ b/src/plugins/pol/common.h
@@ -0,0 +1,73 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef PREGPARSER_COMMON
+#define PREGPARSER_COMMON
+
+#include
+#include
+
+#include "encoding.h"
+#include "iconv.h"
+
+namespace pol {
+
+inline void check_stream(std::istream &target)
+{
+ if (target.fail()) {
+ if (target.eof()) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to read buffer, EOF was encountered.");
+ }
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to read buffer, error was encountered.");
+ }
+}
+inline void check_stream(std::ostream &target)
+{
+ if (target.fail()) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to write buffer, error was encountered.");
+ }
+}
+inline void check_sym(std::istream &target, char16_t sym)
+{
+ char16_t buff;
+ target.read(reinterpret_cast(&buff), 2);
+ buff = leToNative(buff);
+
+ check_stream(target);
+
+ if (buff != sym) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Failed to read/write buffer, invalid symbol was encountered.");
+ }
+}
+inline void write_sym(std::ostream &target, char16_t sym)
+{
+ sym = nativeToLe(sym);
+ target.write(reinterpret_cast(&sym), 2);
+
+ check_stream(target);
+}
+} // namespace pol
+
+#endif // PREGPARSER_COMMON
diff --git a/src/plugins/pol/encoding.h b/src/plugins/pol/encoding.h
new file mode 100644
index 0000000..0216f75
--- /dev/null
+++ b/src/plugins/pol/encoding.h
@@ -0,0 +1,184 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef PREGPARSER_ENCODING
+#define PREGPARSER_ENCODING
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "iconv.h"
+
+namespace pol {
+
+// C++ before C++20 is not support endianess. Becouse of that, we need to
+// provide our own implementation
+
+enum class Endian {
+ BigEndian,
+ LittleEndian = 1,
+};
+
+/*!
+ * \brief Get current native endianness
+ */
+inline Endian getEndianess()
+{
+ union {
+ uint32_t i;
+ char c[4];
+ } bint = { 0x01020304 };
+
+ return bint.c[0] == 0x01 ? Endian::BigEndian : Endian::LittleEndian;
+}
+
+/*!
+ * \brief Byte swap a integral number.
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+inline T byteswap(T value)
+{
+ if constexpr (sizeof(T) == 1) {
+ return value;
+ }
+ if constexpr (sizeof(T) == 2) {
+ return (value >> 8) | (value << 8);
+ }
+ if constexpr (sizeof(T) == 4) {
+ return (value >> 24) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | (value << 24);
+ }
+ if constexpr (sizeof(T) == 8) {
+ return (value >> 56) | ((value >> 40) & 0xFF00) | ((value >> 24) & 0xFF0000)
+ | ((value >> 8) & 0xFF000000) | ((value << 8) & 0xFF00000000)
+ | ((value << 24) & 0xFF0000000000) | ((value << 40) & 0xFF000000000000)
+ | (value << 56);
+ }
+ return value;
+}
+
+/*!
+ * \brief Convert big endian to native endianness
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+inline T beToNative(T value)
+{
+ auto endianess = getEndianess();
+ if (endianess == Endian::BigEndian) {
+ return value;
+ }
+ return byteswap(value);
+}
+
+/*!
+ * \brief Convert little endian to native endianness
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+inline T leToNative(T value)
+{
+ auto endianess = getEndianess();
+ if (endianess == Endian::LittleEndian) {
+ return value;
+ }
+ return byteswap(value);
+}
+/*!
+ * \brief Convert native endianness to big endian
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+inline constexpr T nativeToBe(T num)
+{
+ return beToNative(num);
+}
+
+/*!
+ * \brief Convert native endianness to little endian
+ */
+template
+ && sizeof(T) <= sizeof(unsigned long long)>>
+inline constexpr T nativeToLe(T num)
+{
+ return leToNative(num);
+}
+
+/*!
+ * \brief Helper alias for string iterator(just minimize code size)
+ */
+template
+using string_const_iterator = typename std::basic_string::const_iterator;
+
+/*!
+ * \brief Convert string from one encoding to another using iconv
+ */
+template
+inline std::basic_string convert(string_const_iterator begin,
+ string_const_iterator end, iconv_t conv)
+{
+ std::basic_string result = {};
+
+ char *inbuf = reinterpret_cast(const_cast(&*begin));
+ size_t inbytesLeft = std::distance(begin, end) * sizeof(source_char);
+
+ auto temp = std::make_unique>();
+ char *outbuf = temp->data();
+ size_t outbytesLeft = temp->size();
+
+ while (inbytesLeft > 0) {
+ auto ret = iconv(conv, &inbuf, &inbytesLeft, &outbuf, &outbytesLeft);
+ if (ret == ICONV_ERROR_CODE && errno != E2BIG) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered corrupted unicode string.");
+ }
+
+ result.append(reinterpret_cast(temp->data()),
+ reinterpret_cast(outbuf));
+ outbuf = temp->data();
+ outbytesLeft = temp->size();
+ }
+
+ return result;
+}
+
+/*!
+ * \brief Convert string from one encoding to another using iconv
+ */
+template
+inline std::basic_string convert(const std::basic_string &source,
+ iconv_t conv)
+{
+ return convert(source.cbegin(), source.cend(), conv);
+}
+
+} // namespace pol
+
+#endif // PREGPARSER_ENCODING
diff --git a/src/plugins/pol/iconv.h b/src/plugins/pol/iconv.h
new file mode 100644
index 0000000..f7c4074
--- /dev/null
+++ b/src/plugins/pol/iconv.h
@@ -0,0 +1,31 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#ifndef PREGPARSER_ICONV
+#define PREGPARSER_ICONV
+
+#include
+
+namespace pol {
+static const size_t ICONV_ERROR_CODE = std::numeric_limits::max();
+static const iconv_t ICONV_ERROR_DESCRIPTOR = reinterpret_cast(ICONV_ERROR_CODE);
+} // namespace pol
+
+#endif // PREGPARSER_ICONV
diff --git a/src/plugins/pol/iconvwrapper.cpp b/src/plugins/pol/iconvwrapper.cpp
deleted file mode 100644
index 1c27cef..0000000
--- a/src/plugins/pol/iconvwrapper.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#include "iconvwrapper.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-
-namespace gpui {
-
-IconvWrapper::IconvWrapper(std::string from_encoding,
- std::string to_encoding) {
- this->fromEncoding = from_encoding;
- this->toEncoding = to_encoding;
- this->conv =
- iconv_open(this->toEncoding.c_str(), this->fromEncoding.c_str());
- if (this->invalidOpen == this->conv) {
- throw std::system_error(errno, std::system_category());
- }
-}
-
-IconvWrapper::~IconvWrapper() {
- if (this->invalidOpen != this->conv) {
- int result = iconv_close(this->conv);
- this->conv = this->invalidOpen;
- if (0 != result) {
- std::cout << "Error on iconv_close " << errno << std::endl;
- }
- }
-}
-
-std::string IconvWrapper::convert(std::string from) {
- /*
- Copyright (c) 2011, Yuya Unno
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are met:
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- * Neither the name of the Yuya Unno nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
- DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- bool ignore_error_ = true;
- /* Values like INT_MAX cause awful slowdown */
- size_t buf_size_ = 1024;
- // copy the string to a buffer as iconv function requires a non-const char
- // pointer.
- std::vector in_buf(from.begin(), from.end());
- char *src_ptr = &in_buf[0];
- size_t src_size = from.size();
-
- std::vector buf(buf_size_);
- std::string dst;
- while (0 < src_size) {
- char *dst_ptr = &buf[0];
- size_t dst_size = buf.size();
- size_t res =
- ::iconv(this->conv, &src_ptr, &src_size, &dst_ptr, &dst_size);
- if (res == static_cast(-1))
- {
- if (errno == E2BIG) {
- // ignore this error
- } else if (ignore_error_) {
- // skip character
- ++src_ptr;
- --src_size;
- } else {
- this->checkConversionError();
- }
- }
- dst.append(&buf[0], buf.size() - dst_size);
- }
- std::string output;
- dst.swap(output);
- return output;
-}
-
-void IconvWrapper::checkConversionError() {
- switch (errno) {
- case EBADF: {
- std::cout << "EBADF" << std::endl;
- break;
- }
- case E2BIG: {
- std::cout << "E2BIG" << std::endl;
- break;
- }
- case EILSEQ: {
- std::cout << "EILSEQ" << std::endl;
- break;
- }
- case EINVAL: {
- std::cout << "EINVAL" << std::endl;
- break;
- }
- default: {
- std::cout << "Unknown error " << errno << std::endl;
- break;
- }
- }
-}
-
-}
diff --git a/src/plugins/pol/iconvwrapper.h b/src/plugins/pol/iconvwrapper.h
deleted file mode 100644
index c77c503..0000000
--- a/src/plugins/pol/iconvwrapper.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#ifndef GPUI_ICONV_WRAPPER_H
-#define GPUI_ICONV_WRAPPER_H
-
-#include
-
-#include
-
-namespace gpui {
-
-/*!
- * \brief The IconWrapper provides wrapper for POSIX iconv functionality to ease the access from C++
- * and a convenient way to operate on std::string buffers.
- */
-class IconvWrapper {
- const iconv_t invalidOpen = reinterpret_cast(-1);
-
- IconvWrapper(IconvWrapper const &) = delete;
- IconvWrapper &operator=(IconvWrapper const &) = delete;
-
- iconv_t conv = nullptr;
- std::string fromEncoding {};
- std::string toEncoding {};
-
-public:
- IconvWrapper(std::string from_encoding, std::string to_encoding);
- ~IconvWrapper();
-
- /*!
- * \brief Convert std::string to another format.
- */
- std::string convert(std::string from);
-
-private:
- /*!
- * \brief Check if there were conversion errors.
- */
- void checkConversionError();
-};
-
-}
-
-#endif // GPUI_ICONV_WRAPPER_H
diff --git a/src/plugins/pol/parser.cpp b/src/plugins/pol/parser.cpp
new file mode 100644
index 0000000..d1cc909
--- /dev/null
+++ b/src/plugins/pol/parser.cpp
@@ -0,0 +1,463 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+
+#include "binary.h"
+#include "common.h"
+#include "parser.h"
+
+namespace pol {
+
+/*!
+ * \brief Valid POL Registery file header
+ */
+static const char valid_header[8] = { 0x50, 0x52, 0x65, 0x67, 0x01, 0x00, 0x00, 0x00 };
+
+/*!
+ * \brief Match regex `[\x20-\x7E]`
+ */
+static inline bool isValueCharacter(uint8_t sym)
+{
+ return sym >= 0x20 && sym <= 0x7E;
+}
+
+GPUI_SYMBOL_EXPORT PRegParser::PRegParser()
+{
+ this->m_iconvReadId = ::iconv_open("UTF-8", "UTF-16LE");
+ this->m_iconvWriteId = ::iconv_open("UTF-16LE", "UTF-8");
+}
+
+GPUI_SYMBOL_EXPORT PolicyFile PRegParser::parse(std::istream &stream)
+{
+ PolicyTree instructions;
+
+ parseHeader(stream);
+
+ stream.peek();
+ while (!stream.eof()) {
+ insertInstruction(stream, instructions);
+ stream.peek();
+ }
+
+ return { instructions };
+}
+
+GPUI_SYMBOL_EXPORT bool PRegParser::write(std::ostream &stream, const PolicyFile &file)
+{
+ writeHeader(stream);
+ for (const auto &[key, records] : file.instructions) {
+ for (const auto &[value, array] : records) {
+ for (const auto &instruction : array) {
+ writeInstruction(stream, instruction, key, value);
+ }
+ }
+ }
+
+ return true;
+}
+
+GPUI_SYMBOL_EXPORT PRegParser::~PRegParser()
+{
+ ::iconv_close(this->m_iconvReadId);
+ ::iconv_close(this->m_iconvWriteId);
+}
+
+void PRegParser::parseHeader(std::istream &stream)
+{
+ char buffer[8];
+ stream.read(buffer, 8);
+ check_stream(stream);
+
+ const uint64_t header = *reinterpret_cast(&buffer[0]);
+ const uint64_t normal_header = *reinterpret_cast(&valid_header[0]);
+
+ if (header != normal_header) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered with invalid header.");
+ }
+}
+
+uint32_t PRegParser::getSize(std::istream &stream)
+{
+ return readIntegralFromBuffer(stream);
+}
+
+PolicyRegType PRegParser::getType(std::istream &stream)
+{
+ PolicyRegType type = static_cast(readIntegralFromBuffer(stream));
+
+ if (type >= PolicyRegType::REG_SZ && type <= PolicyRegType::REG_QWORD_BIG_ENDIAN) {
+ return type;
+ }
+
+ return {};
+}
+
+std::string PRegParser::getKey(std::istream &stream)
+{
+ std::string key;
+ char16_t data;
+
+ stream.read(reinterpret_cast(&data), 2);
+ check_stream(stream);
+
+ data = leToNative(data);
+
+ while (data >= 0x20 && data <= 0x7E && data != 0x5C) {
+ key.push_back(static_cast(data));
+
+ stream.read(reinterpret_cast(&data), 2);
+ check_stream(stream);
+
+ data = leToNative(data);
+ }
+
+ // Key from Keypath must contain 1 or more symbols.
+ if (key.empty() || (data != 0 && data != 0x5C)) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected symbol with code " + std::to_string(data) + ".");
+ }
+
+ // Remove last symbol
+ stream.seekg(-2, std::ios::cur);
+
+ return { key };
+}
+
+std::string PRegParser::getKeypath(std::istream &stream)
+{
+ std::string keyPath;
+ char16_t sym = 0;
+
+ while (true) {
+ auto key = getKey(stream);
+
+ keyPath.append(key);
+
+ stream.read(reinterpret_cast(&sym), 2);
+ check_stream(stream);
+
+ // End of Keypath
+ if (sym == 0) {
+ break;
+ }
+
+ // This if never be executed, but for safety i use it
+ if (sym != 0x5C) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected symbol with code " + std::to_string(sym)
+ + ".");
+ }
+
+ keyPath.push_back('\\');
+ }
+
+ return { keyPath };
+}
+
+std::string PRegParser::getValue(std::istream &stream)
+{
+ std::string result;
+ char16_t data;
+
+ stream.read(reinterpret_cast(&data), 2);
+ check_stream(stream);
+ data = leToNative(data);
+
+ // Key in specs [\x20-\x5B\x5D-\x7E](exclude '\'), when keypath include '\' like delimeter
+ while (data >= 0x20 && data <= 0x7E) {
+ // Key from Keypath must contain 1 or more symbols.
+
+ // Check maximum value length
+ if (result.length() == 259) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected symbol with code " + std::to_string(data)
+ + ".");
+ }
+
+ result.push_back(data);
+
+ stream.read(reinterpret_cast(&data), 2);
+ check_stream(stream);
+ data = leToNative(data);
+ }
+
+ if (data != 0 || result.empty()) {
+ return {};
+ }
+
+ return { result };
+}
+
+PolicyData PRegParser::getData(std::istream &stream, PolicyRegType type, uint32_t size)
+{
+ switch (type) {
+ case PolicyRegType::REG_NONE:
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected type REG_NONE.");
+ case PolicyRegType::REG_SZ:
+ case PolicyRegType::REG_EXPAND_SZ:
+ case PolicyRegType::REG_LINK:
+ return { readStringFromBuffer(stream, size, this->m_iconvReadId) };
+
+ case PolicyRegType::REG_BINARY:
+ return { readVectorFromBuffer(stream, size) };
+
+ case PolicyRegType::REG_DWORD_LITTLE_ENDIAN:
+ return { readIntegralFromBuffer(stream) };
+ case PolicyRegType::REG_DWORD_BIG_ENDIAN:
+ return { readIntegralFromBuffer(stream) };
+
+ case PolicyRegType::REG_MULTI_SZ:
+ case PolicyRegType::REG_RESOURCE_LIST:
+ case PolicyRegType::REG_FULL_RESOURCE_DESCRIPTOR: // ????
+ case PolicyRegType::REG_RESOURCE_REQUIREMENTS_LIST:
+ return { readStringsFromBuffer(stream, size, this->m_iconvReadId) };
+
+ case PolicyRegType::REG_QWORD_LITTLE_ENDIAN:
+ return { readIntegralFromBuffer(stream) };
+ case PolicyRegType::REG_QWORD_BIG_ENDIAN:
+ return { readIntegralFromBuffer(stream) };
+ break;
+ }
+ return {};
+}
+
+void PRegParser::insertInstruction(std::istream &stream, PolicyTree &tree)
+{
+ PolicyInstruction instruction;
+ uint32_t dataSize;
+
+ check_sym(stream, '[');
+
+ std::string keyPath = getKeypath(stream);
+
+ check_sym(stream, ';');
+
+ std::string value = getValue(stream);
+
+ try {
+ check_sym(stream, ';');
+
+ instruction.type = getType(stream);
+
+ check_sym(stream, ';');
+
+ dataSize = getSize(stream);
+
+ check_sym(stream, ';');
+
+ instruction.data = getData(stream, instruction.type, dataSize);
+
+ check_sym(stream, ']');
+
+ if (tree.find(keyPath) == tree.end()) {
+ tree[keyPath] = {};
+ }
+ if (tree[keyPath].find(value) == tree[keyPath].end()) {
+ tree[keyPath][value] = {};
+ }
+ tree[keyPath][value].emplace_back(std::move(instruction));
+
+ } catch (const std::exception &e) {
+ throw std::runtime_error(std::string(e.what()) + "\nLINE: " + std::to_string(__LINE__)
+ + ", FILE: " + __FILE__
+ + ", Error was encountered wile parsing instruction with key: "
+ + keyPath + ", value: " + value);
+ }
+}
+
+std::stringstream PRegParser::getDataStream(const PolicyData &data, PolicyRegType type)
+{
+ std::stringstream stream;
+
+ switch (type) {
+ case PolicyRegType::REG_SZ:
+ case PolicyRegType::REG_EXPAND_SZ:
+ case PolicyRegType::REG_LINK:
+ writeStringToBuffer(stream, std::get(data), this->m_iconvWriteId);
+ break;
+
+ case PolicyRegType::REG_BINARY:
+ writeVectorToBuffer(stream, std::get>(data));
+ break;
+
+ case PolicyRegType::REG_DWORD_LITTLE_ENDIAN:
+ writeIntegralToBuffer(stream, std::get(data));
+ break;
+ case PolicyRegType::REG_DWORD_BIG_ENDIAN:
+ writeIntegralToBuffer(stream, std::get(data));
+ break;
+
+ case PolicyRegType::REG_MULTI_SZ:
+ case PolicyRegType::REG_RESOURCE_LIST:
+ case PolicyRegType::REG_FULL_RESOURCE_DESCRIPTOR: // ????
+ case PolicyRegType::REG_RESOURCE_REQUIREMENTS_LIST:
+ writeStringsFromBuffer(stream, std::get>(data),
+ this->m_iconvWriteId);
+ break;
+
+ case PolicyRegType::REG_QWORD_LITTLE_ENDIAN:
+ writeIntegralToBuffer(stream, std::get(data));
+ break;
+ case PolicyRegType::REG_QWORD_BIG_ENDIAN:
+ writeIntegralToBuffer(stream, std::get(data));
+ break;
+
+ case PolicyRegType::REG_NONE:
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected type REG_NONE.");
+ default:
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected type UNKNOWN("
+ + std::to_string(static_cast(type)) + ".");
+ }
+
+ return stream;
+}
+
+void PRegParser::writeHeader(std::ostream &stream)
+{
+ stream.write(valid_header, sizeof(valid_header));
+}
+
+void PRegParser::validateKey(std::string::const_iterator &begin, std::string::const_iterator &end)
+{
+ auto cursor = begin;
+
+ while (cursor != end && *cursor >= 0x20 && *cursor <= 0x7E && *cursor != 0x5C) {
+ ++cursor;
+ }
+
+ if (cursor == begin) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Key is empty.");
+ }
+ begin = cursor;
+}
+
+void PRegParser::validateKeypath(std::string::const_iterator begin, std::string::const_iterator end)
+{
+ if (begin == end) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Keypath is empty.");
+ }
+ while (begin != end) {
+ validateKey(begin, end);
+
+ if (begin != end && *begin != 0x5C) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Invalid character in key was encountered.");
+ }
+
+ // Skip 0x5C character
+ ++begin;
+ }
+}
+void PRegParser::validateValue(std::string::const_iterator begin, std::string::const_iterator end)
+{
+ if (begin == end) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Value is empty.");
+ }
+
+ while (begin != end) {
+ if (*begin < 0x20 || *begin > 0x7E) {
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Invalid character in value was encountered.");
+ }
+ ++begin;
+ }
+}
+
+void PRegParser::validateType(PolicyRegType type)
+{
+ switch (type) {
+ default:
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected type UNKNOWN.");
+ case PolicyRegType::REG_NONE:
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected type REG_NONE.");
+
+ case PolicyRegType::REG_SZ:
+ case PolicyRegType::REG_EXPAND_SZ:
+ case PolicyRegType::REG_BINARY:
+ case PolicyRegType::REG_DWORD_LITTLE_ENDIAN:
+ case PolicyRegType::REG_DWORD_BIG_ENDIAN:
+ case PolicyRegType::REG_LINK:
+ case PolicyRegType::REG_MULTI_SZ:
+ case PolicyRegType::REG_RESOURCE_LIST:
+ case PolicyRegType::REG_FULL_RESOURCE_DESCRIPTOR:
+ case PolicyRegType::REG_RESOURCE_REQUIREMENTS_LIST:
+ case PolicyRegType::REG_QWORD_LITTLE_ENDIAN:
+ case PolicyRegType::REG_QWORD_BIG_ENDIAN:
+ break;
+ }
+}
+
+void PRegParser::writeInstruction(std::ostream &stream, const PolicyInstruction &instruction,
+ std::string key, std::string value)
+{
+
+ try {
+ validateKeypath(key.begin(), key.end());
+ validateValue(value.begin(), value.end());
+ validateType(instruction.type);
+
+ write_sym(stream, '[');
+
+ writeStringToBuffer(stream, key);
+
+ write_sym(stream, ';');
+
+ writeStringToBuffer(stream, value);
+
+ write_sym(stream, ';');
+
+ writeIntegralToBuffer(stream, static_cast(instruction.type));
+
+ write_sym(stream, ';');
+
+ auto dataStream = getDataStream(instruction.data, instruction.type);
+
+ writeIntegralToBuffer(stream, static_cast(dataStream.tellp()));
+
+ write_sym(stream, ';');
+
+ stream << dataStream.str();
+ check_stream(stream);
+
+ write_sym(stream, ']');
+ } catch (const std::exception &e) {
+ throw std::runtime_error(std::string(e.what()) + "\nLINE: " + std::to_string(__LINE__)
+ + ", FILE: " + __FILE__
+ + ", Error was encountered while writing instruction with key: "
+ + key + ", value: " + value);
+ }
+}
+
+GPUI_SYMBOL_EXPORT std::unique_ptr createPregParser()
+{
+ return std::make_unique();
+}
+
+} // namespace pol
diff --git a/src/plugins/pol/parser.h b/src/plugins/pol/parser.h
new file mode 100644
index 0000000..c838772
--- /dev/null
+++ b/src/plugins/pol/parser.h
@@ -0,0 +1,200 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#ifndef PREGPARSER_PARSER
+#define PREGPARSER_PARSER
+
+#include "../../../src/core/core.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "iconv.h"
+
+namespace pol {
+
+enum class PolicyRegType {
+ REG_NONE,
+ /* Null-terminated-string */
+ REG_SZ = 1,
+ REG_EXPAND_SZ = 2,
+
+ /* Any kind of binary data */
+ REG_BINARY = 3,
+ /* 32-bit number */
+ REG_DWORD_LITTLE_ENDIAN = 4,
+
+ /* 32-bit number in NBO format */
+ REG_DWORD_BIG_ENDIAN = 5,
+
+ /* A null-terminated Unicode string that contains the target path of a
+ * symbolic link. */
+ REG_LINK = 6,
+
+ /* Sequence of null-terminated strings terminated by null-terminator */
+ REG_MULTI_SZ = 7,
+ REG_RESOURCE_LIST = 8,
+ REG_FULL_RESOURCE_DESCRIPTOR = 9,
+ REG_RESOURCE_REQUIREMENTS_LIST = 10,
+
+ /* 64-bit number */
+ REG_QWORD_LITTLE_ENDIAN = 11,
+ REG_QWORD_BIG_ENDIAN = 12,
+};
+
+typedef std::variant, std::vector, uint32_t,
+ uint64_t>
+ PolicyData;
+
+typedef struct PolicyInstruction
+{
+ inline bool operator==(const PolicyInstruction &other) const
+ {
+ return type == other.type && data == other.data;
+ }
+ inline bool operator!=(const PolicyInstruction &other) const
+ {
+ return type != other.type && data != other.data;
+ }
+
+ PolicyRegType type{};
+ PolicyData data{};
+} PolicyInstruction;
+
+typedef std::unordered_map>>
+ PolicyTree;
+
+typedef struct PolicyFile
+{
+ inline bool operator==(const PolicyFile &other) const
+ {
+ return instructions == other.instructions;
+ }
+ inline bool operator!=(const PolicyFile &other) const
+ {
+ return instructions != other.instructions;
+ }
+
+ PolicyTree instructions{};
+} PolicyFile;
+
+class GPUI_CORE_EXPORT PRegParser final
+{
+private:
+ /*!
+ * \brief Check regex `\x50\x52\x65\x67\x01\x00\x00\x00`
+ */
+ void parseHeader(std::istream &stream);
+ /*!
+ * \brief Check regex `(.{4})` and return first group as uint32_t (LE, it will be converted to
+ * native)
+ */
+ uint32_t getSize(std::istream &stream);
+ /*!
+ * \brief Convert binary data from stream to PolicyData
+ */
+ PolicyData getData(std::istream &stream, PolicyRegType type, uint32_t size);
+ /*!
+ * \brief Check 32bit LE regex `([\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC])` and return first
+ * group as Type
+ */
+ PolicyRegType getType(std::istream &stream);
+ /*!
+ * \brief Matches regex `([\x20-\x5B\x5D-\x7E]\x00)+` and return
+ * string as result (UTF-16LE will be converted to UTF-8)
+ */
+ std::string getKey(std::istream &stream);
+ /*!
+ * \brief Matches regex
+ * `((:?([\x20-\x5B\x5D-\x7E]\x00)+)(:?\x5C\x00([\x20-\x5B\x5D-\x7E]\x00)+)+)` and return first
+ * group as result
+ */
+ std::string getKeypath(std::istream &stream);
+ /*!
+ * \brief Matches regex `((:?[\x20-\x7E]\x00){1,259})` and return first group as result
+ * (UTF-16LE will be converted to UTF-8)
+ */
+ std::string getValue(std::istream &stream);
+ /*!
+ * \brief Matches ABNF `LBracket KeyPath SC Value SC Type SC Size SC Data RBracket`,
+ * where LBracket `\x5B\x00`, RBracket `\x5D\x00`, SC `\x3B\x00`. Return reduced structure
+ */
+ void insertInstruction(std::istream &stream, PolicyTree &tree);
+
+ /*!
+ * \brief Matches regex `([\x20-\x5B\x5D-\x7E]\x00)+` and throws an
+ * std::runtime_error if it completely does not match the regex
+ */
+ void validateKey(std::string::const_iterator &begin, std::string::const_iterator &end);
+ /*!
+ * \brief Matches regex
+ * `((:?([\x20-\x5B\x5D-\x7E]\x00)+)(:?\x5C\x00([\x20-\x5B\x5D-\x7E]\x00)+)+)` and throws an
+ * std::runtime_error if it completely does not match the regex
+ */
+ void validateKeypath(std::string::const_iterator begin, std::string::const_iterator end);
+ /*!
+ * \brief Matches regex `((:?[\x20-\x7E]\x00){1,259})` and throws an
+ * std::runtime_error if it completely does not match the regex
+ */
+ void validateValue(std::string::const_iterator begin, std::string::const_iterator end);
+ /*!
+ * \brief Validate type and throw an std::runtime_error if it is invalid
+ */
+ void validateType(PolicyRegType type);
+ /*!
+ * \brief Put `\x50\x52\x65\x67\x01\x00\x00\x00` into stream
+ */
+ void writeHeader(std::ostream &stream);
+ /*!
+ * \brief Put instruction, with ABNF
+ * `LBracket KeyPath SC Value SC Type SC Size SC Data RBracket`,
+ * where LBracket `\x5B\x00`, RBracket `\x5D\x00`, SC `\x3B\x00`, into stream.
+ */
+ void writeInstruction(std::ostream &stream, const PolicyInstruction &instruction,
+ std::string key, std::string value);
+
+ /*!
+ * \brief Put PolicyRegData by PolicyRegType into stringstream
+ */
+ std::stringstream getDataStream(const PolicyData &data, PolicyRegType type);
+
+public:
+ PRegParser();
+ PolicyFile parse(std::istream &stream);
+ bool write(std::ostream &stream, const PolicyFile &file);
+ ~PRegParser();
+
+private:
+ PRegParser(const pol::PRegParser &) = delete;
+ void operator=(const pol::PRegParser &) = delete;
+
+ ::iconv_t m_iconvReadId{};
+ ::iconv_t m_iconvWriteId{};
+};
+
+std::unique_ptr createPregParser();
+
+} // namespace pol
+
+#endif // PREGPARSER_PARSER
diff --git a/src/plugins/pol/polformat.cpp b/src/plugins/pol/polformat.cpp
index 8a5be80..9584bf0 100644
--- a/src/plugins/pol/polformat.cpp
+++ b/src/plugins/pol/polformat.cpp
@@ -20,320 +20,236 @@
#include "polformat.h"
-#include "pregdata.h"
-#include "pregparser.h"
-#include "pregwriter.h"
-
#include "../../../src/plugins/administrative_templates/registry/registry.h"
#include "../../../src/plugins/administrative_templates/registry/registryentry.h"
#include "../../../src/plugins/administrative_templates/registry/registryentrytype.h"
+#include "parser.h"
+
#include
+#include
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
using namespace model::registry;
-namespace gpui
-{
+namespace gpui {
class RegistryEntryAdapter
{
-private:
- static std::unique_ptr adaptCharEntry(
- const preg::PregEntry &entry, model::registry::RegistryEntryType type)
- {
- auto registryEntry = std::make_unique>();
- registryEntry->key = entry.key.c_str();
- registryEntry->type = type;
- registryEntry->value = entry.value.c_str();
- if (entry.data)
- {
- void *pt = entry.data;
- size_t requiredSize = entry.size;
- registryEntry->data = QString::fromUtf16(
- reinterpret_cast(std::align(alignof(char16_t), sizeof(char), pt, requiredSize)));
- delete[] entry.data;
- }
-
- return registryEntry;
- }
-
- static std::unique_ptr adaptUInt32Entry(
- const preg::PregEntry &entry, model::registry::RegistryEntryType type, bool bigEndian = false)
- {
- auto registryEntry = std::make_unique>();
- registryEntry->key = entry.key.c_str();
- registryEntry->type = type;
- registryEntry->value = entry.value.c_str();
- if (entry.data)
- {
- uint32_t data = (uint32_t)((uint8_t) entry.data[0]) | (uint32_t)((uint8_t) entry.data[1]) << 8
- | (uint32_t)((uint8_t) entry.data[2]) << 16 | (uint32_t)((uint8_t) entry.data[3]) << 24;
-
- if (bigEndian)
- {
- data = bswap_32(data);
- }
- registryEntry->data = data;
- delete[] entry.data;
- }
-
- return registryEntry;
- }
-
- static std::unique_ptr adaptUInt64Entry(
- const preg::PregEntry &entry, model::registry::RegistryEntryType type, bool bigEndian = false)
- {
- auto registryEntry = std::make_unique>();
- registryEntry->key = entry.key.c_str();
- registryEntry->type = type;
- registryEntry->value = entry.value.c_str();
- if (entry.data)
- {
- uint64_t data = (uint64_t)((uint8_t) entry.data[0]) | (uint64_t)((uint8_t) entry.data[1]) << 8
- | (uint64_t)((uint8_t) entry.data[2]) << 16 | (uint64_t)((uint8_t) entry.data[3]) << 24
- | (uint64_t)((uint8_t) entry.data[4]) << 32 | (uint64_t)((uint8_t) entry.data[5]) << 40
- | (uint64_t)((uint8_t) entry.data[6]) << 48 | (uint64_t)((uint8_t) entry.data[7]) << 56;
- if (bigEndian)
- {
- data = bswap_64(data);
- }
- registryEntry->data = data;
- delete[] entry.data;
- }
-
- return registryEntry;
- }
-
- static std::unique_ptr adaptMultiLineEntry(
- const preg::PregEntry &entry, model::registry::RegistryEntryType type)
- {
- auto registryEntry = std::make_unique>();
- registryEntry->key = entry.key.c_str();
- registryEntry->type = type;
- registryEntry->value = entry.value.c_str();
- if (entry.data)
- {
- size_t size = entry.size - 2 > 0 ? entry.size - 2 : entry.size;
- void *pt = entry.data;
- size_t requiredSize = entry.size;
- const char16_t *data = reinterpret_cast(
- std::align(alignof(char16_t), sizeof(char), pt, requiredSize));
- std::vector> list;
- std::vector current;
- qWarning() << "Data: "
- << QString::fromUtf16(reinterpret_cast(
- std::align(alignof(char16_t), sizeof(char), pt, requiredSize)),
- size / 2)
- << " size: " << size;
- for (size_t i = 0; i < size / 2; ++i)
- {
- current.push_back(data[i]);
- if (data[i] == 0)
- {
- qWarning() << current << " split at: " << i;
- list.emplace_back(current);
- current.clear();
- }
- }
- for (const auto &element : list)
- {
- registryEntry->data.push_back(QString::fromUtf16(element.data()));
- }
- delete[] entry.data;
- }
-
- return registryEntry;
- }
-
public:
- static std::unique_ptr create(const preg::PregEntry &entry)
+ static void addInstruction(pol::PolicyTree &tree,
+ const std::unique_ptr &entry)
{
- switch (entry.type)
- {
- case preg::REG_BINARY: {
- return adaptCharEntry(entry, model::registry::REG_BINARY);
- }
- break;
+ pol::PolicyInstruction instruction;
- case preg::REG_DWORD_LITTLE_ENDIAN: {
- return adaptUInt32Entry(entry, model::registry::REG_DWORD);
- }
- break;
+ auto key = entry->key.toStdString();
+ auto value = entry->value.toStdString();
- case preg::REG_DWORD_BIG_ENDIAN: {
- return adaptUInt32Entry(entry, model::registry::REG_DWORD_BIG_ENDIAN, true);
+ if (tree.find(key) == tree.end()) {
+ tree[key] = {};
+ }
+ if (tree[key].find(value) == tree[key].end()) {
+ tree[key][value] = {};
}
- break;
- case preg::REG_EXPAND_SZ: {
- return adaptCharEntry(entry, model::registry::REG_EXPAND_SZ);
+ switch (entry->type) {
+ case model::registry::RegistryEntryType::REG_SZ: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_SZ;
+ instruction.data = tmp->data.toStdString();
+ break;
}
- break;
-
- case preg::REG_LINK: {
- return adaptCharEntry(entry, model::registry::REG_BINARY);
- }
- break;
-
- case preg::REG_MULTI_SZ: {
- return adaptMultiLineEntry(entry, model::registry::REG_MULTI_SZ);
- }
- break;
-
- case preg::REG_NONE: {
- return adaptCharEntry(entry, model::registry::REG_BINARY);
- }
- break;
-
- case preg::REG_QWORD: {
- return adaptUInt64Entry(entry, model::registry::REG_QWORD, true);
- }
- break;
-
- case preg::REG_QWORD_LITTLE_ENDIAN: {
- return adaptUInt64Entry(entry, model::registry::REG_QWORD);
- }
- break;
-
- case preg::REG_SZ: {
- return adaptCharEntry(entry, model::registry::REG_SZ);
- }
- break;
-
- default: {
- qWarning() << "Unrecognized data type detected! " << entry.type;
- delete[] entry.data;
- }
- break;
- };
-
- return nullptr;
- }
-};
-
-class PregEntryAdapter
-{
-public:
- static preg::PregEntry create(const std::unique_ptr &entry)
- {
- auto result = preg::PregEntry();
- result.key = entry->key.toStdString();
- result.value = entry->value.toStdString();
- result.type = entry->type;
-
- switch (entry->type)
- {
- case REG_BINARY:
- case REG_EXPAND_SZ:
- case REG_SZ: {
- auto binaryEntry = static_cast *>(entry.get());
- auto sixteenBitString = binaryEntry->data.toStdU16String();
- size_t bufferSize = sixteenBitString.size() * sizeof(char16_t);
- char *stringData = new char[bufferSize + 2];
- memcpy(stringData, sixteenBitString.c_str(), bufferSize);
- stringData[bufferSize] = '\0';
- stringData[bufferSize + 1] = '\0';
- result.data = stringData;
- result.size = bufferSize + 2;
- }
- break;
- case REG_DWORD:
- case REG_DWORD_BIG_ENDIAN: {
- auto uint32Entry = static_cast *>(entry.get());
- result.size = 4;
- size_t bufferSize = sizeof(uint32_t);
- char *stringData = new char[bufferSize];
- stringData[0] = (uint8_t)((uint8_t *) (&uint32Entry->data))[0];
- stringData[1] = (uint8_t)((uint8_t *) (&uint32Entry->data))[1];
- stringData[2] = (uint8_t)((uint8_t *) (&uint32Entry->data))[2];
- stringData[3] = (uint8_t)((uint8_t *) (&uint32Entry->data))[3];
-
- result.data = stringData;
- }
- break;
- case REG_QWORD: {
- auto uint64Entry = static_cast *>(entry.get());
- result.size = 8;
- size_t bufferSize = sizeof(uint64_t);
- char *stringData = new char[bufferSize];
- stringData[0] = (uint8_t)((uint8_t *) (&uint64Entry->data))[0];
- stringData[1] = (uint8_t)((uint8_t *) (&uint64Entry->data))[1];
- stringData[2] = (uint8_t)((uint8_t *) (&uint64Entry->data))[2];
- stringData[3] = (uint8_t)((uint8_t *) (&uint64Entry->data))[3];
- stringData[4] = (uint8_t)((uint8_t *) (&uint64Entry->data))[4];
- stringData[5] = (uint8_t)((uint8_t *) (&uint64Entry->data))[5];
- stringData[6] = (uint8_t)((uint8_t *) (&uint64Entry->data))[6];
- stringData[7] = (uint8_t)((uint8_t *) (&uint64Entry->data))[7];
- result.data = stringData;
- }
- break;
- case REG_MULTI_SZ: {
- auto binaryEntry = static_cast *>(entry.get());
- QByteArray byteArray;
- for (const QString &str : binaryEntry->data)
- {
- auto sixteenBitString = str.toStdU16String();
- size_t size = sixteenBitString.size() * sizeof(char16_t);
- byteArray.append(reinterpret_cast(sixteenBitString.c_str()), size);
- byteArray.append(2, '\0');
- }
- if (byteArray.size() == 0)
- {
- byteArray.append(4, '\0');
- }
- else
- {
- byteArray.append(2, '\0');
- }
- char *stringData = new char[byteArray.size()];
- memcpy(stringData, byteArray, byteArray.size());
- result.data = stringData;
- result.size = byteArray.size();
- }
- break;
- default:
+ case model::registry::RegistryEntryType::REG_EXPAND_SZ: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_EXPAND_SZ;
+ instruction.data = tmp->data.toStdString();
break;
}
- return result;
+ case model::registry::RegistryEntryType::REG_BINARY: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_BINARY;
+
+ auto tmp2 = tmp->data.toStdString();
+
+ std::vector data;
+ data.resize(tmp->data.size());
+ memcpy(data.data(), tmp2.data(), tmp2.size());
+ instruction.data = std::move(data);
+ break;
+ }
+
+ case model::registry::RegistryEntryType::REG_MULTI_SZ: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_MULTI_SZ;
+ std::vector data;
+ data.reserve(tmp->data.size());
+ for (const auto &str : tmp->data) {
+ data.push_back(str.toStdString());
+ }
+ instruction.data = std::move(data);
+ break;
+ }
+
+ case model::registry::RegistryEntryType::REG_DWORD: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_DWORD_LITTLE_ENDIAN;
+ instruction.data = static_cast(tmp->data);
+ break;
+ }
+
+ case model::registry::RegistryEntryType::REG_DWORD_BIG_ENDIAN: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_DWORD_BIG_ENDIAN;
+ instruction.data = static_cast(tmp->data);
+ break;
+ }
+ case model::registry::RegistryEntryType::REG_QWORD: {
+ auto tmp = static_cast *>(entry.get());
+ instruction.type = pol::PolicyRegType::REG_QWORD_LITTLE_ENDIAN;
+ instruction.data = static_cast(tmp->data);
+ break;
+ }
+ default: {
+ qWarning() << "Unrecognized data type `REG_NONE` detected! ";
+ return;
+ }
+ }
+
+ tree[key][value].emplace_back(instruction);
+ }
+
+ static std::unique_ptr
+ create(const pol::PolicyInstruction &entry, const std::string &key, const std::string &value)
+ {
+ switch (entry.type) {
+ case pol::PolicyRegType::REG_SZ: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_SZ;
+ registryEntry->data = QString::fromStdString(std::get(entry.data));
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_EXPAND_SZ: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_EXPAND_SZ;
+ registryEntry->data = QString::fromStdString(std::get(entry.data));
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_BINARY: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_BINARY;
+ auto &data = std::get>(entry.data);
+ registryEntry->data = QString::fromStdString(
+ { reinterpret_cast(data.data()), data.size() });
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_DWORD_LITTLE_ENDIAN: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_DWORD;
+ registryEntry->data = std::get(entry.data);
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_DWORD_BIG_ENDIAN: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_DWORD_BIG_ENDIAN;
+ registryEntry->data = std::get(entry.data);
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_LINK: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_BINARY;
+
+ auto &data = registryEntry->data =
+ QString::fromStdString(std::get(entry.data));
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_MULTI_SZ: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_MULTI_SZ;
+
+ auto &data = std::get>(entry.data);
+ registryEntry->data.reserve(data.size());
+ for (const auto &datum : data) {
+ registryEntry->data.append(QString::fromStdString(datum));
+ }
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_QWORD_BIG_ENDIAN:
+ case pol::PolicyRegType::REG_QWORD_LITTLE_ENDIAN: {
+ auto registryEntry = std::make_unique>();
+
+ registryEntry->key = QString::fromStdString(key);
+ registryEntry->value = QString::fromStdString(value);
+ registryEntry->type = model::registry::RegistryEntryType::REG_QWORD;
+ registryEntry->data = std::get(entry.data);
+
+ return registryEntry;
+ }
+ case pol::PolicyRegType::REG_RESOURCE_LIST:
+ case pol::PolicyRegType::REG_FULL_RESOURCE_DESCRIPTOR:
+ case pol::PolicyRegType::REG_RESOURCE_REQUIREMENTS_LIST:
+ default:
+ case pol::PolicyRegType::REG_NONE:
+ qWarning() << "Unrecognized data type detected! " << static_cast(entry.type);
+ return nullptr;
+ }
}
};
-PolFormat::PolFormat()
- : RegistryFileFormat("pol")
-{}
+PolFormat::PolFormat() : RegistryFileFormat("pol") { }
bool PolFormat::read(std::istream &input, io::RegistryFile *file)
{
auto registry = std::make_shared();
- try
- {
- auto parser = std::make_unique(input);
+ auto parser = pol::createPregParser();
+ pol::PolicyFile result;
+ try {
+ result = parser->parse(input);
+ } catch (const std::exception &e) {
+ qWarning() << e.what();
+ return false;
+ }
- preg::PregEntry entry;
-
- while (auto entryPointer = parser->getNextEntry())
- {
- auto registryEntry = RegistryEntryAdapter::create(*entryPointer);
- if (registryEntry.get())
- {
- registry->registryEntries.push_back(std::move(registryEntry));
+ for (const auto &[key, record] : result.instructions) {
+ for (const auto &[value, array] : record) {
+ for(const auto &entry : array) {
+ auto registryEntry = RegistryEntryAdapter::create(entry, key, value);
+ if (registryEntry.get()) {
+ registry->registryEntries.push_back(std::move(registryEntry));
+ }
}
}
}
- catch (preg::InvalidMagic &e)
- {
- setErrorString(e.what());
- return false;
- }
- catch (preg::InvalidVersion &e)
- {
- setErrorString(e.what());
- return false;
- }
file->setRegistry(registry);
@@ -342,34 +258,17 @@ bool PolFormat::read(std::istream &input, io::RegistryFile *file)
bool PolFormat::write(std::ostream &output, io::RegistryFile *file)
{
- auto writer = std::make_unique(&output);
+ auto writer = pol::createPregParser();
+ auto result = pol::PolicyFile();
- try
- {
- for (const auto &entry : file->getRegistry()->registryEntries)
- {
- auto pregEntry = PregEntryAdapter::create(entry);
- writer->addEntry(pregEntry);
-
- switch (pregEntry.type)
- {
- case REG_DWORD:
- case REG_DWORD_BIG_ENDIAN:
- case REG_QWORD:
- case REG_BINARY:
- case REG_EXPAND_SZ:
- case REG_MULTI_SZ:
- case REG_SZ: {
- delete[] pregEntry.data;
- }
- default:
- break;
- }
- }
+ for (const auto &entry : file->getRegistry()->registryEntries) {
+ RegistryEntryAdapter::addInstruction(result.instructions, entry);
}
- catch (std::exception &e)
- {
- setErrorString(e.what());
+
+ try {
+ writer->write(output, result);
+ } catch (const std::exception &e) {
+ qWarning() << e.what();
return false;
}
diff --git a/src/plugins/pol/pregdata.cpp b/src/plugins/pol/pregdata.cpp
deleted file mode 100644
index 3dff0f7..0000000
--- a/src/plugins/pol/pregdata.cpp
+++ /dev/null
@@ -1,144 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#include "pregdata.h"
-
-namespace preg {
-
-std::string regtype2str(uint32_t ®type) {
- std::string result = "UNKNOWN";
-
- switch (regtype) {
- case REG_NONE: {
- result = "REG_NONE";
- break;
- }
- case REG_SZ: {
- result = "REG_SZ";
- break;
- }
- case REG_EXPAND_SZ: {
- result = "REG_EXPAND_SZ";
- break;
- }
- case REG_BINARY: {
- result = "REG_BINARY";
- break;
- }
- case REG_DWORD_LITTLE_ENDIAN: {
- result = "REG_DWORD_LITTLE_ENDIAN";
- break;
- }
- case REG_DWORD_BIG_ENDIAN: {
- result = "REG_DWORD_BIG_ENDIAN";
- break;
- }
- case REG_LINK: {
- result = "REG_LINK";
- break;
- }
- case REG_MULTI_SZ: {
- result = "REG_MULTI_SZ";
- break;
- }
- case REG_RESOURCE_LIST: {
- result = "REG_RESOURCE_LIST";
- break;
- }
- case REG_FULL_RESOURCE_DESCRIPTOR: {
- result = "REG_FULL_RESOURCE_DESCRIPTOR";
- break;
- }
- case REG_RESOURCE_REQUIREMENTS_LIST: {
- result = "REG_RESOURCE_REQUIREMENTS_LIST";
- break;
- }
- case REG_QWORD: {
- result = "REG_QWORD";
- break;
- }
- case REG_QWORD_LITTLE_ENDIAN: {
- result = "REG_QWORD_LITTLE_ENDIAN";
- break;
- }
- default: {
- result = "UNKNOWN";
- break;
- }
- } /* switch (regtype) */
-
- return result;
-} /* std::string regtype2str(uint16_t ®type) */
-
-uint32_t str2regtype(std::string ®type) {
- uint32_t result = 0;
-
- if ("REG_NONE" == regtype) {
- result = REG_NONE;
- }
- if ("REG_SZ" == regtype) {
- result = REG_SZ;
- }
- if ("REG_EXPAND_SZ" == regtype) {
- result = REG_EXPAND_SZ;
- }
- if ("REG_BINARY" == regtype) {
- result = REG_BINARY;
- }
- if ("REG_DWORD_LITTLE_ENDIAN" == regtype || "REG_DWORD" == regtype) {
- result = REG_DWORD_LITTLE_ENDIAN;
- }
- if ("REG_DWORD_BIG_ENDIAN" == regtype) {
- result = REG_DWORD_BIG_ENDIAN;
- }
- if ("REG_LINK" == regtype) {
- result = REG_LINK;
- }
- if ("REG_MULTI_SZ" == regtype) {
- result = REG_MULTI_SZ;
- }
- if ("REG_RESOURCE_LIST" == regtype) {
- result = REG_RESOURCE_LIST;
- }
- if ("REG_FULL_RESOURCE_DESCRIPTOR" == regtype) {
- result = REG_FULL_RESOURCE_DESCRIPTOR;
- }
- if ("REG_RESOURCE_REQUIREMENTS_LIST" == regtype) {
- result = REG_RESOURCE_REQUIREMENTS_LIST;
- }
- if ("REG_QWORD" == regtype) {
- result = REG_QWORD;
- }
- if ("REG_QWORD_LITTLE_ENDIAN" == regtype) {
- result = REG_QWORD_LITTLE_ENDIAN;
- }
-
- return result;
-} /* uint16_t str2regtype(std::string ®type) */
-
-const char *InvalidMagic::what() const throw() {
- return "Invalid PReg file magic value";
-}
-
-const char *InvalidVersion::what() const throw() {
- return "Invalid PReg file version";
-}
-
-}
diff --git a/src/plugins/pol/pregdata.h b/src/plugins/pol/pregdata.h
deleted file mode 100644
index 45c6baf..0000000
--- a/src/plugins/pol/pregdata.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#ifndef GPUI_PREG_DATA_H
-#define GPUI_PREG_DATA_H
-
-#include
-#include
-#include
-#include
-
-namespace preg {
-
-/* Same as REG_BINARY */
-const uint32_t REG_NONE = 0;
-
-/* Null-terminated-string */
-const uint32_t REG_SZ = 1;
-
-/* A null-terminated UTF16-LE or ANSI string that contains unexpanded
- * references to environment variables. */
-const uint32_t REG_EXPAND_SZ = 2;
-
-/* Any kind of binary data */
-const uint32_t REG_BINARY = 3;
-
-/* 32-bit number */
-const uint32_t REG_DWORD_LITTLE_ENDIAN = 4;
-
-/* 32-bit number in NBO format */
-const uint32_t REG_DWORD_BIG_ENDIAN = 5;
-
-/* A null-terminated Unicode string that contains the target path of a
- * symbolic link. */
-const uint32_t REG_LINK = 6;
-
-/* Sequence of null-terminated strings terminated by null-terminator */
-const uint32_t REG_MULTI_SZ = 7;
-const uint32_t REG_RESOURCE_LIST = 8;
-const uint32_t REG_FULL_RESOURCE_DESCRIPTOR = 9;
-const uint32_t REG_RESOURCE_REQUIREMENTS_LIST = 10;
-
-/* 64-bit number */
-const uint32_t REG_QWORD = 11;
-const uint32_t REG_QWORD_LITTLE_ENDIAN = 12;
-
-struct PregEntry
-{
- std::string key {};
- std::string value {};
- uint32_t type = REG_NONE;
- uint32_t size = 0;
- char *data = nullptr;
-};
-
-class InvalidMagic : public std::exception {
-public:
- virtual const char *what() const throw();
-};
-
-class InvalidVersion : public std::exception {
-public:
- virtual const char *what() const throw();
-};
-
-/*!
- * \brief Convert PReg type value from DWORD into string representation.
- * May be useful when operating on PReg files from GUI.
- */
-std::string regtype2str(uint32_t ®type);
-
-/*!
- * \brief Convert PReg type string representation into DWORD.
- * May be useful when serializing data.
- */
-uint32_t str2regtype(std::string ®type);
-
-}
-
-#endif // GPUI_PREG_DATA_H
diff --git a/src/plugins/pol/pregparser.cpp b/src/plugins/pol/pregparser.cpp
deleted file mode 100644
index cfda73c..0000000
--- a/src/plugins/pol/pregparser.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#include "pregparser.h"
-
-#include "iconvwrapper.h"
-
-#include
-
-namespace preg {
-
-namespace {
-
- bool isRangeStart(char symbol) {
- if ('[' == symbol) {
- return true;
- }
- return false;
- }
-
- bool isRangeEnd(char symbol) {
- if (']' == symbol) {
- return true;
- }
- return false;
- }
-
- bool isPregEntrySeparator(char symbol) {
- if (';' == symbol) {
- return true;
- }
- return false;
- }
-
-}
-
-uint16_t buffer2uint16(const char *type_buffer) {
- uint16_t num =
- static_cast(static_cast(type_buffer[1]) << 8 |
- static_cast(type_buffer[0]));
- return num;
-}
-
-uint32_t buffer2uint32(const char *type_buffer) {
- uint32_t num =
- static_cast(static_cast(type_buffer[3]) << 24 |
- static_cast(type_buffer[2]) << 16 |
- static_cast(type_buffer[1]) << 8 |
- static_cast(type_buffer[0]));
- return num;
-}
-
-uint32_t parse_type(const char *type_buffer) {
- return buffer2uint32(type_buffer);
-}
-
-PregParser::PregParser(std::istream &input)
- : polfile(&input)
-{
- this->loadRegpol();
-}
-
-void PregParser::loadRegpol() {
- if (this->polfile->good()) {
- this->polfile->seekg(0, std::ios::end); /* Go to the end of file */
- this->rawFileSize = this->polfile->tellg(); /* Get file length */
-
- this->polfile->seekg(0, std::ios::beg); /* Set file position to beginning */
-
- this->readHeader();
- this->readVersion();
- }
-}
-
-void PregParser::readHeader() {
- if (this->polfile->good() && 4 < this->rawFileSize) {
- this->polfile->seekg(0, std::ios::beg); /* Set file position to beginning */
- this->polfile->read(this->header, 4); /* Read first 4 bytes */
- }
- this->checkHeader();
-}
-
-void PregParser::readVersion() {
- if (this->polfile->good() && 8 < this->rawFileSize) {
- /* Read bytes 4-7 of the file */
- this->polfile->seekg(4, std::ios::beg);
- this->polfile->read(this->version, 4);
- }
- this->checkVersion();
-}
-
-void PregParser::checkHeader() {
- if ('P' == this->header[0] && 'R' == this->header[1] &&
- 'e' == this->header[2] && 'g' == this->header[3]) {
- } else {
- throw InvalidMagic();
- }
-}
-
-void PregParser::checkVersion() {
- if (1 == this->version[0] && 0 == this->version[1] &&
- 0 == this->version[2] && 0 == this->version[3]) {
- } else {
- throw InvalidVersion();
- }
-}
-
-char PregParser::readByte(size_t absFileStartOffset) {
- char symbol = 0;
- if (absFileStartOffset < this->rawFileSize) {
- this->polfile->seekg(absFileStartOffset, std::ios::beg);
- this->polfile->read(&symbol, 1);
- }
- // FIXME: Else throw exception.
- return symbol;
-}
-
-size_t PregParser::seekNextSeparator(size_t absFileStartOffset) {
- size_t end_offset = absFileStartOffset;
- if (absFileStartOffset < this->rawFileSize) {
- char sym_buf;
- for (size_t abs_file_offset = absFileStartOffset;
- abs_file_offset <= this->rawFileSize; abs_file_offset++) {
- sym_buf = this->readByte(abs_file_offset);
- if (isRangeStart(sym_buf) || isPregEntrySeparator(sym_buf) ||
- isRangeEnd(sym_buf) ||
- abs_file_offset == this->rawFileSize) {
-
- end_offset = abs_file_offset;
- break;
- }
- }
- } else {
- end_offset = this->rawFileSize;
- }
- return end_offset;
-}
-
-std::unique_ptr PregParser::getNextKeyEntry() {
- auto entry = std::make_unique();
- entry->startOffset = this->nextEntryStartOffset;
- entry->endOffset = this->nextEntryStartOffset;
-
- /* Check if we're not at the end of file */
- if (this->nextEntryStartOffset < this->rawFileSize) {
- char range_init = this->readByte(this->nextEntryStartOffset);
-
- /* Check that we're at the beginning of the entry we
- * want to parse */
- if (isRangeStart(range_init)) {
- char sym_buf;
-
- /* Read file byte by byte seeking for the end of entry */
- for (size_t offset = this->nextEntryStartOffset + 1;
- offset <= this->rawFileSize; offset++) {
- sym_buf = this->readByte(offset);
-
- /* Build and return the entry if we're found its end */
- if (isRangeEnd(sym_buf)) {
- entry->endOffset = offset + 2;
- this->nextEntryStartOffset = offset + 2;
- return entry;
- }
- }
- }
- } else {
- return nullptr;
- }
-
- return entry;
-}
-
-std::unique_ptr PregParser::readEntry(KeyEntry kentry) {
- std::unique_ptr appentry = std::make_unique();
- std::vector results = this->splitEntry(kentry);
- gpui::IconvWrapper iwrapper("UTF-16LE", "UTF-8");
-
- std::string vn = iwrapper.convert(results.at(0));
- std::string kn = iwrapper.convert(results.at(1));
- appentry->key = std::string(vn, 0, vn.length() - 1);
- appentry->value = std::string(kn, 0, kn.length() - 1);
- appentry->type = parse_type(results.at(2).c_str());
- appentry->size = buffer2uint32(results.at(3).c_str());
-
- if (results.size() >= 5 && results.at(4).size() > 0)
- {
- char* dataDouble = new char[appentry->size];
- memcpy(dataDouble, &results.at(4)[0], appentry->size);
- appentry->data = dataDouble;
- } else {
- appentry->data = nullptr;
- }
-
- return appentry;
-}
-
-std::unique_ptr PregParser::getNextEntry() {
- auto keyEntry = this->getNextKeyEntry();
- if (keyEntry)
- {
- return this->readEntry(*keyEntry);
- }
-
- return nullptr;
-}
-
-std::string PregParser::stripSquareBraces(KeyEntry kentry) {
- size_t entry_size = (kentry.endOffset - 2) - (kentry.startOffset + 2);
- char *entry_buffer = new char[entry_size];
- this->polfile->seekg((kentry.startOffset + 2));
- this->polfile->read(entry_buffer, entry_size);
- std::string bufstring(entry_buffer, entry_size);
- delete[] entry_buffer;
- return bufstring;
-}
-
-std::vector
-PregParser::splitEntry(KeyEntry kentry) {
- std::string bufstring = this->stripSquareBraces(kentry);
- const char *raw_buffer = bufstring.c_str();
- std::vector results;
-
- size_t offset = 0;
- for (size_t i = 0; i <= bufstring.length(); i++) {
- if (isPregEntrySeparator(raw_buffer[i]) || i == bufstring.length()) {
- size_t split_length = i - offset;
- std::string buf = std::string(bufstring, offset, split_length);
- results.push_back(buf);
- offset = i + 2; // Skip separator
- i++;
- }
- }
-
- return results;
-}
-
-}
diff --git a/src/plugins/pol/pregparser.h b/src/plugins/pol/pregparser.h
deleted file mode 100644
index 3b0a849..0000000
--- a/src/plugins/pol/pregparser.h
+++ /dev/null
@@ -1,96 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#ifndef GPUI_PREG_PARSER_H
-#define GPUI_PREG_PARSER_H
-
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "pregdata.h"
-
-namespace preg {
-
- /*!
- * \brief key_entry This structure contains offsets for PReg file pointing to '[' and ']'
- * characters. It is internal to preg_parser.
- */
- struct KeyEntry {
- size_t startOffset;
- size_t endOffset;
- };
-
- uint16_t buffer2uint16(const char *type_buffer);
- uint32_t buffer2uint32(const char *type_buffer);
- uint32_t parse_type(const char *type_buffer);
-
- class PregParser {
- private:
- std::istream* polfile = nullptr;
-
- std::string filePath = "";
-
- size_t rawFileSize = 0;
-
- char header[4] { 'P', 'R', 'e', 'g' };
-
- char version[4] { '\x01', '\x00', '\x00', '\x00' };
-
- size_t nextEntryStartOffset = 8;
-
- public:
- explicit PregParser(std::istream& input);
-
- std::unique_ptr getNextEntry();
-
- protected:
- void loadRegpol();
-
- void readHeader();
- void readVersion();
-
- void checkHeader();
- void checkVersion();
-
- char readByte(size_t absFileStartOffset);
-
- size_t seekNextSeparator(size_t absFileStartOffset);
-
- std::string stripSquareBraces(KeyEntry kentry);
-
- std::unique_ptr getNextKeyEntry();
-
- std::unique_ptr readEntry(KeyEntry kentry);
- std::vector splitEntry(KeyEntry kentry);
-
- private:
- PregParser(const PregParser&) = delete; // copy ctor
- PregParser(PregParser&&) = delete; // move ctor
- PregParser& operator=(const PregParser&) = delete; // copy assignment
- PregParser& operator=(PregParser&&) = delete; // move assignment
- };
-
-}
-
-#endif // GPUI_PREG_PARSER_H
diff --git a/src/plugins/pol/pregwriter.cpp b/src/plugins/pol/pregwriter.cpp
deleted file mode 100644
index c77ebf9..0000000
--- a/src/plugins/pol/pregwriter.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#include "pregwriter.h"
-#include "iconvwrapper.h"
-
-namespace preg {
-
-PregWriter::PregWriter(std::ostream *initial_preg_file) {
- this->preg_file = initial_preg_file;
- this->preg_file->write(this->preg_magic, 4);
- this->preg_file->write(this->preg_version, 4);
-}
-
-PregWriter::~PregWriter() {
-}
-
-void PregWriter::addEntry(PregEntry &pentry) {
- char null_terminator[2]{ '\x00', '\x00' };
- char separator[2]{ ';', '\x00' };
- char range_start[2]{ '[', '\x00' };
- char range_end[2]{ ']', '\x00' };
-
- gpui::IconvWrapper iw("UTF-8", "UTF-16LE");
-
- std::string keyName = iw.convert(pentry.key);
- std::string valueName = iw.convert(pentry.value);
-
- const char *key = keyName.c_str();
- size_t key_size = keyName.length() * sizeof(char);
-
- const char *value = valueName.c_str();
- size_t value_size = valueName.length() * sizeof(char);
-
- char type[2];
- type[0] = pentry.type & 0xFF;
- type[1] = pentry.type >> 8;
-
- char size[4];
- size[0] = pentry.size & 0xFF;
- size[1] = pentry.size >> 8;
- size[2] = pentry.size >> 16;
- size[3] = pentry.size >> 24;
-
- this->preg_file->write(range_start, 2);
- this->preg_file->write(key, key_size);
- this->preg_file->write(null_terminator, 2);
- this->preg_file->write(separator, 2);
- this->preg_file->write(value, value_size);
- this->preg_file->write(null_terminator, 2);
- this->preg_file->write(separator, 2);
- this->preg_file->write(type, 2);
- this->preg_file->write(null_terminator, 2);
- this->preg_file->write(separator, 2);
- this->preg_file->write(size, 4);
- this->preg_file->write(separator, 2);
- this->preg_file->write(pentry.data, pentry.size);
- this->preg_file->write(range_end, 2);
-}
-
-}
diff --git a/src/plugins/pol/pregwriter.h b/src/plugins/pol/pregwriter.h
deleted file mode 100644
index 7fa8e4d..0000000
--- a/src/plugins/pol/pregwriter.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/***********************************************************************************************************************
-**
-** Copyright (C) 2021 BaseALT Ltd.
-**
-** This program is free software; you can redistribute it and/or
-** modify it under the terms of the GNU General Public License
-** as published by the Free Software Foundation; either version 2
-** of the License, or (at your option) any later version.
-**
-** This program is distributed in the hope that it will be useful,
-** but WITHOUT ANY WARRANTY; without even the implied warranty of
-** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-** GNU General Public License for more details.
-**
-** You should have received a copy of the GNU General Public License
-** along with this program; if not, write to the Free Software
-** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-**
-***********************************************************************************************************************/
-
-#ifndef GPUI_PREG_WRITER_H
-#define GPUI_PREG_WRITER_H
-
-#include
-#include
-#include
-#include
-
-#include "pregdata.h"
-
-namespace preg {
-
-class PregWriter {
-private:
- std::ostream* preg_file = nullptr;
- char preg_magic[4] { 'P', 'R', 'e', 'g' };
- char preg_version[4] { '\x01', '\x00', '\x00', '\x00' };
-
-public:
- PregWriter(std::ostream *preg_file);
- ~PregWriter();
-
- void addEntry(preg::PregEntry &pentry);
-
-private:
- void preg_type2buf(uint16_t type);
-
-private:
- PregWriter(const PregWriter&) = delete; // copy ctor
- PregWriter(PregWriter&&) = delete; // move ctor
- PregWriter& operator=(const PregWriter&) = delete; // copy assignment
- PregWriter& operator=(PregWriter&&) = delete; // move assignment
-};
-
-}
-
-#endif // GPUI_PREG_WRITER_H
-
diff --git a/tests/auto/plugins/pol/CMakeLists.txt b/tests/auto/plugins/pol/CMakeLists.txt
index 364d62c..6188030 100644
--- a/tests/auto/plugins/pol/CMakeLists.txt
+++ b/tests/auto/plugins/pol/CMakeLists.txt
@@ -1,4 +1,7 @@
qt5_wrap_cpp(MOC_SOURCES poltest.h)
+
+set(CMAKE_CXX_STANDARD 17)
+
add_executable(poltest poltest.cpp ${MOC_SOURCES})
target_link_libraries(poltest ${GPUI_LIBRARIES} pol-plugin Qt5::Core Qt5::Test)
add_gpui_test(plugins.poltest poltest)
diff --git a/tests/auto/plugins/pol/generatecase.h b/tests/auto/plugins/pol/generatecase.h
new file mode 100644
index 0000000..e4f4e0d
--- /dev/null
+++ b/tests/auto/plugins/pol/generatecase.h
@@ -0,0 +1,179 @@
+/*
+ * libparsepol - POL Registry file parser
+ *
+ * Copyright (C) 2024 BaseALT Ltd.
+ * Copyright (C) 2020 Korney Yakovlevich
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "../../../../src/plugins/pol/encoding.h"
+#include "../../../../src/plugins/pol/parser.h"
+
+std::string generateRandomKey(size_t length, std::mt19937 &gen)
+{
+ std::string key;
+ key.resize(length);
+ for (size_t i = 0; i < length; ++i) {
+ // [0x20-\x5B] | [\x5D-\x7E]
+ key[i] = (gen() % 0x5E) + 0x20;
+ key[i] = key[i] >= 0x5c ? key[i] + 1 : key[i];
+ }
+ return key;
+}
+
+std::string generateRandomKeypath(std::mt19937 &gen)
+{
+ std::string keyPath;
+ keyPath += generateRandomKey((gen() % 99) + 1, gen);
+
+ while ((rand() % 5) >= 3) {
+ keyPath += '\\';
+ keyPath += generateRandomKey((gen() % 99) + 1, gen);
+ }
+
+ return keyPath;
+}
+
+std::string generateRandomValue(std::mt19937 &gen)
+{
+ std::string value;
+ value.resize((gen() % 99) + 1);
+ for (size_t i = 0; i < value.size(); ++i) {
+ value[i] = (gen() % 0x5E) + 0x20;
+ }
+ return value;
+}
+
+pol::PolicyRegType generateRandomType(std::mt19937 &gen)
+{
+ switch (rand() % 7) {
+ case 0:
+ return pol::PolicyRegType::REG_BINARY;
+ case 1:
+ return pol::PolicyRegType::REG_DWORD_LITTLE_ENDIAN;
+ case 2:
+ return pol::PolicyRegType::REG_DWORD_BIG_ENDIAN;
+ case 3:
+ return pol::PolicyRegType::REG_QWORD_LITTLE_ENDIAN;
+ case 4:
+ return pol::PolicyRegType::REG_QWORD_BIG_ENDIAN;
+ case 5:
+ return pol::PolicyRegType::REG_SZ;
+ case 6:
+ return pol::PolicyRegType::REG_MULTI_SZ;
+ default:
+ break;
+ }
+ return pol::PolicyRegType::REG_BINARY;
+}
+
+pol::PolicyData generateRandomData(pol::PolicyRegType type, std::mt19937 &gen)
+{
+ iconv_t conv = iconv_open("UTF-8", "UTF-32LE");
+ if (conv == pol::ICONV_ERROR_DESCRIPTOR) {
+ throw std::runtime_error(
+ "LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Encountered with the inability to create an iconv descriptor.");
+ }
+
+ switch (type) {
+ case pol::PolicyRegType::REG_NONE:
+ throw std::runtime_error("LINE: " + std::to_string(__LINE__) + ", FILE: " + __FILE__
+ + ", Unexpected type REG_NONE.");
+ case pol::PolicyRegType::REG_SZ: {
+ std::basic_string data;
+ data.resize(rand() % 100);
+ for (size_t i = 0; i < data.size(); ++i) {
+ data[i] = (gen() % 0x5E) + 0x20;
+ }
+ auto result = pol::convert(data, conv);
+ iconv_close(conv);
+ return result;
+ }
+
+ case pol::PolicyRegType::REG_MULTI_SZ: {
+ std::vector data1;
+ size_t count = rand() % 100;
+ for (size_t i = 0; i < count; ++i) {
+ std::basic_string data;
+ data.resize((rand() % 100) + 1);
+ for (size_t i = 0; i < data.size(); ++i) {
+ data[i] = (gen() % 0x5E) + 0x20;
+ }
+ data1.push_back(pol::convert(data, conv));
+ }
+ iconv_close(conv);
+ return data1;
+ }
+
+ case pol::PolicyRegType::REG_BINARY: {
+ std::vector data;
+ size_t count = gen() % 100;
+ for (size_t i = 0; i < count; ++i) {
+ data.push_back((gen() % 255) + 1);
+ }
+ iconv_close(conv);
+ return data;
+ }
+
+ case pol::PolicyRegType::REG_DWORD_LITTLE_ENDIAN:
+ iconv_close(conv);
+ return uint32_t(rand() % 10'000'000);
+ case pol::PolicyRegType::REG_DWORD_BIG_ENDIAN:
+ iconv_close(conv);
+ return uint32_t(rand() % 10'000'000);
+ case pol::PolicyRegType::REG_QWORD_LITTLE_ENDIAN:
+ iconv_close(conv);
+ return uint64_t(rand() % 10'000'000);
+ case pol::PolicyRegType::REG_QWORD_BIG_ENDIAN:
+ iconv_close(conv);
+ return uint64_t(rand() % 10'000'000);
+ default:
+ iconv_close(conv);
+ return {};
+ }
+}
+
+pol::PolicyFile generateCase(size_t seed = -1)
+{
+ std::mt19937 gen;
+ std::uniform_int_distribution dist(0, 500);
+ pol::PolicyFile data;
+
+ if (seed == -1) {
+ std::random_device dev;
+ seed = dev();
+ gen.seed(seed);
+ } else {
+ gen.seed(seed);
+ }
+
+ // Generate case
+ size_t el = dist(gen);
+ for (size_t i = 0; i < el; i++) {
+ pol::PolicyInstruction instruction;
+ instruction.type = generateRandomType(gen);
+ instruction.data = generateRandomData(instruction.type, gen);
+ data.instructions[generateRandomKeypath(gen)][generateRandomValue(gen)] = { instruction };
+ }
+
+ return data;
+}
diff --git a/tests/auto/plugins/pol/poltest.cpp b/tests/auto/plugins/pol/poltest.cpp
index 9f3da4a..11cd5ce 100644
--- a/tests/auto/plugins/pol/poltest.cpp
+++ b/tests/auto/plugins/pol/poltest.cpp
@@ -19,47 +19,120 @@
***********************************************************************************************************************/
#include "poltest.h"
-
-#include "../../../../src/io/registryfile.h"
-#include "../../../../src/plugins/administrative_templates/registry/registry.h"
-#include "../../../../src/plugins/administrative_templates/registry/registryentry.h"
-#include "../../../../src/plugins/pol/polformat.h"
+#include "../../../../src/plugins/pol/binary.h"
+#include "../../../../src/plugins/pol/encoding.h"
+#include "../../../../src/plugins/pol/parser.h"
+#include "generatecase.h"
#include
#include
+#include
const std::string dataPath = "../../../data/";
-namespace tests
+namespace tests {
+
+void PolTest::endianness()
{
-void PolTest::read()
-{
- gpui::PolFormat format;
+ uint8_t num1 = 0x12;
+ QCOMPARE(pol::byteswap(num1), 0x12);
- std::ifstream file;
+ uint16_t num2 = 0x1234;
+ QCOMPARE(pol::byteswap(num2), 0x3412);
+ qDebug() << "byteswap: OK";
- file.open(dataPath + "example.pol", std::ifstream::in);
+ uint32_t num3 = 0x12345678;
+ QCOMPARE(pol::byteswap(num3), 0x78563412);
+ qDebug() << "byteswap: OK";
- if (file.good())
- {
- std::unique_ptr registry = std::make_unique