From 9b7c0a8ead64e947b5954936b2118f9d8b054d0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ya=C4=9F=C4=B1z=20Zengin?= Date: Tue, 2 Sep 2025 12:36:51 +0300 Subject: [PATCH] Updated Library Documentation (markdown) --- Library-Documentation.md | 612 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 612 insertions(+) diff --git a/Library-Documentation.md b/Library-Documentation.md index c46185a..433525f 100644 --- a/Library-Documentation.md +++ b/Library-Documentation.md @@ -1 +1,613 @@ +## libhelper library +It provides functions, classes and macros that will make your work easier when writing your string program, such as the name `libhelper`. + +--- + +### Helpful macros and variables +`libhelper` provides some macros and variables to make your work easier. + +```c++ +// File/directory modes +constexpr mode_t DEFAULT_FILE_PERMS = 0644; +constexpr mode_t DEFAULT_EXTENDED_FILE_PERMS = 0755; +constexpr mode_t DEFAULT_DIR_PERMS = 0755; + +// Boolean alternatives (is there anyone who will actually use it???) +constexpr int YES = 1; // YES = true +constexpr int NO = 0; // NO = false + +// Macros that can be useful for size conversions +#define KB(x) (x * 1024) // KB(8) = 8192 (8 * 1024) +#define MB(x) (KB(x) * 1024) // MB(4) = 4194304 (KB(4) * 1024) +#define GB(x) (MB(x) * 1024) // GB(1) = 1073741824 (MB(1) * 1024) + +// Conversion from bytes to other units +#define TO_KB(x) (x / 1024) // TO_KB(1024) = 1 +#define TO_MB(x) (TO_KB(x) / 1024) // TO_MB(2048) (2048 / 1024) +#define TO_GB(x) (TO_MB(x) / 1024) // TO_GB(1048576) (TO_MB(1048576) / 1024) + +// Macros to use for text decoration +#define STYLE_RESET "\033[0m" +#define BOLD "\033[1m" +#define FAINT "\033[2m" +#define ITALIC "\033[3m" +#define UNDERLINE "\033[4m" +#define BLINC "\033[5m" +#define FAST_BLINC "\033[6m" +#define STRIKE_THROUGHT "\033[9m" +#define NO_UNDERLINE "\033[24m" +#define NO_BLINC "\033[25m" +#define RED "\033[31m" +#define GREEN "\033[32m" +#define YELLOW "\033[33m" + +// If NO_C_TYPE_HANDLERS is defined, these macros are can't defined. +#ifndef NO_C_TYPE_HANDLERS +// ABORT(message), ex: ABORT("memory error!\n") +#define ABORT(msg) \ + do { \ + fprintf(stderr, "%s%sCRITICAL ERROR%s: %s\nAborting...\n", BOLD, RED, \ + STYLE_RESET, msg); \ + abort(); \ + } while (0) + +// ERROR(message, exit), ex: ERROR("an error occured.\n", 1) +#define ERROR(msg, code) \ + do { \ + fprintf(stderr, "%s%sERROR%s: %s", BOLD, RED, STYLE_RESET, msg); \ + exit(code); \ + } while (0) + +// WARNING(message), ex: WARNING("using default setting.\n") +#define WARNING(msg) \ + fprintf(stderr, "%s%sWARNING%s: %s", BOLD, YELLOW, STYLE_RESET, msg); + +// INFO(message), ex: INFO("operation ended.\n") +#define INFO(msg) \ + fprintf(stdout, "%s%sINFO%s: %s", BOLD, GREEN, STYLE_RESET, msg); +#endif // #ifndef NO_C_TYPE_HANDLERS + +// Common version string creator. +// Don't forget to define the BUILD*** macros. +#define MKVERSION(name) \ + char vinfo[512]; \ + sprintf(vinfo, \ + "%s %s [%s %s]\nBuildType: %s\nCMakeVersion: %s\nCompilerVersion: " \ + "%s\nBuildFlags: %s", \ + name, BUILD_VERSION, BUILD_DATE, BUILD_TIME, BUILD_TYPE, \ + BUILD_CMAKE_VERSION, BUILD_COMPILER_VERSION, BUILD_FLAGS); \ + return std::string(vinfo) +``` + +--- + +### Classes +`libhelper` provides three classes in total. One is for logging (used with macros), one is an error class created with `std::exception`, and the third is a garbage collector. + +--- + +#### Logging Class +A total of four logging levels are provided: information, warning, error, and abort (critical error). + +```c++ +enum LogLevels { + INFO = static_cast('I'), + WARNING = static_cast('W'), + ERROR = static_cast('E'), + ABORT = static_cast('A') +}; + +// It actually seemed more logical to use the numerical equivalents of logical letters instead of numbers like 1-2. +``` + +A class called `Logging` handles everything. However, logging directly using the class isn't practical. There are some macros for this: + +```c++ +#define LOG(level) \ + Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \ + Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__) +#define LOGN(name, level) \ + Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \ + name, __FILE__, __LINE__) +#define LOGNF(name, file, level) \ + Helper::Logger(level, file, name, __FILE__, __LINE__) + +#define LOG_IF(level, condition) \ + if (condition) \ + Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \ + Helper::LoggingProperties::NAME.data(), __FILE__, __LINE__) +#define LOGN_IF(name, level, condition) \ + if (condition) \ + Helper::Logger(level, __func__, Helper::LoggingProperties::FILE.data(), \ + name, __FILE__, __LINE__) +#define LOGNF_IF(name, file, level, condition) \ + if (condition) Helper::Logger(level, __func__, file, name, __FILE__, __LINE__) +``` + +There are some settings available for logging. These are stored in the `Helper::LoggingProperties` namespace. These are: `FILE` (`std::string_view`), `NAME` (`std::string_view`), `PRINT` (`bool`), `DISABLE` (`bool`). The default values are: + +```c++ +// Utilities.cpp + +namespace Helper { +namespace LoggingProperties { +std::string_view FILE = "last_logs.log", NAME = "main"; +bool PRINT = NO, DISABLE = NO; +} // namespace LoggingProperties +} // namespace Helper +``` + + - `PRINT` specifies whether the log will be printed to the screen. This can be useful for things like verbose logging. The default is `NO` (`false`). + - You can control logging with `DISABLE`. The default is `NO` (`false`). Setting it to true stops logging. No writing to the file. + - `FILE` is the file where the log content will be saved. By default, it's `last_logs.log`. It's created in your current directory. + - `NAME` is the name of the program that prints the log that will appear in the log. By default, it is `main`. + +You can change these settings directly or use the provided functions. + +```c++ +namespace Helper { +namespace LoggingProperties { +void set(std::string_view name, std::string_view file); +void setProgramName(std::string_view name); +void setLogFile(std::string_view file); +void setPrinting(int state); +void setLoggingState(int state); // Disable/enable logging + +void reset(); +} // namespace LoggingProperties +} // namespae Helper +``` + +It's pretty clear what the functions named `set***` do. But I'd still like to mention `reset()`. It restores default settings. +Now we can reinforce it with use cases. That would be good. + +```c++ +#include +#include + +int main(int argc, char** argv) { + Helper::LoggingProperties::set("pmt", "/storage/emulated/0/Dccuments/last_pmt_logs.log"); + + LOG(INFO) << "Hello World!" << std::endl; + LOG_IF(WARNING, argc < 2) << "No argument speficed!" << std::endl; + LOGN(argv[0], INFO) << "Hello World from " << argv[0] << " program!" << std::endl; + LOGNF(argv[0], "last_logs_test.log", INFO) << "LOGNF() test!!!" << std::endl; + LOGN_IF(argv[0], WARNING, argc < 2) << "No argument speficed! (test 2)" << std::endl; + LOGNF_IF(argv[0], "last_logs_test.log", ERROR, argc > 3) << "Too many argument!" << std::endl; + + std::cout << "Program complete!" << std::endl; + return 0; +} +``` + +--- + +#### Error Class +It is a throwable error class derived from `std::exception`. Thrown errors are also recorded in the logs. + +```c++ +#include +#include + +int main(int argc, char** argv) { + try { + if (argc < 2) + throw Helper::Error("No enoght argument!"); + } catch (Helper::Error &e) { + std::cerr << e.what() << std::endl; + return 1; + } + + return 0; +} +``` + +--- + +#### Garbage Collector Class +The garbage collector is there to free allocated memory (certain types) and close file pointers. In other words, it handles your work for you. It also has additional auxiliary functions. + +```c++ +namespace Helper { +class garbageCollector { +// Other definations... + +public: + ~garbageCollector(); + + void delAfterProgress(char *&_ptr); // Delete allocated char variables after function + void delAfterProgress(uint8_t *&_ptr); // Delete allocated uint8_t variables after funtion + void delFileAfterProgress(const std::string &path); // Delete input file after function + void closeAfterProgress(FILE *&_fp); // Close input file pointers after function + void closeAfterProgress(DIR *&_dp); // Close input directory pointers after function + void closeAfterProgress(int _fd); // Close input file descriptor after function + + // You can add whatever you want by using it multiple times +}; + +// Open input path with flags and add to integrity list. And return file descriptor. open() is emulated +[[nodiscard]] int openAndAddToCloseList(const std::string_view &path, + garbageCollector &collector, int flags, + mode_t mode = 0000); +// fopen() is emulated. +[[nodiscard]] FILE *openAndAddToCloseList(const std::string_view &path, + garbageCollector &collector, + const char *mode); +[[nodiscard]] DIR *openAndAddToCloseList(const std::string_view &path, + garbageCollector &collector); + +// You can need use returned values!!! Because these functions marked as nodiscard +} // namespace Helper +``` + +Usage example... +```c++ +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char** argv) { + Helper::garbageCollector collector; + + int fd1 = open("file.txt", O_TRUNC | O_CREAT, 0644); + collector.closeAfterProgress(fd1); // no need close() anymore + // You can do the same with FILE or DIR + // Do your file progresses... + + // Delete file.txt automaticly after program + collector.delFileAfterProgess("file.txt"); + + int fd2 = Helper::openAndAddToCloseList("file2.txt", collector, O_TRUNC, DEFAULT_FILE_PERMS); + // Do your file progresses... + // WARNING: It does not check whether the file is opened or not. + + DIR *dp = Helper::openAndAddToCloseList("dir1", collector); + // Do your directory progresses... + // WARNING: It does not check whether the directory is opened or not. + + auto *buffer = new char[4096]; // Allocate memory + collector.delAfterProgrss(buffer); + // You can do the same with uint8_t + + return 0; +} +``` + +--- + +#### Functions +`libhelper` provides many helper functions. Some of these throw `Helper::Error`. We'll cover each one with code examples. + +```c++ +#include +#include +#include + +int main(int argc, char** argv) { + /** + Checker functions - don't throw Helper::Error + + bool hasSuperUser(); + // Returns true if user id equals AID_ROOT. + // See srclib/libhelper/include/private/android_filesystem_config.h + + bool hasAdbPermissions(); + // Returns true if user id equals AID_SHELL. + // See srclib/libhelper/include/private/android_filesystem_config.h + + bool isExists(std::string_view entry); + // Returns true if entry exists (file or directory). + + bool fileIsExists(std::string_view file); + // Returns true if given file exists. + + bool directoryIsExists(std::string_view directory); + // Returns true if given directory exists. + + bool linkIsExists(std::string_view entry); + // Returns true if entry is symbolic or hard link. + + bool isLink(std::string_view entry); + // Returns true if entry is a symbolic link. + + bool isSymbolicLink(std::string_view entry); + // Alias of isLink(). + + bool isHardLink(std::string_view entry); + // Returns true if entry is a hard link. + + bool areLinked(std::string_view entry1, std::string_view entry2); + // Returns true if entry1 links to entry2 (symbolic link). + */ + + if (!Helper::hasSuperUser()) + std::cout << "Super user privileges not given." << std::endl; + + if (Helper::hasAdbPermissions()) + std::cout << "You have ADB shell privileges." << std::endl; + + if (Helper::isExists("myentry")) + std::cout << "myentry exists." << std::endl; + + if (Helper::fileIsExists("file.txt")) + std::cout << "file.txt exists." << std::endl; + + if (Helper::directoryIsExists("mydir")) + std::cout << "mydir exists." << std::endl; + + if (Helper::linkIsExists("mylinked_entry")) + std::cout << "mylinked_entry is symbolic or hard link." << std::endl; + + if (Helper::isLink("mylinked_entry")) + std::cout << "mylinked_entry is symbolic link." << std::endl; + + if (Helper::isHardLink("myhardlinked_entry")) + std::cout << "myhardlinked_entry is hard link." << std::endl; + + if (Helper::areLinked("mylinked_entry", "myentry")) + std::cout << "mylinked_entry links to myentry." << std::endl; + + + /** + File I/O - don't throw Helper::Error + + bool writeFile(std::string_view file, std::string_view text); + // Writes given text into file. + // If file does not exist, it is automatically created. + // Returns true on success. + + std::optional readFile(std::string_view file); + // Reads file content into string. + // On success returns file content. + // On error returns std::nullopt. + */ + + if (Helper::writeFile("file.txt", "hello world")) + std::cout << "file.txt written." << std::endl; + + auto result = Helper::readFile("file.txt"); + if (!result) + std::cerr << "Cannot read file.txt." << std::endl; + else + std::cout << "file.txt: " << *result << std::endl; + + + /** + Creators - don't throw Helper::Error + + bool makeDirectory(std::string_view path); + // Creates a directory at given path. + // Returns true on success. + + bool makeRecursiveDirectory(std::string_view paths); + // Creates all directories in given path recursively. + // Returns true on success. + + bool createFile(std::string_view path); + // Creates an empty file at given path. + // Returns true on success. + + bool createSymlink(std::string_view entry1, std::string_view entry2); + // Creates a symbolic link entry2 pointing to entry1. + // Returns true on success. + */ + + if (Helper::makeDirectory("dir")) + std::cout << "dir created." << std::endl; + + if (Helper::makeRecursiveDirectory("dir1/dir2/dir3")) + std::cout << "dir1/dir2/dir3 created." << std::endl; + + if (Helper::createFile("newfile.txt")) + std::cout << "newfile.txt created." << std::endl; + + if (Helper::createSymlink("newfile.txt", "newfile_symlink.txt")) + std::cout << "newfile.txt symlinked to newfile_symlink.txt." << std::endl; + + + /** + Removers - don't throw Helper::Error + + bool eraseEntry(std::string_view entry); + // Removes file or empty directory. + // Returns true on success. + + bool eraseDirectoryRecursive(std::string_view directory); + // Removes directory and all its contents recursively. + // Returns true on success. + */ + + if (Helper::eraseEntry("file.txt")) + std::cout << "file.txt erased." << std::endl; + + if (Helper::eraseDirectoryRecursive("dir1/dir2/dir3")) + std::cout << "dir1/dir2/dir3 erased." << std::endl; + + + /** + Getters - don't throw Helper::Error + + int64_T fileSize(std::string_view file); + // Returns file size in bytes. + // On error returns -1. + + std::string readSymlink(std::string_view entry); + // Reads the target of symbolic link. + // Returns empty string on error. + */ + + if (size_t size = Helper::fileSize("newfile.txt"); size == -1) + std::cout << "Cannot get size of newfile.txt" << std::endl; + else + std::cout << "Size of newfile.txt: " << size << std::endl; + + if (std::string s = Helper::readSymlink("newfile_symlink.txt"); s.empty()) + std::cout << "Cannot read symlink: newfile_symlink.txt" << std::endl; + else + std::cout << "newfile_symlink.txt points to " << s << std::endl; + + /** + SHA-256 helpers + + bool sha256Compare(std::string_view file1, std::string_view file2); + // Compares the SHA-256 hash of two files. + // Returns true if hashes are equal, false otherwise. + // Uses sha256Of() internally. + // Does not throw Helper::Error. + + std::optional sha256Of(std::string_view path); + // Calculates SHA-256 of a file at given path. + // Returns hex string of hash on success. + // On error, throws Helper::Error. + */ + + if (Helper::sha256Compare("file1.bin", "file2.bin")) + std::cout << "file1.bin and file2.bin are identical (SHA-256)" << std::endl; + else + std::cout << "Files differ (SHA-256)" << std::endl; + + if (auto hash = Helper::sha256Of("file1.bin")) + std::cout << "SHA-256 of file1.bin: " << *hash << std::endl; + else + std::cout << "Failed to calculate SHA-256 of file1.bin" << std::endl; + + /** + Utilities - don't throw Helper::Error + + bool copyFile(std::string_view file, std::string_view dest); + // Copies file to dest. + // Returns true on success. + + bool runCommand(std::string_view cmd); + // Runs a system command without capturing output. + // Returns true if exit status == 0. + + bool confirmPropt(std::string_view message); + // Shows message and asks for y/N from user. + // Returns true if user selects "Yes", false otherwise. + + bool changeMode(std::string_view file, mode_t mode); + // Changes file permissions. + // Returns true on success. + + bool changeOwner(std::string_view file, uid_t uid, gid_t gid); + // Changes file owner and group. + // Returns true on success. + + std::string currentWorkingDirectory(); + // Returns current working directory as string. + + std::string currentDate(); + // Returns current date as string (format: YYYY-MM-DD). + + std::string currentTime(); + // Returns current time as string (format: HH:MM:SS). + + std::string runCommandWithOutput(std::string_view cmd); + // Runs system command and returns its stdout as string. + + std::string pathJoin(std::string base, std::string relative); + // Joins base path with relative path and returns result. + + std::string pathBasename(std::string_view entry); + // Returns the filename part of given path. + + std::string pathDirname(std::string_view entry); + // Returns the directory part of given path. + + uint64_t getRandomOffset(uint64_t size, uint64_t bufferSize); + // Returns random offset depending on size and bufferSize. + */ + + if (Helper::copyFile("file.txt", "backup.txt")) + std::cout << "file.txt copied to backup.txt" << std::endl; + + if (Helper::runCommand("ls -l")) + std::cout << "Command executed successfully" << std::endl; + + if (Helper::confirmPropt("Do you want to continue?")) + std::cout << "User confirmed YES" << std::endl; + else + std::cout << "User selected NO" << std::endl; + + if (Helper::changeMode("file.txt", 0644)) + std::cout << "file.txt mode changed to 644" << std::endl; + + if (Helper::changeOwner("file.txt", 1000, 1000)) + std::cout << "file.txt owner changed to uid=1000 gid=1000" << std::endl; + + std::cout << "CWD: " << Helper::currentWorkingDirectory() << std::endl; + std::cout << "Today: " << Helper::currentDate() << std::endl; + std::cout << "Now: " << Helper::currentTime() << std::endl; + + std::string output = Helper::runCommandWithOutput("echo Hello"); + std::cout << "Output: " << output << std::endl; + + std::cout << "Joined path: " << Helper::pathJoin("/home/user", "docs/file.txt") << std::endl; + std::cout << "Basename: " << Helper::pathBasename("/home/user/docs/file.txt") << std::endl; + std::cout << "Dirname: " << Helper::pathDirname("/home/user/docs/file.txt") << std::endl; + + uint64_t offset = Helper::getRandomOffset(10240, 512); + std::cout << "Random offset: " << offset << std::endl; + + /** + Android - don't throw Helper::Error + WARNING: IF AN ANDROID-SPECIFIED SYSROOT IS NOT USED, IT WILL NOT BE + ADDED AUTOMATICALLY BECAUSE THERE IS NO __ANDROID__ DECLARATION. + + std::string getProperty(std::string_view prop); + // Reads a system property. + // Returns property value as string. + // Returns empty string if property not found. + + bool reboot(std::string_view arg); + // Reboots the system with given argument. + // Example args: "reboot", "recovery", "bootloader". + // Returns true on success. + */ + + std::string model = Helper::getProperty("ro.product.model"); + if (model.empty()) + std::cout << "Cannot read property ro.product.model" << std::endl; + else + std::cout << "Device model: " << model << std::endl; + + if (Helper::reboot("recovery")) + std::cout << "Rebooting into recovery..." << std::endl; + else + std::cerr << "Failed to reboot" << std::endl; + + /** + Library-specific - don't throw Helper::Error + + std::string getLibVersion(); + // Returns library version string. + */ + + std::cout << "Helper library version: " << Helper::getLibVersion() << std::endl; +``` + +--- + +#### Compling and linking +If you're using CMake in your project, you can include it directly with `add_subdirectory`. Both the static and shared libraries will be compiled. + +```cmake +# Include libhelper library +add_subdirectory(srclib/libhelper) + +# Usage example +add_executable(main main.cpp) +target_link_libraries(main PRIVATE helper_shared) # use helper_static if you want link static library +``` + +If you're going to use it prebuilt, you can find it in the PMT releases. Or you can compile it separately... WARNING: PMT releases only include builds for ARM. + +--- + +## libpartition_map library soon! \ No newline at end of file