mirror of
https://github.com/starr-dusT/tzdb_to_nx
synced 2024-03-05 21:18:52 -08:00
general: Initial strip implementation
Produces files identical to Nintendo's format.
This commit is contained in:
parent
d2349d6587
commit
626ecd21cc
@ -2,4 +2,6 @@ cmake_minimum_required(VERSION 3.10)
|
|||||||
|
|
||||||
project(tzdb2nx VERSION 1.0)
|
project(tzdb2nx VERSION 1.0)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
@ -1,4 +1,11 @@
|
|||||||
add_executable(tzdb2nx
|
add_executable(tzdb2nx
|
||||||
main.cpp)
|
main.cpp
|
||||||
|
tzif.cpp
|
||||||
|
tzif.h)
|
||||||
|
|
||||||
|
add_compile_options(
|
||||||
|
-Werror=all
|
||||||
|
-Werror=extra
|
||||||
|
)
|
||||||
|
|
||||||
include_directories(.)
|
include_directories(.)
|
||||||
|
47
src/main.cpp
47
src/main.cpp
@ -1,3 +1,48 @@
|
|||||||
|
#include "tzif.h"
|
||||||
|
#include <array>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
int main() { return 0; }
|
constexpr std::size_t ten_megabytes{(1 << 20) * 10};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
int f{STDIN_FILENO};
|
||||||
|
char *filename{};
|
||||||
|
std::size_t filesize{ten_megabytes};
|
||||||
|
|
||||||
|
if (argc > 1) {
|
||||||
|
char *filename = argv[1];
|
||||||
|
f = open(filename, O_RDONLY);
|
||||||
|
|
||||||
|
struct stat statbuf;
|
||||||
|
stat(filename, &statbuf);
|
||||||
|
|
||||||
|
filesize = statbuf.st_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
u_int8_t *buf = new u_int8_t[filesize];
|
||||||
|
|
||||||
|
filesize = read(f, buf, filesize);
|
||||||
|
close(f);
|
||||||
|
|
||||||
|
const std::unique_ptr<Tzif::DataImpl> tzif_data =
|
||||||
|
Tzif::ReadData(buf, filesize);
|
||||||
|
|
||||||
|
std::vector<u_int8_t> output_buffer;
|
||||||
|
tzif_data->ReformatNintendo(output_buffer);
|
||||||
|
|
||||||
|
f = STDOUT_FILENO;
|
||||||
|
if (argc > 2) {
|
||||||
|
char *filename = argv[2];
|
||||||
|
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC);
|
||||||
|
}
|
||||||
|
|
||||||
|
write(f, output_buffer.data(), output_buffer.size());
|
||||||
|
|
||||||
|
close(f);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
137
src/tzif.cpp
Normal file
137
src/tzif.cpp
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#include "tzif.h"
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
namespace Tzif {
|
||||||
|
|
||||||
|
static std::size_t SkipToVersion2(const u_int8_t *data) {
|
||||||
|
char magic[5];
|
||||||
|
const u_int8_t *p{data};
|
||||||
|
|
||||||
|
std::memcpy(magic, data, 4);
|
||||||
|
magic[4] = '\0';
|
||||||
|
|
||||||
|
if (std::strcmp(magic, "TZif") != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
p++;
|
||||||
|
} while (std::strncmp(reinterpret_cast<const char *>(p), "TZif", 4) != 0);
|
||||||
|
|
||||||
|
return p - data;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Type> constexpr static void SwapEndianess(Type *value) {
|
||||||
|
u_int8_t *data = reinterpret_cast<u_int8_t *>(value);
|
||||||
|
|
||||||
|
union {
|
||||||
|
u_int8_t data[sizeof(Type)];
|
||||||
|
Type value;
|
||||||
|
} temp;
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(Type); i++) {
|
||||||
|
int alt_index = sizeof(Type) - i - 1;
|
||||||
|
temp.data[alt_index] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
*value = temp.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FlipHeader(Header &header) {
|
||||||
|
SwapEndianess(&header.isutcnt);
|
||||||
|
SwapEndianess(&header.isstdcnt);
|
||||||
|
SwapEndianess(&header.leapcnt);
|
||||||
|
SwapEndianess(&header.timecnt);
|
||||||
|
SwapEndianess(&header.typecnt);
|
||||||
|
SwapEndianess(&header.charcnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size) {
|
||||||
|
const u_int8_t *p = data + SkipToVersion2(data);
|
||||||
|
|
||||||
|
Header header;
|
||||||
|
std::memcpy(&header, p, sizeof(header));
|
||||||
|
p += sizeof(header);
|
||||||
|
|
||||||
|
FlipHeader(header);
|
||||||
|
|
||||||
|
std::unique_ptr<DataImpl> impl = std::make_unique<DataImpl>();
|
||||||
|
impl->header = header;
|
||||||
|
|
||||||
|
impl->transition_times = std::make_unique<int64_t[]>(header.timecnt);
|
||||||
|
impl->transition_types = std::make_unique<u_int8_t[]>(header.timecnt);
|
||||||
|
impl->local_time_type_records =
|
||||||
|
std::make_unique<TimeTypeRecord[]>(header.typecnt);
|
||||||
|
impl->time_zone_designations = std::make_unique<int8_t[]>(header.charcnt);
|
||||||
|
impl->standard_indicators = std::make_unique<u_int8_t[]>(header.isstdcnt);
|
||||||
|
impl->ut_indicators = std::make_unique<u_int8_t[]>(header.isutcnt);
|
||||||
|
|
||||||
|
std::memcpy(impl->transition_times.get(), p,
|
||||||
|
header.timecnt * sizeof(int64_t));
|
||||||
|
p += header.timecnt * sizeof(int64_t);
|
||||||
|
|
||||||
|
std::memcpy(impl->transition_types.get(), p,
|
||||||
|
header.timecnt * sizeof(u_int8_t));
|
||||||
|
p += header.timecnt * sizeof(u_int8_t);
|
||||||
|
|
||||||
|
std::memcpy(impl->local_time_type_records.get(), p,
|
||||||
|
header.typecnt * sizeof(TimeTypeRecord));
|
||||||
|
p += header.typecnt * sizeof(TimeTypeRecord);
|
||||||
|
|
||||||
|
std::memcpy(impl->time_zone_designations.get(), p, header.charcnt);
|
||||||
|
p += header.charcnt * sizeof(int8_t);
|
||||||
|
|
||||||
|
std::memcpy(impl->standard_indicators.get(), p,
|
||||||
|
header.isstdcnt * sizeof(u_int8_t));
|
||||||
|
p += header.isstdcnt * sizeof(u_int8_t);
|
||||||
|
|
||||||
|
std::memcpy(impl->ut_indicators.get(), p, header.isutcnt * sizeof(u_int8_t));
|
||||||
|
p += header.isutcnt * sizeof(u_int8_t);
|
||||||
|
|
||||||
|
const std::size_t footer_string_length = data + size - p - 2;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
impl->footer.tz_string = std::make_unique<char[]>(footer_string_length);
|
||||||
|
std::memcpy(impl->footer.tz_string.get(), p, footer_string_length);
|
||||||
|
impl->footer.footer_string_length = footer_string_length;
|
||||||
|
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PushToBuffer(std::vector<u_int8_t> &buffer, const void *data,
|
||||||
|
std::size_t size) {
|
||||||
|
const u_int8_t *p{reinterpret_cast<const u_int8_t *>(data)};
|
||||||
|
for (std::size_t i = 0; i < size; i++) {
|
||||||
|
buffer.push_back(*p);
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataImpl::ReformatNintendo(std::vector<u_int8_t> &buffer) const {
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
|
Header header_copy{header};
|
||||||
|
header_copy.isstdcnt = 0;
|
||||||
|
header_copy.isutcnt = 0;
|
||||||
|
FlipHeader(header_copy);
|
||||||
|
|
||||||
|
PushToBuffer(buffer, &header_copy, sizeof(Header));
|
||||||
|
PushToBuffer(buffer, transition_times.get(),
|
||||||
|
header.timecnt * sizeof(int64_t));
|
||||||
|
PushToBuffer(buffer, transition_types.get(),
|
||||||
|
header.timecnt * sizeof(u_int8_t));
|
||||||
|
PushToBuffer(buffer, local_time_type_records.get(),
|
||||||
|
header.typecnt * sizeof(TimeTypeRecord));
|
||||||
|
PushToBuffer(buffer, time_zone_designations.get(),
|
||||||
|
header.charcnt * sizeof(int8_t));
|
||||||
|
// omit standard_indicators
|
||||||
|
// omit ut_indicators
|
||||||
|
PushToBuffer(buffer, &footer.nl_a, 1);
|
||||||
|
PushToBuffer(buffer, footer.tz_string.get(), footer.footer_string_length);
|
||||||
|
PushToBuffer(buffer, &footer.nl_b, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Tzif
|
72
src/tzif.h
Normal file
72
src/tzif.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <memory>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace Tzif {
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char magic[4];
|
||||||
|
u_int8_t version;
|
||||||
|
u_int8_t reserved[15];
|
||||||
|
u_int32_t isutcnt;
|
||||||
|
u_int32_t isstdcnt;
|
||||||
|
u_int32_t leapcnt;
|
||||||
|
u_int32_t timecnt;
|
||||||
|
u_int32_t typecnt;
|
||||||
|
u_int32_t charcnt;
|
||||||
|
} Header;
|
||||||
|
static_assert(sizeof(Header) == 0x2c);
|
||||||
|
|
||||||
|
class Footer {
|
||||||
|
public:
|
||||||
|
explicit Footer() = default;
|
||||||
|
~Footer() = default;
|
||||||
|
|
||||||
|
const char nl_a{'\n'};
|
||||||
|
std::unique_ptr<char[]> tz_string;
|
||||||
|
const char nl_b{'\n'};
|
||||||
|
|
||||||
|
std::size_t footer_string_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
u_int32_t utoff;
|
||||||
|
u_int8_t dst;
|
||||||
|
u_int8_t idx;
|
||||||
|
} TimeTypeRecord;
|
||||||
|
#pragma pack(pop)
|
||||||
|
static_assert(sizeof(TimeTypeRecord) == 0x6);
|
||||||
|
|
||||||
|
class Data {
|
||||||
|
public:
|
||||||
|
explicit Data() = default;
|
||||||
|
~Data() = default;
|
||||||
|
|
||||||
|
virtual void ReformatNintendo(std::vector<u_int8_t> &buffer) const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DataImpl : public Data {
|
||||||
|
public:
|
||||||
|
explicit DataImpl() = default;
|
||||||
|
~DataImpl() = default;
|
||||||
|
|
||||||
|
void ReformatNintendo(std::vector<u_int8_t> &buffer) const override;
|
||||||
|
|
||||||
|
Header header;
|
||||||
|
Footer footer;
|
||||||
|
|
||||||
|
std::unique_ptr<int64_t[]> transition_times;
|
||||||
|
std::unique_ptr<u_int8_t[]> transition_types;
|
||||||
|
std::unique_ptr<TimeTypeRecord[]> local_time_type_records;
|
||||||
|
std::unique_ptr<int8_t[]> time_zone_designations;
|
||||||
|
std::unique_ptr<u_int8_t[]> standard_indicators;
|
||||||
|
std::unique_ptr<u_int8_t[]> ut_indicators;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<DataImpl> ReadData(const u_int8_t *data, std::size_t size);
|
||||||
|
|
||||||
|
} // namespace Tzif
|
Loading…
Reference in New Issue
Block a user