Move dead submodules in-tree

Signed-off-by: swurl <swurl@swurl.xyz>
This commit is contained in:
swurl 2025-05-31 02:33:02 -04:00
parent c0cceff365
commit 6c655321e6
No known key found for this signature in database
GPG key ID: A5A7629F109C8FD1
4081 changed files with 1185566 additions and 45 deletions

View file

@ -0,0 +1,11 @@
add_compile_options(
-Werror=all
-Werror=extra
-Werror=shadow
)
include_directories(.)
add_subdirectory(tzdb2nx)
add_subdirectory(tzdb)

View file

@ -0,0 +1,90 @@
find_program(GIT_PROGRAM git)
if (NOT GIT_PROGRAM)
message(FATAL_ERROR "git program not found")
endif()
find_program(GNU_DATE date)
if (NOT GNU_DATE)
message(FATAL_ERROR "date program not found")
endif()
set(NX_TZDB_DIR "${CMAKE_CURRENT_BINARY_DIR}/nx" CACHE PATH "Path to Switch-style time zone data")
set(NX_ZONEINFO_DIR "${NX_TZDB_DIR}/zoneinfo")
set(TZDB_VERSION_FILE ${TZ_SOURCE_DIR}/NEWS)
if (NOT "${TZDB2NX_VERSION}" STREQUAL "")
set(TZDB_VERSION "${TZDB2NX_VERSION}\n")
else()
execute_process(
COMMAND
${GIT_PROGRAM} log --pretty=%at -n1 NEWS
OUTPUT_VARIABLE
TZ_COMMIT_TIME
WORKING_DIRECTORY
${TZ_SOURCE_DIR}
COMMAND_ERROR_IS_FATAL ANY)
string(REPLACE "\n" "" TZ_COMMIT_TIME "${TZ_COMMIT_TIME}")
if (APPLE OR CMAKE_SYSTEM_NAME MATCHES "DragonFly|FreeBSD|NetBSD|OpenBSD")
set(VERSION_COMMAND ${GNU_DATE} -r ${TZ_COMMIT_TIME} +%y%m%d)
else ()
set(VERSION_COMMAND ${GNU_DATE} +%y%m%d --date=@${TZ_COMMIT_TIME})
endif ()
execute_process(
COMMAND
${VERSION_COMMAND}
OUTPUT_VARIABLE
TZDB_VERSION
COMMAND_ERROR_IS_FATAL ANY)
endif()
set(NX_VERSION_FILE ${NX_TZDB_DIR}/version.txt)
file(WRITE ${NX_VERSION_FILE} "${TZDB_VERSION}")
add_custom_target(x80e
DEPENDS
tzdb2nx
${NX_VERSION_FILE})
set(BINARY_LIST_TXT ${NX_TZDB_DIR}/binaryList.txt)
add_custom_command(
OUTPUT
${BINARY_LIST_TXT}
COMMAND
${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/generate_binary_list_txt.cmake ${BINARY_LIST_TXT} ${PROJECT_SOURCE_DIR}/CMakeModules/list_directory.cmake
WORKING_DIRECTORY
${NX_ZONEINFO_DIR})
add_custom_target(time_zone_binary_list
DEPENDS ${BINARY_LIST_TXT})
add_dependencies(x80e time_zone_binary_list)
set(TZ_DATA_LIST "")
file(STRINGS "${TZIF_LIST_FILE}" TZ_FILES)
foreach(FILE ${TZ_FILES})
file(RELATIVE_PATH TARG "${TZ_ZONEINFO_DIR}" "${FILE}")
get_filename_component(TARG_PATH "${NX_ZONEINFO_DIR}/${TARG}" DIRECTORY)
string(REGEX REPLACE "\/" "_" TARG_SANITIZED "${TARG}")
set(NX_TZ_TARGET ${NX_ZONEINFO_DIR}/${TARG})
add_custom_command(
OUTPUT
${NX_TZ_TARGET}
COMMAND
mkdir -p ${TARG_PATH}
COMMAND
${TZDB2NX_PATH} ${FILE} ${NX_ZONEINFO_DIR}/${TARG}
DEPENDS
tzdb2nx)
list(APPEND TZ_DATA_LIST ${NX_TZ_TARGET})
endforeach()
add_custom_target(time_zone_data
DEPENDS ${TZ_DATA_LIST})
add_dependencies(x80e time_zone_data)
add_dependencies(time_zone_binary_list time_zone_data)

View file

@ -0,0 +1,52 @@
set(BINARY_LIST_TXT ${CMAKE_ARGV3})
set(LIST_DIR_CMAKE ${CMAKE_ARGV4})
# Fill text file with zone names
# Issue: Hyphens/underscores are not handled the same way Nintendo handles them
function(get_files_nx TARG SUB_DIR)
execute_process(
COMMAND
${CMAKE_COMMAND} -P ${LIST_DIR_CMAKE} false OFF
WORKING_DIRECTORY
${TARG}
OUTPUT_VARIABLE
FILE_LIST
)
list(SORT FILE_LIST)
execute_process(
COMMAND
${CMAKE_COMMAND} -P ${LIST_DIR_CMAKE} true OFF
WORKING_DIRECTORY
${TARG}
OUTPUT_VARIABLE
DIR_LIST
)
foreach(FILE ${FILE_LIST})
if(FILE STREQUAL "\n")
continue()
endif()
list(REMOVE_ITEM DIR_LIST FILE)
if (SUB_DIR)
file(APPEND ${BINARY_LIST_TXT} "${SUB_DIR}/${FILE}\r\n")
else()
file(APPEND ${BINARY_LIST_TXT} "${FILE}\r\n")
endif()
endforeach()
list(SORT DIR_LIST)
foreach(DIR ${DIR_LIST})
if (NOT DIR OR DIR STREQUAL "\n")
continue()
endif()
if (SUB_DIR)
get_files_nx(${TARG}/${DIR} ${SUB_DIR}/${DIR})
else()
get_files_nx(${TARG}/${DIR} ${DIR})
endif()
endforeach()
endfunction()
get_files_nx(${CMAKE_SOURCE_DIR} "")

View file

@ -0,0 +1,6 @@
add_executable(tzdb2nx
main.cpp
tzif.cpp
tzif.h)
set(TZDB2NX_PATH "$<TARGET_FILE:tzdb2nx>" CACHE PATH "Path to tzdb2nx path")

View file

@ -0,0 +1,158 @@
#include "tzif.h"
#include <array>
#include <cerrno>
#include <cstdio>
#include <cstring>
#include <fcntl.h>
#include <getopt.h>
#include <poll.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
constexpr std::size_t ten_megabytes{(1 << 20) * 10};
static void ShortHelp(const char *argv0) {
std::fprintf(stderr, "Usage: %s [INFILE] [OUTFILE]\n", argv0);
}
static void PrintArg(const char *short_arg, const char *long_arg,
const char *text) {
std::fprintf(stderr, "%5s, %-20s %s\n", short_arg, long_arg, text);
}
static void PrintHelp(const char *argv0) {
ShortHelp(argv0);
std::fprintf(stderr,
"Converts a TZif file INFILE from the RFC8536 format to a "
"Nintendo Switch compatible file OUTFILE.\nWith no arguments, "
"tzdb2nx can read and write from stdin/stdout, "
"respectively.\nGiving no arguments without input will print "
"usage information and exit the program.\n\nArguments:\n");
PrintArg("-h", "--help", "Print this help text and exit");
}
int main(int argc, char *argv[]) {
int f{STDIN_FILENO};
const char *filename{"(stdin)"};
std::size_t filesize{ten_megabytes};
const char *optstring = "h";
int c;
const struct option longopts[] = {
{
"help",
no_argument,
nullptr,
'h',
},
{
nullptr,
0,
nullptr,
0,
},
};
while ((c = getopt_long(argc, argv, optstring, longopts, nullptr)) != -1) {
switch (c) {
case 'h':
PrintHelp(argv[0]);
return -1;
case '?':
ShortHelp(argv[0]);
return -1;
}
}
if (argc > 1) {
filename = argv[1];
f = open(filename, O_RDONLY);
if (f == -1) {
const int err = errno;
std::fprintf(stderr, "%s: %s\n", filename, std::strerror(err));
return err;
}
struct stat statbuf;
fstat(f, &statbuf);
filesize = statbuf.st_size;
} else {
struct pollfd fds {
f, POLLIN, 0,
};
const int result = poll(&fds, 1, 0);
if (result == 0) {
std::fprintf(stderr, "%s: No input\n", filename);
ShortHelp(argv[0]);
return -1;
}
}
u_int8_t *buf = new u_int8_t[filesize];
filesize = read(f, buf, filesize);
if (filesize == static_cast<std::size_t>(-1)) {
const int err = errno;
std::fprintf(stderr, "%s: %s\n", filename, std::strerror(err));
return err;
}
int result = close(f);
if (result == -1) {
const int err = errno;
std::fprintf(stderr, "%s: %s\n", filename, std::strerror(err));
return err;
}
if (filesize < 4) {
std::fprintf(stderr, "%s: Too small\n", filename);
return -1;
}
if (std::strncmp(reinterpret_cast<const char *>(buf), "TZif", 4) != 0) {
std::fprintf(stderr, "%s: Bad magic number\n", filename);
return -1;
}
const std::unique_ptr<Tzif::Data> tzif_data = Tzif::ReadData(buf, filesize);
if (tzif_data == nullptr) {
std::fprintf(stderr, "%s: Error occured while reading data\n", filename);
return -1;
}
delete[] buf;
std::vector<u_int8_t> output_buffer;
tzif_data->ReformatNintendo(output_buffer);
filename = "(stdout)";
f = STDOUT_FILENO;
if (argc > 2) {
filename = argv[2];
f = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);
if (f == -1) {
const int err = errno;
std::fprintf(stderr, "%s: %s\n", filename, std::strerror(err));
return err;
}
}
result = write(f, output_buffer.data(), output_buffer.size());
if (result == -1) {
const int err = errno;
std::fprintf(stderr, "%s: %s\n", filename, std::strerror(err));
return err;
}
result = close(f);
if (result == -1) {
const int err = errno;
std::fprintf(stderr, "%s: %s\n", filename, std::strerror(err));
return err;
}
return 0;
}

View file

@ -0,0 +1,146 @@
#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, std::size_t size) {
char magic[5];
const u_int8_t *p{data};
std::memcpy(magic, data, 4);
magic[4] = '\0';
if (std::strcmp(magic, "TZif") != 0) {
return -1;
}
do {
p++;
if (p >= data + size) {
return -1;
}
} 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 (u_int32_t i = 0; i < sizeof(Type); i++) {
u_int32_t 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 std::size_t v2_offset = SkipToVersion2(data, size);
if (v2_offset == static_cast<std::size_t>(-1)) {
return nullptr;
}
const u_int8_t *p = data + v2_offset;
Header header;
std::memcpy(&header, p, sizeof(header));
p += sizeof(header);
FlipHeader(header);
const std::size_t data_block_length =
header.timecnt * sizeof(int64_t) + header.timecnt * sizeof(u_int8_t) +
header.typecnt * sizeof(TimeTypeRecord) +
header.charcnt * sizeof(int8_t) + header.isstdcnt * sizeof(u_int8_t) +
header.isutcnt * sizeof(u_int8_t);
if (v2_offset + data_block_length + sizeof(Header) > size) {
return nullptr;
}
std::unique_ptr<DataImpl> impl = std::make_unique<DataImpl>();
impl->header = header;
const auto copy =
[]<typename Type>(std::unique_ptr<Type[]> &array, int length,
const u_int8_t *const &ptr) -> const u_int8_t * {
const std::size_t region_length = length * sizeof(Type);
array = std::make_unique<Type[]>(length);
std::memcpy(array.get(), ptr, region_length);
return ptr + region_length;
};
p = copy(impl->transition_times, header.timecnt, p);
p = copy(impl->transition_types, header.timecnt, p);
p = copy(impl->local_time_type_records, header.typecnt, p);
p = copy(impl->time_zone_designations, header.charcnt, p);
p = copy(impl->standard_indicators, header.isstdcnt, p);
p = copy(impl->ut_indicators, header.isutcnt, p);
const std::size_t footer_string_length = data + size - p - 2;
p++;
if (p + footer_string_length > data + size ||
p + footer_string_length < data) {
return nullptr;
}
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

View 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;
virtual ~Data() = default;
virtual void ReformatNintendo(std::vector<u_int8_t> &buffer) const = 0;
};
class DataImpl : public Data {
public:
explicit DataImpl() = default;
~DataImpl() override = 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