utility 2026.1.9
A comprehensive C++ utilities library tailored for the development of modern desktop and extended reality (XR) applications.
Loading...
Searching...
No Matches
android_system_io.cpp
1/*
2 Copyright (c) 2026 ETIB Corporation
3
4 Permission is hereby granted, free of charge, to any person obtaining a copy of
5 this software and associated documentation files (the "Software"), to deal in
6 the Software without restriction, including without limitation the rights to
7 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
8 of the Software, and to permit persons to whom the Software is furnished to do
9 so, subject to the following conditions:
10
11 The above copyright notice and this permission notice shall be included in all
12 copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 SOFTWARE.
21 */
22
23#include "utility/system_io/android_system_io.hpp"
24
25#ifdef __ANDROID__
26
27 #include <filesystem>
28 #include <fstream>
29 #include <memory>
30
32
33namespace
34{
35 std::string NormalizePath(const std::string &path)
36 {
37 return std::filesystem::path(path).lexically_normal().string();
38 }
39} // namespace
40
41utility::AndroidSystemIO::AndroidSystemIO(AAssetManager *systemInterface)
42 : _assetManager(systemInterface)
43 , _logger(
44 std::make_unique<utility::logging::DefaultLogger>("AndroidSystemIO"))
45{
46}
47
48utility::logging::Logger &utility::AndroidSystemIO::getLogger(void)
49{
50 return *_logger;
51}
52
53utility::logging::Logger &utility::AndroidSystemIO::getLogger(void) const
54{
55 return *_logger;
56}
57
58bool utility::AndroidSystemIO::loadDirectory(const std::string &directory)
59{
60 AAssetDir *assetDir =
61 AAssetManager_openDir(_assetManager, directory.c_str());
62 if (assetDir == nullptr) {
63 getLogger().warning()
64 << "Failed to open asset directory: " << directory;
65 return false;
66 }
67
68 const char *fileName = nullptr;
69 while ((fileName = AAssetDir_getNextFileName(assetDir)) != nullptr) {
70 std::string assetPath = directory + "/" + fileName;
71 if (!this->add(assetPath)) {
72 getLogger().warning() << "Failed to load asset: " << assetPath;
73 }
74 }
75 AAssetDir_close(assetDir);
76 return true;
77}
78
79std::shared_ptr<utility::File>
80 utility::AndroidSystemIO::add(const std::string &path)
81{
82 const std::string key = NormalizePath(path);
83 if (this->exists(key)) {
84 return this->open(key);
85 }
86
87 AAsset *file =
88 AAssetManager_open(_assetManager, key.c_str(), AASSET_MODE_UNKNOWN);
89 if (file == nullptr) {
90 return nullptr;
91 }
92
93 off_t fileLength = AAsset_getLength(file);
94 if (fileLength < 0) {
95 AAsset_close(file);
96 return nullptr;
97 }
98
99 std::string content(static_cast<size_t>(fileLength), '\0');
100 if (!content.empty()) {
101 const int bytesRead =
102 AAsset_read(file, content.data(), static_cast<size_t>(fileLength));
103 if (bytesRead < 0 || static_cast<off_t>(bytesRead) != fileLength) {
104 AAsset_close(file);
105 return nullptr;
106 }
107 }
108 AAsset_close(file);
109
110 auto asset = std::make_shared<utility::File>(path, content);
111 _assets[key] = asset;
112 return asset;
113}
114
115void utility::AndroidSystemIO::remove(const std::string &path, bool save)
116{
117 const std::string key = NormalizePath(path);
118 auto it = _assets.find(key);
119 if (it != _assets.end()) {
120 if (save) {
121 this->save(key);
122 }
123 _assets.erase(it);
124 } else {
125 getLogger().warning() << "Asset not found: " << key;
126 }
127}
128
129bool utility::AndroidSystemIO::save(const std::string &path,
130 const std::string &newPath)
131{
132 const std::string key = NormalizePath(path);
133 auto it = _assets.find(key);
134 if (it == _assets.end()) {
135 getLogger().warning() << "Asset not found: " << key;
136 return false;
137 }
138 // Android assets are read-only from the APK. Saving to a new path must be
139 // provided.
140 if (newPath.empty()) {
141 getLogger().warning()
142 << "Cannot save Android asset to original path. Provide a newPath.";
143 return false;
144 }
145 const auto &content = it->second->data();
146 std::ofstream file(newPath, std::ios::binary);
147 if (!file.is_open()) {
148 getLogger().warning() << "Failed to open file for writing: " << newPath;
149 return false;
150 }
151 file.write(reinterpret_cast<const char *>(content.data()), content.size());
152 file.close();
153 return true;
154}
155
156#endif // __ANDROID__
Abstract logger interface defining stream-style logging operations.
Definition logger.hpp:96
Platform-specific default logger alias.
StandardLogger DefaultLogger
Alias for the platform-specific default logger.
The utility namespace contains classes and functions for the utility project.
Definition cache.hpp:34