Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion cli/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ include_directories(
${THIRDPARTY_DIRECTORY}/Vulkan-Headers/include
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${LibArchive_INCLUDE_DIRS}
)

add_definitions(-DLITTLEENDIAN_CPU)
Expand Down
3 changes: 1 addition & 2 deletions dive_core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -333,15 +333,14 @@ if(WIN32)
# Supress warning about deprecation of std::iterator when compile with c++17
add_definitions(-D_SILENCE_CXX17_ITERATOR_BASE_CLASS_DEPRECATION_WARNING)
endif() # WIN32
target_link_libraries(${PROJECT_NAME} PRIVATE ${LibArchive_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PRIVATE LibArchive::LibArchive)

# This is needed in u_debug.h in mesa, which is included by shader_disassembly.cpp
check_function_exists(secure_getenv HAVE_SECURE_GETENV)
if(HAVE_SECURE_GETENV)
target_compile_definitions(${PROJECT_NAME} PRIVATE -DHAVE_SECURE_GETENV)
endif() # HAVE_SECURE_GETENV

include_directories(${LibArchive_INCLUDE_DIRS})
if(MSVC)
set_property(TARGET ${PROJECT_NAME} PROPERTY C_STANDARD 11) # To support alignas
set_source_files_properties(
Expand Down
1 change: 1 addition & 0 deletions libarchive.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ else()
set(LibArchive_INCLUDE_DIRS ${THIRDPARTY_DIRECTORY}/libarchive/libarchive/)
add_compile_definitions(LIBARCHIVE_STATIC=ON)
include_directories(${THIRDPARTY_DIRECTORY}/libarchive/libarchive/)
add_library(LibArchive::LibArchive ALIAS archive_static)
endif()

include_directories(LibArchive_INCLUDE_DIRS)
Expand Down
1 change: 0 additions & 1 deletion lrz_validator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ include_directories(
${THIRDPARTY_DIRECTORY}/Vulkan-Headers/include
${CMAKE_SOURCE_DIR}
${CMAKE_BINARY_DIR}
${LibArchive_INCLUDE_DIRS}
)

add_executable(${PROJECT_NAME} "main.cpp")
Expand Down
11 changes: 11 additions & 0 deletions src/dive/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,17 @@
message(CHECK_START "Generate build files for src/dive/utils")
list(APPEND CMAKE_MESSAGE_INDENT " ")

# === dive_archive =============================================================

if(NOT ANDROID)
add_library(dive_archive dive_archive.h dive_archive.cpp)
target_link_libraries(
dive_archive
PUBLIC dive_src_includes absl::statusor
PRIVATE LibArchive::LibArchive
)
endif()

# === component_files ==========================================================

if(NOT ANDROID)
Expand Down
168 changes: 168 additions & 0 deletions src/dive/utils/dive_archive.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
/*
Copyright 2026 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

#include "dive/utils/dive_archive.h"

// libarchive:
#include <archive.h>
#include <archive_entry.h>

#include <algorithm>
#include <array>
#include <fstream>
#include <string_view>

namespace
{

void ArchiveReadCloseAndFree(struct archive* archive_reader)
{
if (archive_reader == nullptr)
{
return;
}
archive_read_close(archive_reader);
archive_read_free(archive_reader);
}

using UniqueArchiveReadPtr = std::unique_ptr<struct archive, decltype(&ArchiveReadCloseAndFree)>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍 Good use of unique_ptr to create an RAII type


UniqueArchiveReadPtr ArchiveReadNew()
{
return UniqueArchiveReadPtr{archive_read_new(), &ArchiveReadCloseAndFree};
}

constexpr auto kKnownDiveArchiveExtension =
std::to_array<std::string_view>({".zip", ".tar", ".tar.gz", ".tgz"});

// We don't produce captalized extension, so check for lower case only.
constexpr auto kKnownDiveExtension =
std::to_array<std::string_view>({".rd", ".gfxr", ".gfxa", ".png", ".csv"});

std::string_view GetArchiveEntryPath(struct archive_entry* entry)
{
const char* pathname = archive_entry_pathname(entry);
if (pathname == nullptr)
{
return "";
}
return std::string_view(pathname);
}

int WriteArchiveEntry(std::ostream& ost, struct archive* archive_reader)
{
// Make sure we don't expand a bad sparse file.
constexpr la_int64_t kMaxSkip = 0x40000000;

la_int64_t processed = 0;

while (ost)
{
const void* buff = nullptr;
size_t size = 0;
la_int64_t offset = 0;
auto res = archive_read_data_block(archive_reader, &buff, &size, &offset);
if (res < ARCHIVE_OK)
{
return res;
}
if (size == 0)
{
return ARCHIVE_OK;
}
if (offset - processed > kMaxSkip)
{
return ARCHIVE_FAILED;
}
if (processed != offset)
{
ost.seekp(offset);
}
ost.write(static_cast<const char*>(buff), static_cast<std::streamsize>(size));
processed += static_cast<la_int64_t>(size);
}

return ARCHIVE_FAILED;
}

} // namespace

namespace Dive
{

bool DiveArchive::IsSupportedInputFormat(std::filesystem::path filename)
{
auto ext = filename.extension().string();
std::transform(ext.begin(), ext.end(), ext.begin(), [](auto c) { return std::tolower(c); });
return std::any_of(std::begin(kKnownDiveArchiveExtension), std::end(kKnownDiveArchiveExtension),
[&ext](std::string_view known) { return ext == known; });
}

std::unique_ptr<DiveArchive> DiveArchive::Open(std::filesystem::path filename)
{
return std::unique_ptr<DiveArchive>(new DiveArchive(filename));
}

DiveArchive::DiveArchive(std::filesystem::path archive_path) : m_path(archive_path) {}

std::vector<std::filesystem::path> DiveArchive::ExtractTo(std::filesystem::path dst)
{
constexpr size_t kBlockSize = 0x10000; // 64KiB, we don't really care.
auto reader = ArchiveReadNew();
archive_read_support_format_all(reader.get());
archive_read_support_filter_all(reader.get());

if (auto res = archive_read_open_filename(reader.get(), m_path.string().c_str(), kBlockSize);
res != ARCHIVE_OK)
Comment on lines +128 to +129
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: since res isn't used outside the if, can be omitted

Suggested change
if (auto res = archive_read_open_filename(reader.get(), m_path.string().c_str(), kBlockSize);
res != ARCHIVE_OK)
if (archive_read_open_filename(reader.get(), m_path.string().c_str(), kBlockSize) != ARCHIVE_OK)

{
return {};
}

std::vector<std::filesystem::path> filenames;
while (true)
{
struct archive_entry* entry = nullptr;
if (auto res = archive_read_next_header(reader.get(), &entry); res != ARCHIVE_OK)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: since res isn't used outside the if, can be omitted

Suggested change
if (auto res = archive_read_next_header(reader.get(), &entry); res != ARCHIVE_OK)
if (archive_read_next_header(reader.get(), &entry) != ARCHIVE_OK)

{
break;
}

if (archive_entry_filetype(entry) != AE_IFREG)
{
continue;
}

std::filesystem::path entry_path = std::filesystem::path(GetArchiveEntryPath(entry));
if (std::none_of(std::begin(kKnownDiveExtension), std::end(kKnownDiveExtension),
[ext = entry_path.extension().string()](std::string_view expected) {
return ext == expected;
}))
{
continue;
}

auto dst_file_path = dst / entry_path.filename();
std::ofstream dst_file(dst_file_path, std::ios::binary | std::ios::out);
if (auto res = WriteArchiveEntry(dst_file, reader.get()); res != ARCHIVE_OK)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: since res isn't used outside the if, can be omitted

Suggested change
if (auto res = WriteArchiveEntry(dst_file, reader.get()); res != ARCHIVE_OK)
if (WriteArchiveEntry(dst_file, reader.get()) != ARCHIVE_OK)

{
break;
}
filenames.push_back(dst_file_path);
}
return filenames;
}

} // namespace Dive
42 changes: 42 additions & 0 deletions src/dive/utils/dive_archive.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
Copyright 2026 Google LLC

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.
*/

#pragma once

#include <filesystem>
#include <memory>
#include <vector>

namespace Dive
{

class DiveArchive
{
public:
static std::unique_ptr<DiveArchive> Open(std::filesystem::path filename);

// Extract to `dst` directory, returns extracted filepaths.
std::vector<std::filesystem::path> ExtractTo(std::filesystem::path dst);

static bool IsSupportedInputFormat(std::filesystem::path filename);

private:
explicit DiveArchive(std::filesystem::path archive_path);

std::filesystem::path m_path;
};

} // namespace Dive
2 changes: 1 addition & 1 deletion ui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,6 @@ target_include_directories(
"${CMAKE_SOURCE_DIR}"
# Include CMAKE_BINARY_DIR for generated files.
"${CMAKE_BINARY_DIR}"
"${LibArchive_INCLUDE_DIRS}"
)

# Enable asan and ubsan
Expand Down Expand Up @@ -225,6 +224,7 @@ target_link_libraries(
absl::span
absl::symbolize
network
dive_archive
dive_core
dive_lib_os
dive_lib_ui
Expand Down
Loading
Loading