blob: 99dd3a84c1e54f4a2c09b9017a85a3891a65b6d4 [file]
// Copyright 2025 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/objects/js-temporal-zoneinfo64.h"
#include <iostream>
#include "src/base/logging.h"
#include "temporal_rs/Provider.hpp"
#include "temporal_rs/TimeZone.hpp"
#ifdef V8_INTL_SUPPORT
#include "udatamem.h"
#else
// Defined in builtins-temporal-zoneinfo64-data.cc, generated by
// include-file-as-bytes.py
extern "C" uint32_t zoneinfo64_static_data[];
extern "C" size_t zoneinfo64_static_data_len;
#endif
namespace v8::internal {
ZoneInfo64Provider::ZoneInfo64Provider() {
#ifdef V8_INTL_SUPPORT
UErrorCode status = U_ZERO_ERROR;
memory = udata_open(0, "res", "zoneinfo64", &status);
if (U_FAILURE(status)) {
DCHECK_WITH_MSG(false, "Failed to open zoneinfo64.res");
provider = temporal_rs::Provider::empty();
return;
}
// NOT udata_getLength: this ignores the header,
// and we're parsing resb files with the header
auto length = memory->length;
const void* data = udata_getRawMemory(memory);
DCHECK_WITH_MSG(length % 4 == 0, "ICU4C should align udata to uint32_t");
if (length % 4 != 0) {
// This really shouldn't happen: ICU4C aligns these files
// to 4 when baking them in
provider = temporal_rs::Provider::empty();
return;
}
const uint32_t* data_32 = static_cast<const uint32_t*>(data);
std::span<const uint32_t> data_span(data_32, length / 4);
#else
std::span<const uint32_t> data_span(zoneinfo64_static_data,
zoneinfo64_static_data_len);
#endif
auto result = temporal_rs::Provider::new_zoneinfo64(data_span);
DCHECK_WITH_MSG(result.is_ok(), "Baked-in zoneinfo64 file must parse");
if (result.is_ok()) {
provider = std::move(result).ok().value();
} else {
provider = temporal_rs::Provider::empty();
}
}
ZoneInfo64Provider& ZoneInfo64Provider::Singleton() {
// Allocate it so that it gets leaked (-Wno-exit-destructors)
static ZoneInfo64Provider* SINGLETON = new ZoneInfo64Provider();
return *SINGLETON;
}
// This destructor exists for completeness in case someone decides to use this
// as a stack value, though the default way of accessing this is via singleton.
ZoneInfo64Provider::~ZoneInfo64Provider() {
// Release provider first since it
// may reference memory
provider = nullptr;
// Then clean up memory
// This ideally is a no-op when using static data
#ifdef V8_INTL_SUPPORT
if (memory) {
udata_close(memory);
}
#endif
}
} // namespace v8::internal