#ifndef UI_BASE_RESOURCE_DATA_PACK_H_
#define UI_BASE_RESOURCE_DATA_PACK_H_
#include <stddef.h>
#include <stdint.h>
#include <map>
#include <memory>
#include <optional>
#include <string_view>
#include <vector>
#include "base/compiler_specific.h"
#include "base/component_export.h"
#include "base/files/file.h"
#include "base/files/memory_mapped_file.h"
#include "base/memory/raw_ptr.h"
#include "base/types/expected.h"
#include "build/build_config.h"
#include "ui/base/resource/resource_handle.h"
#if BUILDFLAG(IS_WIN)
#include "base/win/windows_types.h"
#endif
namespace base {
class FilePath;
class RefCountedStaticMemory;
}
namespace ui {
enum ResourceScaleFactor : int;
class COMPONENT_EXPORT(UI_DATA_PACK) DataPack : public ResourceHandle {
public:
#if BUILDFLAG(ARKWEB_HAP_DECOMPRESSED)
friend class DataPackUtil;
#endif
explicit DataPack(ResourceScaleFactor resource_scale_factor);
DataPack(const DataPack&) = delete;
DataPack& operator=(const DataPack&) = delete;
~DataPack() override;
#pragma pack(push, 1)
struct Entry {
static int CompareById(const void* void_key, const void* void_entry);
uint16_t resource_id;
uint32_t file_offset;
};
struct Alias {
static int CompareById(const void* void_key, const void* void_entry);
uint16_t resource_id;
uint16_t entry_index;
};
#pragma pack(pop)
struct ResourceData {
explicit ResourceData(uint16_t id, std::string_view data)
: id(id), data(data) {}
uint16_t id;
std::string_view data;
};
class Iterator {
public:
Iterator() = default;
~Iterator() = default;
Iterator(const Iterator&) = default;
Iterator& operator=(const Iterator&) = default;
const ResourceData& operator*() { return *resource_data_; }
Iterator& operator++() {
UNSAFE_TODO(++entry_);
UpdateResourceData();
return *this;
}
bool operator==(const Iterator& other) const {
return entry_ == other.entry_;
}
private:
friend class DataPack;
explicit Iterator(const uint8_t* data_source, const Entry* entry)
: data_source_(data_source), entry_(entry) {
UpdateResourceData();
}
void UpdateResourceData();
raw_ptr<const uint8_t> data_source_;
raw_ptr<ResourceData> resource_data_;
raw_ptr<const Entry, AllowPtrArithmetic> entry_;
};
Iterator begin() const;
Iterator end() const;
class DataSource {
public:
virtual ~DataSource() = default;
virtual size_t GetLength() const = 0;
virtual const uint8_t* GetData() const = 0;
};
bool LoadFromPath(const base::FilePath& path);
enum class FailureReason {
kOpenFile,
kMapFile,
kUnzip,
kIncompleteHeader,
kBadPakVersion,
kBadEncodingType,
kTooShort,
kBoundsExceeded,
kOrderingViolation,
kAliasTableCorrupt,
};
struct ErrorState {
FailureReason reason;
#if BUILDFLAG(IS_WIN)
DWORD error;
#else
int error;
#endif
base::File::Error file_error;
friend bool operator==(const ErrorState& lhs,
const ErrorState& rhs) = default;
};
base::expected<void, DataPack::ErrorState> LoadFromPathWithError(
const base::FilePath& path);
static base::expected<std::unique_ptr<DataPack::DataSource>,
DataPack::ErrorState>
LoadFromPathInternal(const base::FilePath& path);
bool LoadFromFile(base::File file);
bool LoadFromFileRegion(base::File file,
const base::MemoryMappedFile::Region& region);
bool LoadFromBuffer(base::span<const uint8_t> buffer);
static bool WritePack(const base::FilePath& path,
const std::map<uint16_t, std::string_view>& resources,
TextEncodingType textEncodingType);
bool HasResource(uint16_t resource_id) const override;
std::optional<std::string_view> GetStringView(
uint16_t resource_id) const override;
base::RefCountedStaticMemory* GetStaticMemory(
uint16_t resource_id) const override;
TextEncodingType GetTextEncodingType() const override;
ResourceScaleFactor GetResourceScaleFactor() const override;
#if DCHECK_IS_ON()
void CheckForDuplicateResources(
const std::vector<std::unique_ptr<ResourceHandle>>& packs) override;
#endif
const Entry* GetEntryByResourceTableIndex(size_t index) const {
return UNSAFE_TODO(&resource_table_[index]);
}
const Alias* GetAliasByAliasTableIndex(size_t index) const {
return UNSAFE_TODO(&alias_table_[index]);
}
size_t GetAliasTableSize() const { return alias_count_; }
size_t GetResourceTableSizeForTesting() const { return resource_count_; }
private:
class BufferDataSource;
class MemoryMappedDataSource;
class StringDataSource;
base::expected<void, DataPack::FailureReason> LoadImpl(
std::unique_ptr<DataSource> data_source);
const Entry* LookupEntryById(uint16_t resource_id) const;
base::expected<void, DataPack::FailureReason>
SanityCheckFileAndRegisterResources(size_t margin_to_skip,
const uint8_t* data,
size_t data_length);
static std::string_view GetStringViewFromOffset(uint32_t target_offset,
uint32_t next_offset,
const uint8_t* data_source);
std::unique_ptr<DataSource> data_source_;
raw_ptr<const Entry, AllowPtrArithmetic> resource_table_;
size_t resource_count_;
raw_ptr<const Alias, AllowPtrArithmetic> alias_table_;
size_t alias_count_;
TextEncodingType text_encoding_type_;
ResourceScaleFactor resource_scale_factor_;
};
}
#endif