Skip to content
Open
4 changes: 4 additions & 0 deletions SolARFramework.pri
Original file line number Diff line number Diff line change
Expand Up @@ -127,9 +127,11 @@ interfaces/api/tracking/IOpticalFlowEstimator.h \
interfaces/core/Log.h \
interfaces/core/Timer.h \
interfaces/core/Messages.h \
interfaces/core/ScopedTempDir.h \
interfaces/core/SerializationDefinitions.h \
interfaces/core/SolARFramework.h \
interfaces/core/SolARFrameworkDefinitions.h \
interfaces/core/ZipBufferUtils.h \
interfaces/datastructure/BufferInternal.hpp \
interfaces/datastructure/CameraDefinitions.h \
interfaces/datastructure/CameraParametersCollection.h \
Expand Down Expand Up @@ -190,7 +192,9 @@ src/api/map/IRectifyMap.cpp \
src/datastructure/RelocalizationInformation.cpp \
src/datastructure/StorageCapabilities.cpp \
src/core/Log.cpp \
src/core/ScopedTempDir.cpp \
src/core/SolARFramework.cpp \
src/core/ZipBufferUtils.cpp \
src/datastructure/CameraParametersCollection.cpp \
src/datastructure/CloudPoint.cpp \
src/datastructure/CoordinateSystem.cpp \
Expand Down
57 changes: 57 additions & 0 deletions interfaces/core/ScopedTempDir.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/**
* @copyright Copyright (c) 2026 B-com http://www.b-com.com/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef SOLAR_SCOPEDTEMPDIR_H
#define SOLAR_SCOPEDTEMPDIR_H

#include <string>
#include <filesystem>

namespace SolAR {
namespace util {

/**
* @class ScopedTempDir
* @brief <B>Create a temporary directory</B>
*
*/
class ScopedTempDir {

public:

ScopedTempDir();

~ScopedTempDir();

// Delete copy operations to prevent double deletion
ScopedTempDir(const ScopedTempDir&) = delete;
ScopedTempDir& operator=(const ScopedTempDir&) = delete;
ScopedTempDir(ScopedTempDir&&) = delete;
ScopedTempDir& operator=(ScopedTempDir&&) = delete;

const std::filesystem::path& getPath() const;
const std::string getStringPath() const;

private:

std::filesystem::path m_tempPath; // Temporary working directory used to copy, zip or unzip data

};

} // end of namespace util
} // end of namespace SolAR

#endif // SOLAR_SCOPEDTEMPDIR_H
60 changes: 60 additions & 0 deletions interfaces/core/ZipBufferUtils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* @copyright Copyright (c) 2026 B-com http://www.b-com.com/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#ifndef SOLAR_ZIPBUFFERUTILS_H
#define SOLAR_ZIPBUFFERUTILS_H

#include "core/Messages.h"
#include <string>
#include <vector>

namespace SolAR {
namespace util {

/**
* @class ZipBufferUtils
* @brief <B>Defines methods to zip/unzip data to/from a binary buffer </B>
*
*/

class ZipBufferUtils {

public:

/// @brief zip the content of the original path and store the binary result in the output buffer
/// @param[in] originalPath path to data to zip
/// @param[out] compressedZipBuffer output buffer containing the zip data
/// @return
/// * FrameworkReturnCode::_SUCCESS if the process succeeds
/// * else FrameworkReturnCode::_ERROR_
static FrameworkReturnCode compress(const std::string & originalPath,
std::vector<unsigned char> & compressedZipBuffer);

/// @brief unzip the content of the input buffer and store the result in the destination path
/// @param[in] compressedZipBuffer input buffer containing the zip data
/// @param[in] destinationPath path for unzipped data
/// @return
/// * FrameworkReturnCode::_SUCCESS if the process succeeds
/// * else FrameworkReturnCode::_ERROR_
static FrameworkReturnCode extract(const std::vector<unsigned char> & compressedZipBuffer,
const std::string & destinationPath);

};

} // end of namespace util
} // end of namespace SolAR

#endif // SOLAR_ZIPBUFFERUTILS_H
41 changes: 41 additions & 0 deletions src/core/ScopedTempDir.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "core/ScopedTempDir.h"
#include <random>

namespace fs = std::filesystem;

using namespace SolAR;
using namespace SolAR::util;

ScopedTempDir::ScopedTempDir()
{
fs::path base_path = fs::temp_directory_path();

// Generate a random name for temporary subdirectory
std::random_device rd;
std::mt19937_64 gen(rd());
std::uniform_int_distribution<uint64_t> dis;
do {
std::string random_name = "tmp_" + std::to_string(dis(gen));
m_tempPath = base_path / random_name;
} while (fs::exists(m_tempPath));

// Create the temporary subdirectory
std::error_code ec;
fs::create_directories(m_tempPath, ec);
}

ScopedTempDir::~ScopedTempDir()
{
// Delete the temporary directory (and its contents)
std::error_code ec; fs::remove_all(m_tempPath, ec);
}

const fs::path& ScopedTempDir::getPath() const
{
return m_tempPath;
}

const std::string ScopedTempDir::getStringPath() const
{
return m_tempPath.string();
}
121 changes: 121 additions & 0 deletions src/core/ZipBufferUtils.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include "core/ZipBufferUtils.h"
#include "core/ScopedTempDir.h"
#include "core/Log.h"

namespace fs = std::filesystem;

using namespace SolAR;
using namespace SolAR::util;

FrameworkReturnCode ZipBufferUtils::compress(const std::string & originalPath,
std::vector<unsigned char> & compressedZipBuffer)
{
LOG_DEBUG("ZipBufferUtils::compress - Original path: {}", originalPath);

compressedZipBuffer.clear();

// Get a temporary working directory
ScopedTempDir workingDir;

LOG_DEBUG("ZipBufferUtils::compress - Working temporary path: {}", workingDir.getStringPath());

fs::path op(originalPath);

try {
// Check original path
if (!fs::is_directory(op)) {
LOG_ERROR("ZipBufferUtils::compress - The original path is not a directory: {}", originalPath);
return FrameworkReturnCode::_ERROR_;
}
if (fs::is_empty(op)) {
LOG_WARNING("ZipBufferUtils::compress - The original path is empty: {}", originalPath);
return FrameworkReturnCode::_SUCCESS;
}
}
catch (const fs::filesystem_error & e) {
LOG_ERROR("ZipBufferUtils::compress - The following exception has been caught {}", e.what());
return FrameworkReturnCode::_ERROR_;
}

// Try to zip the original path content
std::string command = "cd " + originalPath +"; zip -r " + workingDir.getStringPath() + "/data.zip .";
if (std::system(command.c_str()) != 0) {
LOG_ERROR("ZipBufferUtils::compress - Error occured while trying to zip the working directory content: {}", workingDir.getStringPath());
return FrameworkReturnCode::_ERROR_;
}

// Open the resulting zip file
std::string zipFile = workingDir.getStringPath() + "/data.zip";
std::ifstream file(zipFile, std::ios::binary);
if (!file.is_open()) {
LOG_ERROR("ZipBufferUtils::compress - Cannot open the zip binary file: {}", zipFile);
return FrameworkReturnCode::_ERROR_;
}

// Get its size
file.seekg(0, std::ios::end);
std::streampos fileSize = file.tellg();
file.seekg(0, std::ios::beg);
if (fileSize == 0) {
LOG_ERROR("ZipBufferUtils::compress - Empty zip binary file: {}", zipFile);
return FrameworkReturnCode::_ERROR_;
}
LOG_DEBUG("ZipBufferUtils::compress - Zip file size ({}): {}", zipFile, fmt::streamed(fileSize));

// Read the data and put it in the output buffer
compressedZipBuffer.resize(fileSize);
file.read(reinterpret_cast<char*>(compressedZipBuffer.data()), compressedZipBuffer.size());

return FrameworkReturnCode::_SUCCESS;
}

FrameworkReturnCode ZipBufferUtils::extract(const std::vector<unsigned char> & compressedZipBuffer,
const std::string & destinationPath)
{
LOG_DEBUG("ZipBufferUtils::extract - Destination path: {}", destinationPath);

if (compressedZipBuffer.empty()) {
LOG_WARNING("ZipBufferUtils::extract - Empty input buffer");
return FrameworkReturnCode::_SUCCESS;
}

try {
fs::path dp(destinationPath);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the other function you clear the output buffer, here we could delete the content of the destination path as well ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so: this destination directory can contain other files, we don't know.


// Check destination path
if (!fs::is_directory(dp)) {
LOG_ERROR("ZipBufferUtils::extract - The destination path is not a directory: {}", destinationPath);
return FrameworkReturnCode::_ERROR_;
}

// Get a temporary working directory
ScopedTempDir workingDir;

LOG_DEBUG("ZipBufferUtils::extract - Working temporary path: {}", workingDir.getStringPath());

// Create the zip file from the input buffer
std::string zipFile = workingDir.getStringPath() + "/data.zip";
std::ofstream file(zipFile, std::ios::out | std::ios::binary);
if (!file.is_open()) {
LOG_ERROR("ZipBufferUtils::extract - Cannot create/open zip file: {}", zipFile);
return FrameworkReturnCode::_ERROR_;
}

// Write the compressed data
file.write(reinterpret_cast<const char*>(compressedZipBuffer.data()), compressedZipBuffer.size());
file.close();

// Try to unzip the file content
std::string command = "unzip " + workingDir.getStringPath() + "/data.zip -d " + destinationPath;
if (std::system(command.c_str()) != 0) {
LOG_ERROR("ZipBufferUtils::extract - Error occured while trying to unzip the compressed data file: {}", zipFile);
return FrameworkReturnCode::_ERROR_;
}

return FrameworkReturnCode::_SUCCESS;
}
catch (const fs::filesystem_error & e) {
LOG_ERROR("ZipBufferUtils::extract - The following exception has been caught {}", e.what());
return FrameworkReturnCode::_ERROR_;
}
}