Merge pull request #3271 from bunnei/time-rewrite
service: time: Rewrite implementation of glue services.
This commit is contained in:
commit
8b9f433d95
43 changed files with 3670 additions and 539 deletions
|
@ -96,6 +96,8 @@ add_library(core STATIC
|
||||||
file_sys/system_archive/system_archive.h
|
file_sys/system_archive/system_archive.h
|
||||||
file_sys/system_archive/system_version.cpp
|
file_sys/system_archive/system_version.cpp
|
||||||
file_sys/system_archive/system_version.h
|
file_sys/system_archive/system_version.h
|
||||||
|
file_sys/system_archive/time_zone_binary.cpp
|
||||||
|
file_sys/system_archive/time_zone_binary.h
|
||||||
file_sys/vfs.cpp
|
file_sys/vfs.cpp
|
||||||
file_sys/vfs.h
|
file_sys/vfs.h
|
||||||
file_sys/vfs_concat.cpp
|
file_sys/vfs_concat.cpp
|
||||||
|
@ -461,12 +463,40 @@ add_library(core STATIC
|
||||||
hle/service/spl/spl.h
|
hle/service/spl/spl.h
|
||||||
hle/service/ssl/ssl.cpp
|
hle/service/ssl/ssl.cpp
|
||||||
hle/service/ssl/ssl.h
|
hle/service/ssl/ssl.h
|
||||||
|
hle/service/time/clock_types.h
|
||||||
|
hle/service/time/ephemeral_network_system_clock_context_writer.h
|
||||||
|
hle/service/time/ephemeral_network_system_clock_core.h
|
||||||
|
hle/service/time/errors.h
|
||||||
hle/service/time/interface.cpp
|
hle/service/time/interface.cpp
|
||||||
hle/service/time/interface.h
|
hle/service/time/interface.h
|
||||||
|
hle/service/time/local_system_clock_context_writer.h
|
||||||
|
hle/service/time/network_system_clock_context_writer.h
|
||||||
|
hle/service/time/standard_local_system_clock_core.h
|
||||||
|
hle/service/time/standard_network_system_clock_core.h
|
||||||
|
hle/service/time/standard_steady_clock_core.cpp
|
||||||
|
hle/service/time/standard_steady_clock_core.h
|
||||||
|
hle/service/time/standard_user_system_clock_core.cpp
|
||||||
|
hle/service/time/standard_user_system_clock_core.h
|
||||||
|
hle/service/time/steady_clock_core.h
|
||||||
|
hle/service/time/system_clock_context_update_callback.cpp
|
||||||
|
hle/service/time/system_clock_context_update_callback.h
|
||||||
|
hle/service/time/system_clock_core.cpp
|
||||||
|
hle/service/time/system_clock_core.h
|
||||||
|
hle/service/time/tick_based_steady_clock_core.cpp
|
||||||
|
hle/service/time/tick_based_steady_clock_core.h
|
||||||
hle/service/time/time.cpp
|
hle/service/time/time.cpp
|
||||||
hle/service/time/time.h
|
hle/service/time/time.h
|
||||||
|
hle/service/time/time_manager.cpp
|
||||||
|
hle/service/time/time_manager.h
|
||||||
hle/service/time/time_sharedmemory.cpp
|
hle/service/time/time_sharedmemory.cpp
|
||||||
hle/service/time/time_sharedmemory.h
|
hle/service/time/time_sharedmemory.h
|
||||||
|
hle/service/time/time_zone_content_manager.cpp
|
||||||
|
hle/service/time/time_zone_content_manager.h
|
||||||
|
hle/service/time/time_zone_manager.cpp
|
||||||
|
hle/service/time/time_zone_manager.h
|
||||||
|
hle/service/time/time_zone_service.cpp
|
||||||
|
hle/service/time/time_zone_service.h
|
||||||
|
hle/service/time/time_zone_types.h
|
||||||
hle/service/usb/usb.cpp
|
hle/service/usb/usb.cpp
|
||||||
hle/service/usb/usb.h
|
hle/service/usb/usb.h
|
||||||
hle/service/vi/display/vi_display.cpp
|
hle/service/vi/display/vi_display.cpp
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "core/file_sys/system_archive/shared_font.h"
|
#include "core/file_sys/system_archive/shared_font.h"
|
||||||
#include "core/file_sys/system_archive/system_archive.h"
|
#include "core/file_sys/system_archive/system_archive.h"
|
||||||
#include "core/file_sys/system_archive/system_version.h"
|
#include "core/file_sys/system_archive/system_version.h"
|
||||||
|
#include "core/file_sys/system_archive/time_zone_binary.h"
|
||||||
|
|
||||||
namespace FileSys::SystemArchive {
|
namespace FileSys::SystemArchive {
|
||||||
|
|
||||||
|
@ -38,7 +39,7 @@ constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHI
|
||||||
{0x010000000000080B, "LocalNews", nullptr},
|
{0x010000000000080B, "LocalNews", nullptr},
|
||||||
{0x010000000000080C, "Eula", nullptr},
|
{0x010000000000080C, "Eula", nullptr},
|
||||||
{0x010000000000080D, "UrlBlackList", nullptr},
|
{0x010000000000080D, "UrlBlackList", nullptr},
|
||||||
{0x010000000000080E, "TimeZoneBinary", nullptr},
|
{0x010000000000080E, "TimeZoneBinary", &TimeZoneBinary},
|
||||||
{0x010000000000080F, "CertStoreCruiser", nullptr},
|
{0x010000000000080F, "CertStoreCruiser", nullptr},
|
||||||
{0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension},
|
{0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension},
|
||||||
{0x0100000000000811, "FontStandard", &FontStandard},
|
{0x0100000000000811, "FontStandard", &FontStandard},
|
||||||
|
|
657
src/core/file_sys/system_archive/time_zone_binary.cpp
Normal file
657
src/core/file_sys/system_archive/time_zone_binary.cpp
Normal file
|
@ -0,0 +1,657 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/swap.h"
|
||||||
|
#include "core/file_sys/system_archive/time_zone_binary.h"
|
||||||
|
#include "core/file_sys/vfs_vector.h"
|
||||||
|
#include "core/hle/service/time/time_zone_types.h"
|
||||||
|
|
||||||
|
namespace FileSys::SystemArchive {
|
||||||
|
|
||||||
|
static constexpr std::array<u8, 9633> LOCATION_NAMES{
|
||||||
|
0x43, 0x45, 0x54, 0x0d, 0x0a, 0x43, 0x53, 0x54, 0x36, 0x43, 0x44, 0x54, 0x0d, 0x0a, 0x43, 0x75,
|
||||||
|
0x62, 0x61, 0x0d, 0x0a, 0x45, 0x45, 0x54, 0x0d, 0x0a, 0x45, 0x67, 0x79, 0x70, 0x74, 0x0d, 0x0a,
|
||||||
|
0x45, 0x69, 0x72, 0x65, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45,
|
||||||
|
0x44, 0x54, 0x0d, 0x0a, 0x47, 0x42, 0x0d, 0x0a, 0x47, 0x42, 0x2d, 0x45, 0x69, 0x72, 0x65, 0x0d,
|
||||||
|
0x0a, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54,
|
||||||
|
0x2d, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77,
|
||||||
|
0x69, 0x63, 0x68, 0x0d, 0x0a, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x48,
|
||||||
|
0x53, 0x54, 0x0d, 0x0a, 0x49, 0x63, 0x65, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x49, 0x72, 0x61,
|
||||||
|
0x6e, 0x0d, 0x0a, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x0d, 0x0a, 0x4a, 0x61, 0x6d, 0x61, 0x69,
|
||||||
|
0x63, 0x61, 0x0d, 0x0a, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x4b, 0x77, 0x61, 0x6a, 0x61,
|
||||||
|
0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x4c, 0x69, 0x62, 0x79, 0x61, 0x0d, 0x0a, 0x4d, 0x45, 0x54,
|
||||||
|
0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x37, 0x4d, 0x44, 0x54, 0x0d, 0x0a,
|
||||||
|
0x4e, 0x61, 0x76, 0x61, 0x6a, 0x6f, 0x0d, 0x0a, 0x4e, 0x5a, 0x0d, 0x0a, 0x4e, 0x5a, 0x2d, 0x43,
|
||||||
|
0x48, 0x41, 0x54, 0x0d, 0x0a, 0x50, 0x6f, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x50, 0x6f, 0x72,
|
||||||
|
0x74, 0x75, 0x67, 0x61, 0x6c, 0x0d, 0x0a, 0x50, 0x52, 0x43, 0x0d, 0x0a, 0x50, 0x53, 0x54, 0x38,
|
||||||
|
0x50, 0x44, 0x54, 0x0d, 0x0a, 0x52, 0x4f, 0x43, 0x0d, 0x0a, 0x52, 0x4f, 0x4b, 0x0d, 0x0a, 0x53,
|
||||||
|
0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x54, 0x75, 0x72, 0x6b, 0x65, 0x79,
|
||||||
|
0x0d, 0x0a, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c,
|
||||||
|
0x0d, 0x0a, 0x55, 0x54, 0x43, 0x0d, 0x0a, 0x57, 0x2d, 0x53, 0x55, 0x0d, 0x0a, 0x57, 0x45, 0x54,
|
||||||
|
0x0d, 0x0a, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
|
||||||
|
0x62, 0x69, 0x64, 0x6a, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
|
||||||
|
0x63, 0x63, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x64,
|
||||||
|
0x69, 0x73, 0x5f, 0x41, 0x62, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x41, 0x6c, 0x67, 0x69, 0x65, 0x72, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x41, 0x73, 0x6d, 0x61, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x41, 0x73, 0x6d, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42,
|
||||||
|
0x61, 0x6d, 0x61, 0x6b, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61,
|
||||||
|
0x6e, 0x67, 0x75, 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e,
|
||||||
|
0x6a, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x73,
|
||||||
|
0x61, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x74,
|
||||||
|
0x79, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x72, 0x61, 0x7a,
|
||||||
|
0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x42, 0x75, 0x6a, 0x75, 0x6d, 0x62, 0x75, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x43, 0x61, 0x69, 0x72, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x43, 0x61, 0x73, 0x61, 0x62, 0x6c, 0x61, 0x6e, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x43, 0x65, 0x75, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x43, 0x6f, 0x6e, 0x61, 0x6b, 0x72, 0x79, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x44, 0x61, 0x6b, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44,
|
||||||
|
0x61, 0x72, 0x5f, 0x65, 0x73, 0x5f, 0x53, 0x61, 0x6c, 0x61, 0x61, 0x6d, 0x0d, 0x0a, 0x41, 0x66,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x41,
|
||||||
|
0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x75, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x66,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x41, 0x61, 0x69, 0x75, 0x6e, 0x0d, 0x0a, 0x41,
|
||||||
|
0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x72, 0x65, 0x65, 0x74, 0x6f, 0x77, 0x6e, 0x0d, 0x0a,
|
||||||
|
0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x6e, 0x65, 0x0d,
|
||||||
|
0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x61, 0x72, 0x65, 0x0d, 0x0a,
|
||||||
|
0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x6f, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x62,
|
||||||
|
0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x62, 0x61,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x70, 0x61, 0x6c, 0x61,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x68, 0x61, 0x72, 0x74, 0x6f, 0x75,
|
||||||
|
0x6d, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x67, 0x61, 0x6c, 0x69,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73,
|
||||||
|
0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x67, 0x6f, 0x73, 0x0d,
|
||||||
|
0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x76, 0x69, 0x6c,
|
||||||
|
0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x6d, 0x65, 0x0d,
|
||||||
|
0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x61, 0x6e, 0x64, 0x61, 0x0d, 0x0a,
|
||||||
|
0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x62, 0x75, 0x6d, 0x62, 0x61, 0x73, 0x68,
|
||||||
|
0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x73, 0x61, 0x6b, 0x61,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6c, 0x61, 0x62, 0x6f, 0x0d,
|
||||||
|
0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x70, 0x75, 0x74, 0x6f, 0x0d, 0x0a,
|
||||||
|
0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x73, 0x65, 0x72, 0x75, 0x0d, 0x0a, 0x41,
|
||||||
|
0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x62, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41,
|
||||||
|
0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x67, 0x61, 0x64, 0x69, 0x73, 0x68, 0x75, 0x0d,
|
||||||
|
0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x72, 0x6f, 0x76, 0x69, 0x61,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x69, 0x72, 0x6f, 0x62, 0x69,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x64, 0x6a, 0x61, 0x6d, 0x65, 0x6e,
|
||||||
|
0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x61, 0x6d, 0x65, 0x79,
|
||||||
|
0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x75, 0x61, 0x6b, 0x63, 0x68,
|
||||||
|
0x6f, 0x74, 0x74, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x75, 0x61, 0x67,
|
||||||
|
0x61, 0x64, 0x6f, 0x75, 0x67, 0x6f, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x50, 0x6f, 0x72, 0x74, 0x6f, 0x2d, 0x4e, 0x6f, 0x76, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f, 0x5f, 0x54, 0x6f, 0x6d, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6d, 0x62, 0x75, 0x6b, 0x74, 0x75, 0x0d, 0x0a, 0x41, 0x66,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x72, 0x69, 0x70, 0x6f, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x66,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x64, 0x68, 0x6f, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x61, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c, 0x6c, 0x61, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x0d,
|
||||||
|
0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x61, 0x67, 0x75, 0x61, 0x69,
|
||||||
|
0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x75, 0x62,
|
||||||
|
0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x75, 0x6e, 0x63,
|
||||||
|
0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x74, 0x69,
|
||||||
|
0x6b, 0x6f, 0x6b, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41,
|
||||||
|
0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68,
|
||||||
|
0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x69,
|
||||||
|
0x61, 0x5f, 0x42, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x63, 0x2d, 0x53, 0x61, 0x62, 0x6c, 0x6f,
|
||||||
|
0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x61, 0x5f, 0x56,
|
||||||
|
0x69, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f,
|
||||||
|
0x67, 0x6f, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f,
|
||||||
|
0x69, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65,
|
||||||
|
0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x42, 0x61, 0x79,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x6f, 0x5f,
|
||||||
|
0x47, 0x72, 0x61, 0x6e, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x43, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x43, 0x61, 0x72, 0x61, 0x63, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61, 0x0d,
|
||||||
|
0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x48,
|
||||||
|
0x61, 0x72, 0x62, 0x6f, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x5f, 0x52, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x61, 0x63, 0x61, 0x6f, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x68,
|
||||||
|
0x61, 0x76, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77,
|
||||||
|
0x73, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77,
|
||||||
|
0x73, 0x6f, 0x6e, 0x5f, 0x43, 0x72, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x44, 0x65, 0x74, 0x72, 0x6f, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x64, 0x6d, 0x6f, 0x6e, 0x74, 0x6f, 0x6e, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x69, 0x72, 0x75, 0x6e, 0x65, 0x70, 0x65,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x53, 0x61, 0x6c,
|
||||||
|
0x76, 0x61, 0x64, 0x6f, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45,
|
||||||
|
0x6e, 0x73, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x46, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x65, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x4e, 0x65, 0x6c, 0x73, 0x6f, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x57, 0x61,
|
||||||
|
0x79, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6c, 0x61,
|
||||||
|
0x63, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x47, 0x6f, 0x64, 0x74, 0x68, 0x61, 0x62, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x47, 0x6f, 0x6f, 0x73, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x54, 0x75, 0x72, 0x6b, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d,
|
||||||
|
0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f,
|
||||||
|
0x75, 0x70, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61,
|
||||||
|
0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x47, 0x75, 0x61, 0x79, 0x61, 0x71, 0x75, 0x69, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x76, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x48, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x69, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70,
|
||||||
|
0x6f, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
|
||||||
|
0x75, 0x76, 0x69, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x71,
|
||||||
|
0x61, 0x6c, 0x75, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a,
|
||||||
|
0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a,
|
||||||
|
0x75, 0x6e, 0x65, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b,
|
||||||
|
0x6e, 0x6f, 0x78, 0x5f, 0x49, 0x4e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x4b, 0x72, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6a, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x50, 0x61, 0x7a, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x4c, 0x6f, 0x73, 0x5f, 0x41, 0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c,
|
||||||
|
0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x77, 0x65, 0x72,
|
||||||
|
0x5f, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x4d, 0x61, 0x63, 0x65, 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x75, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x67, 0x6f, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x72, 0x6f,
|
||||||
|
0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x7a, 0x61, 0x74,
|
||||||
|
0x6c, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x6e,
|
||||||
|
0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65,
|
||||||
|
0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x4d, 0x65, 0x72, 0x69, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x4d, 0x65, 0x74, 0x6c, 0x61, 0x6b, 0x61, 0x74, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c,
|
||||||
|
0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x63,
|
||||||
|
0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e,
|
||||||
|
0x74, 0x65, 0x72, 0x72, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x72, 0x65, 0x61, 0x6c, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x73, 0x73, 0x61, 0x75,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x59, 0x6f,
|
||||||
|
0x72, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x70, 0x69,
|
||||||
|
0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x6d,
|
||||||
|
0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x6f, 0x6e,
|
||||||
|
0x68, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x6a, 0x69, 0x6e,
|
||||||
|
0x61, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
|
||||||
|
0x61, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e,
|
||||||
|
0x67, 0x6e, 0x69, 0x72, 0x74, 0x75, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x61, 0x72, 0x69, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x68, 0x6f, 0x65, 0x6e, 0x69, 0x78, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x2d, 0x61, 0x75, 0x2d, 0x50,
|
||||||
|
0x72, 0x69, 0x6e, 0x63, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50,
|
||||||
|
0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x56, 0x65, 0x6c, 0x68, 0x6f, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x5f,
|
||||||
|
0x53, 0x70, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50,
|
||||||
|
0x75, 0x65, 0x72, 0x74, 0x6f, 0x5f, 0x52, 0x69, 0x63, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x6e, 0x74, 0x61, 0x5f, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x61, 0x69, 0x6e, 0x79, 0x5f,
|
||||||
|
0x52, 0x69, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52,
|
||||||
|
0x61, 0x6e, 0x6b, 0x69, 0x6e, 0x5f, 0x49, 0x6e, 0x6c, 0x65, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x63, 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x67, 0x69, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x42, 0x72, 0x61, 0x6e, 0x63,
|
||||||
|
0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x73, 0x61, 0x72,
|
||||||
|
0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74,
|
||||||
|
0x61, 0x72, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61,
|
||||||
|
0x6e, 0x74, 0x61, 0x5f, 0x49, 0x73, 0x61, 0x62, 0x65, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x6f, 0x5f, 0x44, 0x6f, 0x6d, 0x69,
|
||||||
|
0x6e, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f,
|
||||||
|
0x5f, 0x50, 0x61, 0x75, 0x6c, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x73, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x68, 0x69, 0x70, 0x72, 0x6f, 0x63, 0x6b, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x69, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x42, 0x61, 0x72, 0x74, 0x68, 0x65,
|
||||||
|
0x6c, 0x65, 0x6d, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74,
|
||||||
|
0x5f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x53, 0x74, 0x5f, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e,
|
||||||
|
0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x77, 0x69, 0x66, 0x74,
|
||||||
|
0x5f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x54, 0x65, 0x67, 0x75, 0x63, 0x69, 0x67, 0x61, 0x6c, 0x70, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6d,
|
||||||
|
0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x42, 0x61,
|
||||||
|
0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61,
|
||||||
|
0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x6f,
|
||||||
|
0x6e, 0x74, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72,
|
||||||
|
0x74, 0x6f, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x61,
|
||||||
|
0x6e, 0x63, 0x6f, 0x75, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65,
|
||||||
|
0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x6e, 0x69, 0x70, 0x65, 0x67, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x61, 0x74, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6b, 0x6e,
|
||||||
|
0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67,
|
||||||
|
0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69,
|
||||||
|
0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67,
|
||||||
|
0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74,
|
||||||
|
0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x52, 0x69, 0x76, 0x61, 0x64, 0x61, 0x76,
|
||||||
|
0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
|
||||||
|
0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
|
||||||
|
0x2f, 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x52, 0x69, 0x6f,
|
||||||
|
0x6a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
|
||||||
|
0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
|
||||||
|
0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x47, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61,
|
||||||
|
0x2f, 0x53, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4a, 0x75,
|
||||||
|
0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65,
|
||||||
|
0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4c, 0x75, 0x69, 0x73, 0x0d, 0x0a,
|
||||||
|
0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e,
|
||||||
|
0x61, 0x2f, 0x54, 0x75, 0x63, 0x75, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x55, 0x73, 0x68,
|
||||||
|
0x75, 0x61, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e,
|
||||||
|
0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c,
|
||||||
|
0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69,
|
||||||
|
0x61, 0x6e, 0x61, 0x2f, 0x4b, 0x6e, 0x6f, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x65, 0x6e, 0x67,
|
||||||
|
0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61,
|
||||||
|
0x6e, 0x61, 0x2f, 0x50, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x54,
|
||||||
|
0x65, 0x6c, 0x6c, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x65, 0x76, 0x61, 0x79, 0x0d,
|
||||||
|
0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61,
|
||||||
|
0x2f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x61,
|
||||||
|
0x6d, 0x61, 0x63, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e,
|
||||||
|
0x74, 0x75, 0x63, 0x6b, 0x79, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c, 0x65,
|
||||||
|
0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e, 0x74, 0x75, 0x63,
|
||||||
|
0x6b, 0x79, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x69, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a, 0x41,
|
||||||
|
0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b,
|
||||||
|
0x6f, 0x74, 0x61, 0x2f, 0x42, 0x65, 0x75, 0x6c, 0x61, 0x68, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61,
|
||||||
|
0x2f, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61,
|
||||||
|
0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x4e, 0x65,
|
||||||
|
0x77, 0x5f, 0x53, 0x61, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74,
|
||||||
|
0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72,
|
||||||
|
0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x76, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6e, 0x74,
|
||||||
|
0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x75, 0x6d, 0x6f, 0x6e, 0x74, 0x44, 0x55,
|
||||||
|
0x72, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x71, 0x75, 0x61, 0x72, 0x69, 0x65, 0x0d, 0x0a, 0x41, 0x6e,
|
||||||
|
0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x63, 0x4d, 0x75,
|
||||||
|
0x72, 0x64, 0x6f, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x50, 0x61, 0x6c, 0x6d, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69,
|
||||||
|
0x63, 0x61, 0x2f, 0x52, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61,
|
||||||
|
0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f, 0x50, 0x6f, 0x6c,
|
||||||
|
0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x79,
|
||||||
|
0x6f, 0x77, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f,
|
||||||
|
0x54, 0x72, 0x6f, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63,
|
||||||
|
0x61, 0x2f, 0x56, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x72, 0x63, 0x74, 0x69, 0x63,
|
||||||
|
0x2f, 0x4c, 0x6f, 0x6e, 0x67, 0x79, 0x65, 0x61, 0x72, 0x62, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41,
|
||||||
|
0x6c, 0x6d, 0x61, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6d, 0x6d, 0x61,
|
||||||
|
0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6e, 0x61, 0x64, 0x79, 0x72, 0x0d, 0x0a,
|
||||||
|
0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71, 0x74, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x41, 0x71, 0x74, 0x6f, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73,
|
||||||
|
0x68, 0x67, 0x61, 0x62, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73, 0x68,
|
||||||
|
0x6b, 0x68, 0x61, 0x62, 0x61, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x74, 0x79,
|
||||||
|
0x72, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x67, 0x68, 0x64, 0x61,
|
||||||
|
0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x72, 0x61, 0x69, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6b, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x42, 0x61, 0x6e, 0x67, 0x6b, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42,
|
||||||
|
0x61, 0x72, 0x6e, 0x61, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x65, 0x69,
|
||||||
|
0x72, 0x75, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x68, 0x6b, 0x65,
|
||||||
|
0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x0d, 0x0a,
|
||||||
|
0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x74, 0x74, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
|
||||||
|
0x43, 0x68, 0x6f, 0x69, 0x62, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x43, 0x68, 0x6f, 0x6e, 0x67, 0x71, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x43, 0x68, 0x75, 0x6e, 0x67, 0x6b, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44,
|
||||||
|
0x61, 0x63, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x6d, 0x61, 0x73,
|
||||||
|
0x63, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x68, 0x61, 0x6b, 0x61, 0x0d,
|
||||||
|
0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x69, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x44, 0x75, 0x62, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x73,
|
||||||
|
0x68, 0x61, 0x6e, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x46, 0x61, 0x6d, 0x61,
|
||||||
|
0x67, 0x75, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x47, 0x61, 0x7a, 0x61,
|
||||||
|
0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x62, 0x69, 0x6e, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x48, 0x6f, 0x6e, 0x67, 0x5f, 0x4b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x48, 0x6f, 0x76, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x5f, 0x43,
|
||||||
|
0x68, 0x69, 0x5f, 0x4d, 0x69, 0x6e, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x72,
|
||||||
|
0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x73, 0x74, 0x61,
|
||||||
|
0x6e, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x6b, 0x61, 0x72,
|
||||||
|
0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x79, 0x61, 0x70, 0x75, 0x72,
|
||||||
|
0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x65, 0x72, 0x75, 0x73, 0x61, 0x6c, 0x65,
|
||||||
|
0x6d, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x72, 0x61, 0x63, 0x68, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69,
|
||||||
|
0x61, 0x2f, 0x4b, 0x61, 0x73, 0x68, 0x67, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
|
||||||
|
0x4b, 0x61, 0x74, 0x68, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
|
||||||
|
0x4b, 0x61, 0x74, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b,
|
||||||
|
0x68, 0x61, 0x6e, 0x64, 0x79, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x6f,
|
||||||
|
0x6c, 0x6b, 0x61, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73,
|
||||||
|
0x6e, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75,
|
||||||
|
0x61, 0x6c, 0x61, 0x5f, 0x4c, 0x75, 0x6d, 0x70, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x4b, 0x75, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b,
|
||||||
|
0x75, 0x77, 0x61, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61,
|
||||||
|
0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69,
|
||||||
|
0x61, 0x2f, 0x4d, 0x61, 0x6b, 0x61, 0x73, 0x73, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x4d, 0x61, 0x6e, 0x69, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x75,
|
||||||
|
0x73, 0x63, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73,
|
||||||
|
0x69, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x6b, 0x75, 0x7a,
|
||||||
|
0x6e, 0x65, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f,
|
||||||
|
0x73, 0x69, 0x62, 0x69, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x6d,
|
||||||
|
0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x50, 0x68, 0x6e, 0x6f, 0x6d, 0x5f, 0x50, 0x65, 0x6e, 0x68, 0x0d, 0x0a,
|
||||||
|
0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x6f, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x61, 0x6b, 0x0d, 0x0a,
|
||||||
|
0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x79, 0x6f, 0x6e, 0x67, 0x79, 0x61, 0x6e, 0x67, 0x0d, 0x0a,
|
||||||
|
0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x61, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x52, 0x61, 0x6e, 0x67, 0x6f, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52,
|
||||||
|
0x69, 0x79, 0x61, 0x64, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x69, 0x67,
|
||||||
|
0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69,
|
||||||
|
0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x6e,
|
||||||
|
0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x65, 0x6f, 0x75, 0x6c, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x53, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73,
|
||||||
|
0x69, 0x61, 0x2f, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x73,
|
||||||
|
0x69, 0x61, 0x2f, 0x53, 0x72, 0x65, 0x64, 0x6e, 0x65, 0x6b, 0x6f, 0x6c, 0x79, 0x6d, 0x73, 0x6b,
|
||||||
|
0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x73,
|
||||||
|
0x69, 0x61, 0x2f, 0x54, 0x62, 0x69, 0x6c, 0x69, 0x73, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61,
|
||||||
|
0x2f, 0x54, 0x65, 0x68, 0x72, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x65,
|
||||||
|
0x6c, 0x5f, 0x41, 0x76, 0x69, 0x76, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69,
|
||||||
|
0x6d, 0x62, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, 0x6d, 0x70, 0x68,
|
||||||
|
0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
|
||||||
|
0x55, 0x6a, 0x75, 0x6e, 0x67, 0x5f, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x67, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x0d,
|
||||||
|
0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x6e, 0x5f, 0x42, 0x61, 0x74, 0x6f, 0x72,
|
||||||
|
0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x72, 0x75, 0x6d, 0x71, 0x69, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x55, 0x73, 0x74, 0x2d, 0x4e, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x73,
|
||||||
|
0x69, 0x61, 0x2f, 0x56, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x73,
|
||||||
|
0x69, 0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a,
|
||||||
|
0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73,
|
||||||
|
0x69, 0x61, 0x2f, 0x59, 0x61, 0x6e, 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f,
|
||||||
|
0x59, 0x65, 0x6b, 0x61, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41,
|
||||||
|
0x73, 0x69, 0x61, 0x2f, 0x59, 0x65, 0x72, 0x65, 0x76, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c,
|
||||||
|
0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x74,
|
||||||
|
0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x0d, 0x0a,
|
||||||
|
0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x0d,
|
||||||
|
0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x70, 0x65, 0x5f, 0x56,
|
||||||
|
0x65, 0x72, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x46,
|
||||||
|
0x61, 0x65, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
|
||||||
|
0x46, 0x61, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f,
|
||||||
|
0x4a, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e,
|
||||||
|
0x74, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x64, 0x65, 0x69, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c,
|
||||||
|
0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x52, 0x65, 0x79, 0x6b, 0x6a, 0x61, 0x76, 0x69, 0x6b, 0x0d,
|
||||||
|
0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f,
|
||||||
|
0x47, 0x65, 0x6f, 0x72, 0x67, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69,
|
||||||
|
0x63, 0x2f, 0x53, 0x74, 0x61, 0x6e, 0x6c, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e,
|
||||||
|
0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x5f, 0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x0d, 0x0a, 0x41,
|
||||||
|
0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x43, 0x54, 0x0d, 0x0a, 0x41, 0x75,
|
||||||
|
0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x65,
|
||||||
|
0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x69, 0x73,
|
||||||
|
0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
|
||||||
|
0x42, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x48, 0x69, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x75, 0x73,
|
||||||
|
0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6e, 0x62, 0x65, 0x72, 0x72, 0x61, 0x0d,
|
||||||
|
0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x72, 0x69,
|
||||||
|
0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x72,
|
||||||
|
0x77, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x45,
|
||||||
|
0x75, 0x63, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
|
||||||
|
0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69,
|
||||||
|
0x61, 0x2f, 0x4c, 0x48, 0x49, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
|
||||||
|
0x2f, 0x4c, 0x69, 0x6e, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72,
|
||||||
|
0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4c, 0x6f, 0x72, 0x64, 0x5f, 0x48, 0x6f, 0x77, 0x65, 0x0d, 0x0a,
|
||||||
|
0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75,
|
||||||
|
0x72, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4e,
|
||||||
|
0x6f, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
|
||||||
|
0x4e, 0x53, 0x57, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x50,
|
||||||
|
0x65, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f,
|
||||||
|
0x51, 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74,
|
||||||
|
0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73,
|
||||||
|
0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64, 0x6e, 0x65, 0x79, 0x0d, 0x0a, 0x41,
|
||||||
|
0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x6d, 0x61, 0x6e, 0x69,
|
||||||
|
0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x56, 0x69, 0x63,
|
||||||
|
0x74, 0x6f, 0x72, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
|
||||||
|
0x2f, 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61,
|
||||||
|
0x2f, 0x59, 0x61, 0x6e, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61,
|
||||||
|
0x7a, 0x69, 0x6c, 0x2f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c,
|
||||||
|
0x2f, 0x44, 0x65, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, 0x68, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a,
|
||||||
|
0x69, 0x6c, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c, 0x2f,
|
||||||
|
0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x41, 0x74, 0x6c,
|
||||||
|
0x61, 0x6e, 0x74, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x43, 0x65,
|
||||||
|
0x6e, 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61,
|
||||||
|
0x73, 0x74, 0x2d, 0x53, 0x61, 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e,
|
||||||
|
0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x66, 0x6f, 0x75, 0x6e,
|
||||||
|
0x64, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x50, 0x61,
|
||||||
|
0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x53, 0x61,
|
||||||
|
0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61,
|
||||||
|
0x64, 0x61, 0x2f, 0x59, 0x75, 0x6b, 0x6f, 0x6e, 0x0d, 0x0a, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x2f,
|
||||||
|
0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x68, 0x69,
|
||||||
|
0x6c, 0x65, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d,
|
||||||
|
0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
|
||||||
|
0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x0d, 0x0a,
|
||||||
|
0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f,
|
||||||
|
0x47, 0x4d, 0x54, 0x2b, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b,
|
||||||
|
0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x32, 0x0d, 0x0a, 0x45,
|
||||||
|
0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
|
||||||
|
0x54, 0x2b, 0x34, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x35, 0x0d, 0x0a,
|
||||||
|
0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47,
|
||||||
|
0x4d, 0x54, 0x2b, 0x37, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x38, 0x0d,
|
||||||
|
0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f,
|
||||||
|
0x47, 0x4d, 0x54, 0x2d, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31,
|
||||||
|
0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74,
|
||||||
|
0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
|
||||||
|
0x54, 0x2d, 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x33,
|
||||||
|
0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x34, 0x0d, 0x0a, 0x45, 0x74,
|
||||||
|
0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54,
|
||||||
|
0x2d, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x34, 0x0d, 0x0a, 0x45,
|
||||||
|
0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x35, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d,
|
||||||
|
0x54, 0x2d, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x37, 0x0d, 0x0a,
|
||||||
|
0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x38, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47,
|
||||||
|
0x4d, 0x54, 0x2d, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a,
|
||||||
|
0x45, 0x74, 0x63, 0x2f, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x45,
|
||||||
|
0x74, 0x63, 0x2f, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x6e, 0x69, 0x76,
|
||||||
|
0x65, 0x72, 0x73, 0x61, 0x6c, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x0d, 0x0a,
|
||||||
|
0x45, 0x74, 0x63, 0x2f, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
|
||||||
|
0x2f, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
|
||||||
|
0x70, 0x65, 0x2f, 0x41, 0x6e, 0x64, 0x6f, 0x72, 0x72, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
|
||||||
|
0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75,
|
||||||
|
0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72,
|
||||||
|
0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x66, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72,
|
||||||
|
0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x45, 0x75,
|
||||||
|
0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72,
|
||||||
|
0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x0d, 0x0a,
|
||||||
|
0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x75, 0x73, 0x73, 0x65, 0x6c, 0x73, 0x0d,
|
||||||
|
0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x63, 0x68, 0x61, 0x72, 0x65, 0x73,
|
||||||
|
0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65,
|
||||||
|
0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x73, 0x69, 0x6e,
|
||||||
|
0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x68, 0x69, 0x73,
|
||||||
|
0x69, 0x6e, 0x61, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x6f, 0x70,
|
||||||
|
0x65, 0x6e, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
|
||||||
|
0x44, 0x75, 0x62, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47,
|
||||||
|
0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
|
||||||
|
0x2f, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
|
||||||
|
0x65, 0x2f, 0x48, 0x65, 0x6c, 0x73, 0x69, 0x6e, 0x6b, 0x69, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f,
|
||||||
|
0x70, 0x65, 0x2f, 0x49, 0x73, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x4d, 0x61, 0x6e, 0x0d, 0x0a,
|
||||||
|
0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x0d,
|
||||||
|
0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x0d, 0x0a,
|
||||||
|
0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x61, 0x6c, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72,
|
||||||
|
0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x0d,
|
||||||
|
0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x72, 0x6f, 0x76, 0x0d, 0x0a, 0x45,
|
||||||
|
0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x69, 0x73, 0x62, 0x6f, 0x6e, 0x0d, 0x0a, 0x45, 0x75,
|
||||||
|
0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6a, 0x75, 0x62, 0x6c, 0x6a, 0x61, 0x6e, 0x61, 0x0d, 0x0a,
|
||||||
|
0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x0d, 0x0a, 0x45,
|
||||||
|
0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67,
|
||||||
|
0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x72, 0x69, 0x64, 0x0d,
|
||||||
|
0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x45,
|
||||||
|
0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x65, 0x68, 0x61, 0x6d, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x73, 0x6b, 0x0d, 0x0a, 0x45,
|
||||||
|
0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x0d, 0x0a, 0x45, 0x75,
|
||||||
|
0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72,
|
||||||
|
0x6f, 0x70, 0x65, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72,
|
||||||
|
0x6f, 0x70, 0x65, 0x2f, 0x4f, 0x73, 0x6c, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
|
||||||
|
0x2f, 0x50, 0x61, 0x72, 0x69, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50,
|
||||||
|
0x6f, 0x64, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
|
||||||
|
0x2f, 0x50, 0x72, 0x61, 0x67, 0x75, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
|
||||||
|
0x52, 0x69, 0x67, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x6f, 0x6d,
|
||||||
|
0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x61,
|
||||||
|
0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x72,
|
||||||
|
0x69, 0x6e, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61,
|
||||||
|
0x6a, 0x65, 0x76, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72,
|
||||||
|
0x61, 0x74, 0x6f, 0x76, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x69, 0x6d,
|
||||||
|
0x66, 0x65, 0x72, 0x6f, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
|
||||||
|
0x53, 0x6b, 0x6f, 0x70, 0x6a, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53,
|
||||||
|
0x6f, 0x66, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x74, 0x6f,
|
||||||
|
0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54,
|
||||||
|
0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54,
|
||||||
|
0x69, 0x72, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, 0x69,
|
||||||
|
0x72, 0x61, 0x73, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55,
|
||||||
|
0x6c, 0x79, 0x61, 0x6e, 0x6f, 0x76, 0x73, 0x6b, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
|
||||||
|
0x2f, 0x55, 0x7a, 0x68, 0x67, 0x6f, 0x72, 0x6f, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
|
||||||
|
0x65, 0x2f, 0x56, 0x61, 0x64, 0x75, 0x7a, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
|
||||||
|
0x56, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
|
||||||
|
0x56, 0x69, 0x65, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56,
|
||||||
|
0x69, 0x6c, 0x6e, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56,
|
||||||
|
0x6f, 0x6c, 0x67, 0x6f, 0x67, 0x72, 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65,
|
||||||
|
0x2f, 0x57, 0x61, 0x72, 0x73, 0x61, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f,
|
||||||
|
0x5a, 0x61, 0x67, 0x72, 0x65, 0x62, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a,
|
||||||
|
0x61, 0x70, 0x6f, 0x72, 0x6f, 0x7a, 0x68, 0x79, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70,
|
||||||
|
0x65, 0x2f, 0x5a, 0x75, 0x72, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e,
|
||||||
|
0x2f, 0x41, 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x76, 0x6f, 0x0d, 0x0a, 0x49,
|
||||||
|
0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e,
|
||||||
|
0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73, 0x0d, 0x0a,
|
||||||
|
0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e,
|
||||||
|
0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x6f, 0x0d, 0x0a, 0x49, 0x6e, 0x64,
|
||||||
|
0x69, 0x61, 0x6e, 0x2f, 0x4b, 0x65, 0x72, 0x67, 0x75, 0x65, 0x6c, 0x65, 0x6e, 0x0d, 0x0a, 0x49,
|
||||||
|
0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x68, 0x65, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69,
|
||||||
|
0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x0d, 0x0a, 0x49, 0x6e, 0x64,
|
||||||
|
0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x49,
|
||||||
|
0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x0d, 0x0a, 0x49,
|
||||||
|
0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x52, 0x65, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x4d,
|
||||||
|
0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x4e, 0x6f, 0x72, 0x74, 0x65, 0x0d,
|
||||||
|
0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x53, 0x75, 0x72, 0x0d,
|
||||||
|
0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x0d,
|
||||||
|
0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x70, 0x69, 0x61, 0x0d, 0x0a, 0x50,
|
||||||
|
0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x75, 0x63, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x0d,
|
||||||
|
0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x42, 0x6f, 0x75, 0x67, 0x61, 0x69, 0x6e,
|
||||||
|
0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x43,
|
||||||
|
0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
|
||||||
|
0x43, 0x68, 0x75, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45,
|
||||||
|
0x61, 0x73, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45,
|
||||||
|
0x66, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x6e,
|
||||||
|
0x64, 0x65, 0x72, 0x62, 0x75, 0x72, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
|
||||||
|
0x2f, 0x46, 0x61, 0x6b, 0x61, 0x6f, 0x66, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
|
||||||
|
0x63, 0x2f, 0x46, 0x69, 0x6a, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
|
||||||
|
0x46, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
|
||||||
|
0x63, 0x2f, 0x47, 0x61, 0x6c, 0x61, 0x70, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63,
|
||||||
|
0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61,
|
||||||
|
0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x61, 0x6c, 0x63, 0x61, 0x6e, 0x61,
|
||||||
|
0x6c, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x6d, 0x0d,
|
||||||
|
0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x48, 0x6f, 0x6e, 0x6f, 0x6c, 0x75, 0x6c,
|
||||||
|
0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4a, 0x6f, 0x68, 0x6e, 0x73,
|
||||||
|
0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x69, 0x72,
|
||||||
|
0x69, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
|
||||||
|
0x2f, 0x4b, 0x6f, 0x73, 0x72, 0x61, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
|
||||||
|
0x2f, 0x4b, 0x77, 0x61, 0x6a, 0x61, 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
|
||||||
|
0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x6a, 0x75, 0x72, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
|
||||||
|
0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x0d, 0x0a, 0x50,
|
||||||
|
0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x69, 0x64, 0x77, 0x61, 0x79, 0x0d, 0x0a, 0x50,
|
||||||
|
0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x0d, 0x0a, 0x50, 0x61,
|
||||||
|
0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x69, 0x75, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69,
|
||||||
|
0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63,
|
||||||
|
0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x75, 0x6d, 0x65, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63,
|
||||||
|
0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x67, 0x6f, 0x5f, 0x50, 0x61, 0x67, 0x6f, 0x0d, 0x0a,
|
||||||
|
0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x0d, 0x0a, 0x50,
|
||||||
|
0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x0d,
|
||||||
|
0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x68, 0x6e, 0x70, 0x65, 0x69,
|
||||||
|
0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x6e, 0x61, 0x70, 0x65,
|
||||||
|
0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x4d,
|
||||||
|
0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f,
|
||||||
|
0x52, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
|
||||||
|
0x69, 0x63, 0x2f, 0x53, 0x61, 0x69, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
|
||||||
|
0x69, 0x63, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
|
||||||
|
0x63, 0x2f, 0x54, 0x61, 0x68, 0x69, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
|
||||||
|
0x63, 0x2f, 0x54, 0x61, 0x72, 0x61, 0x77, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
|
||||||
|
0x63, 0x2f, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x74, 0x61, 0x70, 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63,
|
||||||
|
0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x72, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66,
|
||||||
|
0x69, 0x63, 0x2f, 0x57, 0x61, 0x6b, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
|
||||||
|
0x2f, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63,
|
||||||
|
0x2f, 0x59, 0x61, 0x70, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x61, 0x73, 0x6b, 0x61, 0x0d,
|
||||||
|
0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53,
|
||||||
|
0x2f, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x43, 0x65, 0x6e,
|
||||||
|
0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x2d, 0x49, 0x6e,
|
||||||
|
0x64, 0x69, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72,
|
||||||
|
0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x48, 0x61, 0x77, 0x61, 0x69, 0x69, 0x0d, 0x0a, 0x55, 0x53,
|
||||||
|
0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2d, 0x53, 0x74, 0x61, 0x72, 0x6b, 0x65, 0x0d,
|
||||||
|
0x0a, 0x55, 0x53, 0x2f, 0x4d, 0x69, 0x63, 0x68, 0x69, 0x67, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53,
|
||||||
|
0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61,
|
||||||
|
0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69,
|
||||||
|
0x63, 0x2d, 0x4e, 0x65, 0x77, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d,
|
||||||
|
0x0a};
|
||||||
|
|
||||||
|
static VirtualFile GenerateDefaultTimeZoneFile() {
|
||||||
|
struct {
|
||||||
|
s64_be at;
|
||||||
|
INSERT_PADDING_BYTES(7);
|
||||||
|
std::array<char, 4> time_zone_chars;
|
||||||
|
INSERT_PADDING_BYTES(2);
|
||||||
|
std::array<char, 6> time_zone_name;
|
||||||
|
} time_zone_info{};
|
||||||
|
|
||||||
|
const VirtualFile file{std::make_shared<VectorVfsFile>(
|
||||||
|
std::vector<u8>(sizeof(Service::Time::TimeZone::TzifHeader) + sizeof(time_zone_info)),
|
||||||
|
"GMT")};
|
||||||
|
|
||||||
|
Service::Time::TimeZone::TzifHeader header{};
|
||||||
|
header.magic = 0x545a6966;
|
||||||
|
header.version = 0x32;
|
||||||
|
header.ttis_gmt_count = 0x1;
|
||||||
|
header.ttis_std_count = 0x1;
|
||||||
|
header.time_count = 0x1;
|
||||||
|
header.type_count = 0x1;
|
||||||
|
header.char_count = 0x4;
|
||||||
|
file->WriteObject(header, 0);
|
||||||
|
|
||||||
|
time_zone_info.at = 0xf8;
|
||||||
|
time_zone_info.time_zone_chars = {'G', 'M', 'T', '\0'};
|
||||||
|
time_zone_info.time_zone_name = {'\n', 'G', 'M', 'T', '0', '\n'};
|
||||||
|
file->WriteObject(time_zone_info, sizeof(Service::Time::TimeZone::TzifHeader));
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
VirtualDir TimeZoneBinary() {
|
||||||
|
const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||||
|
std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
|
||||||
|
"zoneinfo")};
|
||||||
|
const std::vector<VirtualFile> root_files{
|
||||||
|
std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")};
|
||||||
|
return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace FileSys::SystemArchive
|
14
src/core/file_sys/system_archive/time_zone_binary.h
Normal file
14
src/core/file_sys/system_archive/time_zone_binary.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include "core/file_sys/vfs_types.h"
|
||||||
|
|
||||||
|
namespace FileSys::SystemArchive {
|
||||||
|
|
||||||
|
VirtualDir TimeZoneBinary();
|
||||||
|
|
||||||
|
} // namespace FileSys::SystemArchive
|
|
@ -211,7 +211,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileManager& profile_manager;
|
ProfileManager& profile_manager;
|
||||||
Common::UUID user_id; ///< The user id this profile refers to.
|
Common::UUID user_id{Common::INVALID_UUID}; ///< The user id this profile refers to.
|
||||||
};
|
};
|
||||||
|
|
||||||
class IProfile final : public IProfileCommon {
|
class IProfile final : public IProfileCommon {
|
||||||
|
|
|
@ -16,17 +16,17 @@ namespace Service::Account {
|
||||||
using Common::UUID;
|
using Common::UUID;
|
||||||
|
|
||||||
struct UserRaw {
|
struct UserRaw {
|
||||||
UUID uuid;
|
UUID uuid{Common::INVALID_UUID};
|
||||||
UUID uuid2;
|
UUID uuid2{Common::INVALID_UUID};
|
||||||
u64 timestamp;
|
u64 timestamp{};
|
||||||
ProfileUsername username;
|
ProfileUsername username{};
|
||||||
ProfileData extra_data;
|
ProfileData extra_data{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
|
static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size.");
|
||||||
|
|
||||||
struct ProfileDataRaw {
|
struct ProfileDataRaw {
|
||||||
INSERT_PADDING_BYTES(0x10);
|
INSERT_PADDING_BYTES(0x10);
|
||||||
std::array<UserRaw, MAX_USERS> users;
|
std::array<UserRaw, MAX_USERS> users{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size.");
|
static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size.");
|
||||||
|
|
||||||
|
@ -238,7 +238,7 @@ UserIDArray ProfileManager::GetOpenUsers() const {
|
||||||
std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) {
|
std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) {
|
||||||
if (p.is_open)
|
if (p.is_open)
|
||||||
return p.user_uuid;
|
return p.user_uuid;
|
||||||
return UUID{};
|
return UUID{Common::INVALID_UUID};
|
||||||
});
|
});
|
||||||
std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; });
|
std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; });
|
||||||
return output;
|
return output;
|
||||||
|
|
|
@ -13,9 +13,10 @@
|
||||||
#include "core/hle/result.h"
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
namespace Service::Account {
|
namespace Service::Account {
|
||||||
constexpr std::size_t MAX_USERS = 8;
|
|
||||||
|
|
||||||
constexpr std::size_t profile_username_size = 32;
|
constexpr std::size_t MAX_USERS{8};
|
||||||
|
constexpr std::size_t profile_username_size{32};
|
||||||
|
|
||||||
using ProfileUsername = std::array<u8, profile_username_size>;
|
using ProfileUsername = std::array<u8, profile_username_size>;
|
||||||
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
|
using UserIDArray = std::array<Common::UUID, MAX_USERS>;
|
||||||
|
|
||||||
|
@ -23,8 +24,8 @@ using UserIDArray = std::array<Common::UUID, MAX_USERS>;
|
||||||
/// TODO: RE this structure
|
/// TODO: RE this structure
|
||||||
struct ProfileData {
|
struct ProfileData {
|
||||||
INSERT_PADDING_WORDS(1);
|
INSERT_PADDING_WORDS(1);
|
||||||
u32 icon_id;
|
u32 icon_id{};
|
||||||
u8 bg_color_id;
|
u8 bg_color_id{};
|
||||||
INSERT_PADDING_BYTES(0x7);
|
INSERT_PADDING_BYTES(0x7);
|
||||||
INSERT_PADDING_BYTES(0x10);
|
INSERT_PADDING_BYTES(0x10);
|
||||||
INSERT_PADDING_BYTES(0x60);
|
INSERT_PADDING_BYTES(0x60);
|
||||||
|
@ -34,17 +35,17 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect
|
||||||
/// This holds general information about a users profile. This is where we store all the information
|
/// This holds general information about a users profile. This is where we store all the information
|
||||||
/// based on a specific user
|
/// based on a specific user
|
||||||
struct ProfileInfo {
|
struct ProfileInfo {
|
||||||
Common::UUID user_uuid;
|
Common::UUID user_uuid{Common::INVALID_UUID};
|
||||||
ProfileUsername username;
|
ProfileUsername username{};
|
||||||
u64 creation_time;
|
u64 creation_time{};
|
||||||
ProfileData data; // TODO(ognik): Work out what this is
|
ProfileData data{}; // TODO(ognik): Work out what this is
|
||||||
bool is_open;
|
bool is_open{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProfileBase {
|
struct ProfileBase {
|
||||||
Common::UUID user_uuid;
|
Common::UUID user_uuid{Common::INVALID_UUID};
|
||||||
u64_le timestamp;
|
u64_le timestamp{};
|
||||||
ProfileUsername username;
|
ProfileUsername username{};
|
||||||
|
|
||||||
// Zero out all the fields to make the profile slot considered "Empty"
|
// Zero out all the fields to make the profile slot considered "Empty"
|
||||||
void Invalidate() {
|
void Invalidate() {
|
||||||
|
@ -101,7 +102,7 @@ private:
|
||||||
bool RemoveProfileAtIndex(std::size_t index);
|
bool RemoveProfileAtIndex(std::size_t index);
|
||||||
|
|
||||||
std::array<ProfileInfo, MAX_USERS> profiles{};
|
std::array<ProfileInfo, MAX_USERS> profiles{};
|
||||||
std::size_t user_count = 0;
|
std::size_t user_count{};
|
||||||
Common::UUID last_opened_user{Common::INVALID_UUID};
|
Common::UUID last_opened_user{Common::INVALID_UUID};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -241,7 +241,7 @@ private:
|
||||||
bool has_received_friend_request;
|
bool has_received_friend_request;
|
||||||
};
|
};
|
||||||
|
|
||||||
Common::UUID uuid;
|
Common::UUID uuid{Common::INVALID_UUID};
|
||||||
Kernel::EventPair notification_event;
|
Kernel::EventPair notification_event;
|
||||||
std::queue<SizedNotificationInfo> notifications;
|
std::queue<SizedNotificationInfo> notifications;
|
||||||
States states{};
|
States states{};
|
||||||
|
|
|
@ -10,13 +10,13 @@
|
||||||
|
|
||||||
namespace Service::Mii {
|
namespace Service::Mii {
|
||||||
|
|
||||||
constexpr std::size_t MAX_MIIS = 100;
|
constexpr std::size_t MAX_MIIS{100};
|
||||||
constexpr u32 INVALID_INDEX = 0xFFFFFFFF;
|
constexpr u32 INVALID_INDEX{0xFFFFFFFF};
|
||||||
|
|
||||||
struct RandomParameters {
|
struct RandomParameters {
|
||||||
u32 unknown_1;
|
u32 unknown_1{};
|
||||||
u32 unknown_2;
|
u32 unknown_2{};
|
||||||
u32 unknown_3;
|
u32 unknown_3{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size.");
|
static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size.");
|
||||||
|
|
||||||
|
@ -30,57 +30,57 @@ enum class Source : u32 {
|
||||||
std::ostream& operator<<(std::ostream& os, Source source);
|
std::ostream& operator<<(std::ostream& os, Source source);
|
||||||
|
|
||||||
struct MiiInfo {
|
struct MiiInfo {
|
||||||
Common::UUID uuid;
|
Common::UUID uuid{Common::INVALID_UUID};
|
||||||
std::array<char16_t, 11> name;
|
std::array<char16_t, 11> name{};
|
||||||
u8 font_region;
|
u8 font_region{};
|
||||||
u8 favorite_color;
|
u8 favorite_color{};
|
||||||
u8 gender;
|
u8 gender{};
|
||||||
u8 height;
|
u8 height{};
|
||||||
u8 weight;
|
u8 weight{};
|
||||||
u8 mii_type;
|
u8 mii_type{};
|
||||||
u8 mii_region;
|
u8 mii_region{};
|
||||||
u8 face_type;
|
u8 face_type{};
|
||||||
u8 face_color;
|
u8 face_color{};
|
||||||
u8 face_wrinkle;
|
u8 face_wrinkle{};
|
||||||
u8 face_makeup;
|
u8 face_makeup{};
|
||||||
u8 hair_type;
|
u8 hair_type{};
|
||||||
u8 hair_color;
|
u8 hair_color{};
|
||||||
bool hair_flip;
|
bool hair_flip{};
|
||||||
u8 eye_type;
|
u8 eye_type{};
|
||||||
u8 eye_color;
|
u8 eye_color{};
|
||||||
u8 eye_scale;
|
u8 eye_scale{};
|
||||||
u8 eye_aspect_ratio;
|
u8 eye_aspect_ratio{};
|
||||||
u8 eye_rotate;
|
u8 eye_rotate{};
|
||||||
u8 eye_x;
|
u8 eye_x{};
|
||||||
u8 eye_y;
|
u8 eye_y{};
|
||||||
u8 eyebrow_type;
|
u8 eyebrow_type{};
|
||||||
u8 eyebrow_color;
|
u8 eyebrow_color{};
|
||||||
u8 eyebrow_scale;
|
u8 eyebrow_scale{};
|
||||||
u8 eyebrow_aspect_ratio;
|
u8 eyebrow_aspect_ratio{};
|
||||||
u8 eyebrow_rotate;
|
u8 eyebrow_rotate{};
|
||||||
u8 eyebrow_x;
|
u8 eyebrow_x{};
|
||||||
u8 eyebrow_y;
|
u8 eyebrow_y{};
|
||||||
u8 nose_type;
|
u8 nose_type{};
|
||||||
u8 nose_scale;
|
u8 nose_scale{};
|
||||||
u8 nose_y;
|
u8 nose_y{};
|
||||||
u8 mouth_type;
|
u8 mouth_type{};
|
||||||
u8 mouth_color;
|
u8 mouth_color{};
|
||||||
u8 mouth_scale;
|
u8 mouth_scale{};
|
||||||
u8 mouth_aspect_ratio;
|
u8 mouth_aspect_ratio{};
|
||||||
u8 mouth_y;
|
u8 mouth_y{};
|
||||||
u8 facial_hair_color;
|
u8 facial_hair_color{};
|
||||||
u8 beard_type;
|
u8 beard_type{};
|
||||||
u8 mustache_type;
|
u8 mustache_type{};
|
||||||
u8 mustache_scale;
|
u8 mustache_scale{};
|
||||||
u8 mustache_y;
|
u8 mustache_y{};
|
||||||
u8 glasses_type;
|
u8 glasses_type{};
|
||||||
u8 glasses_color;
|
u8 glasses_color{};
|
||||||
u8 glasses_scale;
|
u8 glasses_scale{};
|
||||||
u8 glasses_y;
|
u8 glasses_y{};
|
||||||
u8 mole_type;
|
u8 mole_type{};
|
||||||
u8 mole_scale;
|
u8 mole_scale{};
|
||||||
u8 mole_x;
|
u8 mole_x{};
|
||||||
u8 mole_y;
|
u8 mole_y{};
|
||||||
INSERT_PADDING_BYTES(1);
|
INSERT_PADDING_BYTES(1);
|
||||||
|
|
||||||
std::u16string Name() const;
|
std::u16string Name() const;
|
||||||
|
@ -94,14 +94,14 @@ bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs);
|
||||||
|
|
||||||
#pragma pack(push, 4)
|
#pragma pack(push, 4)
|
||||||
struct MiiInfoElement {
|
struct MiiInfoElement {
|
||||||
MiiInfo info;
|
MiiInfo info{};
|
||||||
Source source;
|
Source source{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size.");
|
static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size.");
|
||||||
|
|
||||||
struct MiiStoreBitFields {
|
struct MiiStoreBitFields {
|
||||||
union {
|
union {
|
||||||
u32 word_0;
|
u32 word_0{};
|
||||||
|
|
||||||
BitField<24, 8, u32> hair_type;
|
BitField<24, 8, u32> hair_type;
|
||||||
BitField<23, 1, u32> mole_type;
|
BitField<23, 1, u32> mole_type;
|
||||||
|
@ -112,7 +112,7 @@ struct MiiStoreBitFields {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u32 word_1;
|
u32 word_1{};
|
||||||
|
|
||||||
BitField<31, 1, u32> gender;
|
BitField<31, 1, u32> gender;
|
||||||
BitField<24, 7, u32> eye_color;
|
BitField<24, 7, u32> eye_color;
|
||||||
|
@ -122,7 +122,7 @@ struct MiiStoreBitFields {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u32 word_2;
|
u32 word_2{};
|
||||||
|
|
||||||
BitField<31, 1, u32> mii_type;
|
BitField<31, 1, u32> mii_type;
|
||||||
BitField<24, 7, u32> glasses_color;
|
BitField<24, 7, u32> glasses_color;
|
||||||
|
@ -135,7 +135,7 @@ struct MiiStoreBitFields {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u32 word_3;
|
u32 word_3{};
|
||||||
|
|
||||||
BitField<29, 3, u32> mustache_type;
|
BitField<29, 3, u32> mustache_type;
|
||||||
BitField<24, 5, u32> eyebrow_type;
|
BitField<24, 5, u32> eyebrow_type;
|
||||||
|
@ -148,7 +148,7 @@ struct MiiStoreBitFields {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u32 word_4;
|
u32 word_4{};
|
||||||
|
|
||||||
BitField<29, 3, u32> eye_rotate;
|
BitField<29, 3, u32> eye_rotate;
|
||||||
BitField<24, 5, u32> mustache_y;
|
BitField<24, 5, u32> mustache_y;
|
||||||
|
@ -160,7 +160,7 @@ struct MiiStoreBitFields {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u32 word_5;
|
u32 word_5{};
|
||||||
|
|
||||||
BitField<24, 5, u32> glasses_type;
|
BitField<24, 5, u32> glasses_type;
|
||||||
BitField<20, 4, u32> face_type;
|
BitField<20, 4, u32> face_type;
|
||||||
|
@ -172,7 +172,7 @@ struct MiiStoreBitFields {
|
||||||
};
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
u32 word_6;
|
u32 word_6{};
|
||||||
|
|
||||||
BitField<28, 4, u32> eyebrow_rotate;
|
BitField<28, 4, u32> eyebrow_rotate;
|
||||||
BitField<24, 4, u32> eyebrow_scale;
|
BitField<24, 4, u32> eyebrow_scale;
|
||||||
|
@ -192,30 +192,30 @@ struct MiiStoreData {
|
||||||
// This corresponds to the above structure MiiStoreBitFields. I did it like this because the
|
// This corresponds to the above structure MiiStoreBitFields. I did it like this because the
|
||||||
// BitField<> type makes this (and any thing that contains it) not trivially copyable, which is
|
// BitField<> type makes this (and any thing that contains it) not trivially copyable, which is
|
||||||
// not suitable for our uses.
|
// not suitable for our uses.
|
||||||
std::array<u8, 0x1C> data;
|
std::array<u8, 0x1C> data{};
|
||||||
static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size.");
|
static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size.");
|
||||||
|
|
||||||
std::array<char16_t, 10> name;
|
std::array<char16_t, 10> name{};
|
||||||
Common::UUID uuid;
|
Common::UUID uuid{Common::INVALID_UUID};
|
||||||
u16 crc_1;
|
u16 crc_1{};
|
||||||
u16 crc_2;
|
u16 crc_2{};
|
||||||
|
|
||||||
std::u16string Name() const;
|
std::u16string Name() const;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size.");
|
static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size.");
|
||||||
|
|
||||||
struct MiiStoreDataElement {
|
struct MiiStoreDataElement {
|
||||||
MiiStoreData data;
|
MiiStoreData data{};
|
||||||
Source source;
|
Source source{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size.");
|
static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size.");
|
||||||
|
|
||||||
struct MiiDatabase {
|
struct MiiDatabase {
|
||||||
u32 magic; // 'NFDB'
|
u32 magic{}; // 'NFDB'
|
||||||
std::array<MiiStoreData, MAX_MIIS> miis;
|
std::array<MiiStoreData, MAX_MIIS> miis{};
|
||||||
INSERT_PADDING_BYTES(1);
|
INSERT_PADDING_BYTES(1);
|
||||||
u8 count;
|
u8 count{};
|
||||||
u16 crc;
|
u16 crc{};
|
||||||
};
|
};
|
||||||
static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
|
static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size.");
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
@ -266,8 +266,8 @@ private:
|
||||||
void EnsureDatabasePartition();
|
void EnsureDatabasePartition();
|
||||||
|
|
||||||
MiiDatabase database;
|
MiiDatabase database;
|
||||||
bool updated_flag = false;
|
bool updated_flag{};
|
||||||
bool is_test_mode_enabled = false;
|
bool is_test_mode_enabled{};
|
||||||
};
|
};
|
||||||
|
|
||||||
}; // namespace Service::Mii
|
}; // namespace Service::Mii
|
||||||
|
|
103
src/core/hle/service/time/clock_types.h
Normal file
103
src/core/hle/service/time/clock_types.h
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/uuid.h"
|
||||||
|
#include "core/hle/service/time/errors.h"
|
||||||
|
#include "core/hle/service/time/time_zone_types.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
/// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint
|
||||||
|
struct SteadyClockTimePoint {
|
||||||
|
s64 time_point;
|
||||||
|
Common::UUID clock_source_id;
|
||||||
|
|
||||||
|
ResultCode GetSpanBetween(SteadyClockTimePoint other, s64& span) const {
|
||||||
|
span = 0;
|
||||||
|
|
||||||
|
if (clock_source_id != other.clock_source_id) {
|
||||||
|
return ERROR_TIME_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
span = other.time_point - time_point;
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SteadyClockTimePoint GetRandom() {
|
||||||
|
return {0, Common::UUID::Generate()};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
|
||||||
|
static_assert(std::is_trivially_copyable_v<SteadyClockTimePoint>,
|
||||||
|
"SteadyClockTimePoint must be trivially copyable");
|
||||||
|
|
||||||
|
struct SteadyClockContext {
|
||||||
|
u64 internal_offset;
|
||||||
|
Common::UUID steady_time_point;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size");
|
||||||
|
static_assert(std::is_trivially_copyable_v<SteadyClockContext>,
|
||||||
|
"SteadyClockContext must be trivially copyable");
|
||||||
|
|
||||||
|
struct SystemClockContext {
|
||||||
|
s64 offset;
|
||||||
|
SteadyClockTimePoint steady_time_point;
|
||||||
|
};
|
||||||
|
static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorrect size");
|
||||||
|
static_assert(std::is_trivially_copyable_v<SystemClockContext>,
|
||||||
|
"SystemClockContext must be trivially copyable");
|
||||||
|
|
||||||
|
/// https://switchbrew.org/wiki/Glue_services#TimeSpanType
|
||||||
|
struct TimeSpanType {
|
||||||
|
s64 nanoseconds{};
|
||||||
|
static constexpr s64 ns_per_second{1000000000ULL};
|
||||||
|
|
||||||
|
s64 ToSeconds() const {
|
||||||
|
return nanoseconds / ns_per_second;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TimeSpanType FromSeconds(s64 seconds) {
|
||||||
|
return {seconds * ns_per_second};
|
||||||
|
}
|
||||||
|
|
||||||
|
static TimeSpanType FromTicks(u64 ticks, u64 frequency) {
|
||||||
|
return FromSeconds(static_cast<s64>(ticks) / static_cast<s64>(frequency));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size");
|
||||||
|
|
||||||
|
struct ClockSnapshot {
|
||||||
|
SystemClockContext user_context{};
|
||||||
|
SystemClockContext network_context{};
|
||||||
|
s64 user_time{};
|
||||||
|
s64 network_time{};
|
||||||
|
TimeZone::CalendarTime user_calendar_time{};
|
||||||
|
TimeZone::CalendarTime network_calendar_time{};
|
||||||
|
TimeZone::CalendarAdditionalInfo user_calendar_additional_time{};
|
||||||
|
TimeZone::CalendarAdditionalInfo network_calendar_additional_time{};
|
||||||
|
SteadyClockTimePoint steady_clock_time_point{};
|
||||||
|
TimeZone::LocationName location_name{};
|
||||||
|
u8 is_automatic_correction_enabled{};
|
||||||
|
u8 type{};
|
||||||
|
INSERT_PADDING_BYTES(0x2);
|
||||||
|
|
||||||
|
static ResultCode GetCurrentTime(s64& current_time,
|
||||||
|
const SteadyClockTimePoint& steady_clock_time_point,
|
||||||
|
const SystemClockContext& context) {
|
||||||
|
if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) {
|
||||||
|
current_time = 0;
|
||||||
|
return ERROR_TIME_MISMATCH;
|
||||||
|
}
|
||||||
|
current_time = steady_clock_time_point.time_point + context.offset;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size");
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,16 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/system_clock_context_update_callback.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
|
||||||
|
public:
|
||||||
|
EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/system_clock_core.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class EphemeralNetworkSystemClockCore final : public SystemClockCore {
|
||||||
|
public:
|
||||||
|
explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core)
|
||||||
|
: SystemClockCore{steady_clock_core} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
22
src/core/hle/service/time/errors.h
Normal file
22
src/core/hle/service/time/errors.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/result.h"
|
||||||
|
|
||||||
|
namespace Service::Time {
|
||||||
|
|
||||||
|
constexpr ResultCode ERROR_PERMISSION_DENIED{ErrorModule::Time, 1};
|
||||||
|
constexpr ResultCode ERROR_TIME_MISMATCH{ErrorModule::Time, 102};
|
||||||
|
constexpr ResultCode ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103};
|
||||||
|
constexpr ResultCode ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200};
|
||||||
|
constexpr ResultCode ERROR_OVERFLOW{ErrorModule::Time, 201};
|
||||||
|
constexpr ResultCode ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801};
|
||||||
|
constexpr ResultCode ERROR_OUT_OF_RANGE{ErrorModule::Time, 902};
|
||||||
|
constexpr ResultCode ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903};
|
||||||
|
constexpr ResultCode ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989};
|
||||||
|
constexpr ResultCode ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990};
|
||||||
|
|
||||||
|
} // namespace Service::Time
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2018 yuzu emulator team
|
// Copyright 2019 yuzu emulator team
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
@ -6,9 +6,8 @@
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Service::Time {
|
||||||
|
|
||||||
Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
|
Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name)
|
||||||
Core::System& system, const char* name)
|
: Module::Interface(std::move(module), system, name) {
|
||||||
: Module::Interface(std::move(time), std::move(shared_memory), system, name) {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
|
{0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},
|
||||||
|
@ -22,15 +21,15 @@ Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_me
|
||||||
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
|
{31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"},
|
||||||
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
|
{50, nullptr, "SetStandardSteadyClockInternalOffset"},
|
||||||
{51, nullptr, "GetStandardSteadyClockRtcValue"},
|
{51, nullptr, "GetStandardSteadyClockRtcValue"},
|
||||||
{100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
{100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||||
{101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
{101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"},
|
||||||
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
||||||
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
|
{200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||||
{201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
|
{201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"},
|
||||||
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
|
{300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||||
{400, &Time::GetClockSnapshot, "GetClockSnapshot"},
|
{400, &Time::GetClockSnapshot, "GetClockSnapshot"},
|
||||||
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
|
{401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"},
|
||||||
{500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"},
|
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||||
{501, nullptr, "CalculateSpanBetween"},
|
{501, nullptr, "CalculateSpanBetween"},
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2018 yuzu emulator team
|
// Copyright 2019 yuzu emulator team
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
@ -6,14 +6,15 @@
|
||||||
|
|
||||||
#include "core/hle/service/time/time.h"
|
#include "core/hle/service/time/time.h"
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
class SharedMemory;
|
namespace Service::Time {
|
||||||
|
|
||||||
class Time final : public Module::Interface {
|
class Time final : public Module::Interface {
|
||||||
public:
|
public:
|
||||||
explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory,
|
explicit Time(std::shared_ptr<Module> time, Core::System& system, const char* name);
|
||||||
Core::System& system, const char* name);
|
|
||||||
~Time() override;
|
~Time() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/errors.h"
|
||||||
|
#include "core/hle/service/time/system_clock_context_update_callback.h"
|
||||||
|
#include "core/hle/service/time/time_sharedmemory.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback {
|
||||||
|
public:
|
||||||
|
explicit LocalSystemClockContextWriter(SharedMemory& shared_memory)
|
||||||
|
: SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ResultCode Update() override {
|
||||||
|
shared_memory.UpdateLocalSystemClockContext(context);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedMemory& shared_memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/errors.h"
|
||||||
|
#include "core/hle/service/time/system_clock_context_update_callback.h"
|
||||||
|
#include "core/hle/service/time/time_sharedmemory.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback {
|
||||||
|
public:
|
||||||
|
explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory)
|
||||||
|
: SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ResultCode Update() override {
|
||||||
|
shared_memory.UpdateNetworkSystemClockContext(context);
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SharedMemory& shared_memory;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
17
src/core/hle/service/time/standard_local_system_clock_core.h
Normal file
17
src/core/hle/service/time/standard_local_system_clock_core.h
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/system_clock_core.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class StandardLocalSystemClockCore final : public SystemClockCore {
|
||||||
|
public:
|
||||||
|
explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core)
|
||||||
|
: SystemClockCore{steady_clock_core} {}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/steady_clock_core.h"
|
||||||
|
#include "core/hle/service/time/system_clock_core.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class StandardNetworkSystemClockCore final : public SystemClockCore {
|
||||||
|
public:
|
||||||
|
explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core)
|
||||||
|
: SystemClockCore{steady_clock_core} {}
|
||||||
|
|
||||||
|
void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) {
|
||||||
|
standard_network_clock_sufficient_accuracy = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) {
|
||||||
|
SystemClockContext context{};
|
||||||
|
if (GetClockContext(system, context) != RESULT_SUCCESS) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 span{};
|
||||||
|
if (context.steady_time_point.GetSpanBetween(
|
||||||
|
GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return TimeSpanType{span}.nanoseconds <
|
||||||
|
standard_network_clock_sufficient_accuracy.nanoseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeSpanType standard_network_clock_sufficient_accuracy{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
26
src/core/hle/service/time/standard_steady_clock_core.cpp
Normal file
26
src/core/hle/service/time/standard_steady_clock_core.cpp
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hle/service/time/standard_steady_clock_core.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
|
||||||
|
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
|
||||||
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
|
Core::Timing::CNTFREQ)};
|
||||||
|
TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds};
|
||||||
|
|
||||||
|
if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) {
|
||||||
|
raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
cached_raw_time_point = raw_time_point;
|
||||||
|
return raw_time_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
42
src/core/hle/service/time/standard_steady_clock_core.h
Normal file
42
src/core/hle/service/time/standard_steady_clock_core.h
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/steady_clock_core.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class StandardSteadyClockCore final : public SteadyClockCore {
|
||||||
|
public:
|
||||||
|
SteadyClockTimePoint GetTimePoint(Core::System& system) override {
|
||||||
|
return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()};
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpanType GetInternalOffset() const override {
|
||||||
|
return internal_offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInternalOffset(TimeSpanType value) override {
|
||||||
|
internal_offset = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
|
||||||
|
|
||||||
|
void SetSetupValue(TimeSpanType value) {
|
||||||
|
setup_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeSpanType setup_value{};
|
||||||
|
TimeSpanType internal_offset{};
|
||||||
|
TimeSpanType cached_raw_time_point{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/hle/kernel/writable_event.h"
|
||||||
|
#include "core/hle/service/time/standard_local_system_clock_core.h"
|
||||||
|
#include "core/hle/service/time/standard_network_system_clock_core.h"
|
||||||
|
#include "core/hle/service/time/standard_user_system_clock_core.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
StandardUserSystemClockCore::StandardUserSystemClockCore(
|
||||||
|
StandardLocalSystemClockCore& local_system_clock_core,
|
||||||
|
StandardNetworkSystemClockCore& network_system_clock_core, Core::System& system)
|
||||||
|
: SystemClockCore(local_system_clock_core.GetSteadyClockCore()),
|
||||||
|
local_system_clock_core{local_system_clock_core},
|
||||||
|
network_system_clock_core{network_system_clock_core}, auto_correction_enabled{},
|
||||||
|
auto_correction_time{SteadyClockTimePoint::GetRandom()},
|
||||||
|
auto_correction_event{Kernel::WritableEvent::CreateEventPair(
|
||||||
|
system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} {}
|
||||||
|
|
||||||
|
ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system,
|
||||||
|
bool value) {
|
||||||
|
if (const ResultCode result{ApplyAutomaticCorrection(system, value)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto_correction_enabled = value;
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system,
|
||||||
|
SystemClockContext& context) const {
|
||||||
|
if (const ResultCode result{ApplyAutomaticCorrection(system, false)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return local_system_clock_core.GetClockContext(system, context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext& context) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext& context) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return ERROR_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system,
|
||||||
|
bool value) const {
|
||||||
|
if (auto_correction_enabled == value) {
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!network_system_clock_core.IsClockSetup(system)) {
|
||||||
|
return ERROR_UNINITIALIZED_CLOCK;
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemClockContext context{};
|
||||||
|
if (const ResultCode result{network_system_clock_core.GetClockContext(system, context)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
local_system_clock_core.SetClockContext(context);
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
57
src/core/hle/service/time/standard_user_system_clock_core.h
Normal file
57
src/core/hle/service/time/standard_user_system_clock_core.h
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/kernel/writable_event.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/system_clock_core.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class StandardLocalSystemClockCore;
|
||||||
|
class StandardNetworkSystemClockCore;
|
||||||
|
|
||||||
|
class StandardUserSystemClockCore final : public SystemClockCore {
|
||||||
|
public:
|
||||||
|
StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core,
|
||||||
|
StandardNetworkSystemClockCore& network_system_clock_core,
|
||||||
|
Core::System& system);
|
||||||
|
|
||||||
|
ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value);
|
||||||
|
|
||||||
|
ResultCode GetClockContext(Core::System& system, SystemClockContext& context) const override;
|
||||||
|
|
||||||
|
bool IsAutomaticCorrectionEnabled() const {
|
||||||
|
return auto_correction_enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) {
|
||||||
|
auto_correction_time = steady_clock_time_point;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
ResultCode Flush(const SystemClockContext& context) override;
|
||||||
|
|
||||||
|
ResultCode SetClockContext(const SystemClockContext&) override;
|
||||||
|
|
||||||
|
ResultCode ApplyAutomaticCorrection(Core::System& system, bool value) const;
|
||||||
|
|
||||||
|
const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const {
|
||||||
|
return auto_correction_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
StandardLocalSystemClockCore& local_system_clock_core;
|
||||||
|
StandardNetworkSystemClockCore& network_system_clock_core;
|
||||||
|
bool auto_correction_enabled{};
|
||||||
|
SteadyClockTimePoint auto_correction_time;
|
||||||
|
Kernel::EventPair auto_correction_event;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
55
src/core/hle/service/time/steady_clock_core.h
Normal file
55
src/core/hle/service/time/steady_clock_core.h
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/uuid.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class SteadyClockCore {
|
||||||
|
public:
|
||||||
|
SteadyClockCore() = default;
|
||||||
|
|
||||||
|
const Common::UUID& GetClockSourceId() const {
|
||||||
|
return clock_source_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetClockSourceId(const Common::UUID& value) {
|
||||||
|
clock_source_id = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual TimeSpanType GetInternalOffset() const = 0;
|
||||||
|
|
||||||
|
virtual void SetInternalOffset(TimeSpanType internal_offset) = 0;
|
||||||
|
|
||||||
|
virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0;
|
||||||
|
|
||||||
|
virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0;
|
||||||
|
|
||||||
|
SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) {
|
||||||
|
SteadyClockTimePoint result{GetTimePoint(system)};
|
||||||
|
result.time_point += GetInternalOffset().ToSeconds();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsInitialized() const {
|
||||||
|
return is_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkAsInitialized() {
|
||||||
|
is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Common::UUID clock_source_id{Common::UUID::Generate()};
|
||||||
|
bool is_initialized{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/hle/kernel/writable_event.h"
|
||||||
|
#include "core/hle/service/time/errors.h"
|
||||||
|
#include "core/hle/service/time/system_clock_context_update_callback.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default;
|
||||||
|
SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default;
|
||||||
|
|
||||||
|
bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const {
|
||||||
|
if (has_context) {
|
||||||
|
return context.offset != value.offset ||
|
||||||
|
context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemClockContextUpdateCallback::RegisterOperationEvent(
|
||||||
|
std::shared_ptr<Kernel::WritableEvent>&& writable_event) {
|
||||||
|
operation_event_list.emplace_back(std::move(writable_event));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SystemClockContextUpdateCallback::BroadcastOperationEvent() {
|
||||||
|
for (const auto& writable_event : operation_event_list) {
|
||||||
|
writable_event->Signal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SystemClockContextUpdateCallback::Update(const SystemClockContext& value) {
|
||||||
|
ResultCode result{RESULT_SUCCESS};
|
||||||
|
|
||||||
|
if (NeedUpdate(value)) {
|
||||||
|
context = value;
|
||||||
|
has_context = true;
|
||||||
|
|
||||||
|
result = Update();
|
||||||
|
|
||||||
|
if (result == RESULT_SUCCESS) {
|
||||||
|
BroadcastOperationEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SystemClockContextUpdateCallback::Update() {
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -0,0 +1,43 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
|
||||||
|
namespace Kernel {
|
||||||
|
class WritableEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
|
||||||
|
// This code was released under public domain.
|
||||||
|
|
||||||
|
class SystemClockContextUpdateCallback {
|
||||||
|
public:
|
||||||
|
SystemClockContextUpdateCallback();
|
||||||
|
~SystemClockContextUpdateCallback();
|
||||||
|
|
||||||
|
bool NeedUpdate(const SystemClockContext& value) const;
|
||||||
|
|
||||||
|
void RegisterOperationEvent(std::shared_ptr<Kernel::WritableEvent>&& writable_event);
|
||||||
|
|
||||||
|
void BroadcastOperationEvent();
|
||||||
|
|
||||||
|
ResultCode Update(const SystemClockContext& value);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ResultCode Update();
|
||||||
|
|
||||||
|
SystemClockContext context{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool has_context{};
|
||||||
|
std::vector<std::shared_ptr<Kernel::WritableEvent>> operation_event_list;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
72
src/core/hle/service/time/system_clock_core.cpp
Normal file
72
src/core/hle/service/time/system_clock_core.cpp
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/hle/service/time/steady_clock_core.h"
|
||||||
|
#include "core/hle/service/time/system_clock_context_update_callback.h"
|
||||||
|
#include "core/hle/service/time/system_clock_core.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core)
|
||||||
|
: steady_clock_core{steady_clock_core}, is_initialized{} {
|
||||||
|
context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId();
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemClockCore ::~SystemClockCore() = default;
|
||||||
|
|
||||||
|
ResultCode SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const {
|
||||||
|
posix_time = 0;
|
||||||
|
|
||||||
|
const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
|
||||||
|
|
||||||
|
SystemClockContext clock_context{};
|
||||||
|
if (const ResultCode result{GetClockContext(system, clock_context)}; result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) {
|
||||||
|
return ERROR_TIME_MISMATCH;
|
||||||
|
}
|
||||||
|
|
||||||
|
posix_time = clock_context.offset + current_time_point.time_point;
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) {
|
||||||
|
const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)};
|
||||||
|
const SystemClockContext clock_context{posix_time - current_time_point.time_point,
|
||||||
|
current_time_point};
|
||||||
|
|
||||||
|
if (const ResultCode result{SetClockContext(clock_context)}; result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return Flush(clock_context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SystemClockCore::Flush(const SystemClockContext& context) {
|
||||||
|
if (!system_clock_context_update_callback) {
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
return system_clock_context_update_callback->Update(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& context) {
|
||||||
|
if (const ResultCode result{SetClockContext(context)}; result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return Flush(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SystemClockCore::IsClockSetup(Core::System& system) const {
|
||||||
|
SystemClockContext value{};
|
||||||
|
if (GetClockContext(system, value) == RESULT_SUCCESS) {
|
||||||
|
const SteadyClockTimePoint steady_clock_time_point{
|
||||||
|
steady_clock_core.GetCurrentTimePoint(system)};
|
||||||
|
return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
71
src/core/hle/service/time/system_clock_core.h
Normal file
71
src/core/hle/service/time/system_clock_core.h
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class SteadyClockCore;
|
||||||
|
class SystemClockContextUpdateCallback;
|
||||||
|
|
||||||
|
// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
|
||||||
|
// This code was released under public domain.
|
||||||
|
|
||||||
|
class SystemClockCore {
|
||||||
|
public:
|
||||||
|
explicit SystemClockCore(SteadyClockCore& steady_clock_core);
|
||||||
|
~SystemClockCore();
|
||||||
|
|
||||||
|
SteadyClockCore& GetSteadyClockCore() const {
|
||||||
|
return steady_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode GetCurrentTime(Core::System& system, s64& posix_time) const;
|
||||||
|
|
||||||
|
ResultCode SetCurrentTime(Core::System& system, s64 posix_time);
|
||||||
|
|
||||||
|
virtual ResultCode GetClockContext([[maybe_unused]] Core::System& system,
|
||||||
|
SystemClockContext& value) const {
|
||||||
|
value = context;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ResultCode SetClockContext(const SystemClockContext& value) {
|
||||||
|
context = value;
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ResultCode Flush(const SystemClockContext& context);
|
||||||
|
|
||||||
|
void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) {
|
||||||
|
system_clock_context_update_callback = std::move(callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SetSystemClockContext(const SystemClockContext& context);
|
||||||
|
|
||||||
|
bool IsInitialized() const {
|
||||||
|
return is_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkAsInitialized() {
|
||||||
|
is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsClockSetup(Core::System& system) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
SteadyClockCore& steady_clock_core;
|
||||||
|
SystemClockContext context{};
|
||||||
|
bool is_initialized{};
|
||||||
|
std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
24
src/core/hle/service/time/tick_based_steady_clock_core.cpp
Normal file
24
src/core/hle/service/time/tick_based_steady_clock_core.cpp
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright 2020 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hle/service/time/tick_based_steady_clock_core.h"
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) {
|
||||||
|
const TimeSpanType ticks_time_span{TimeSpanType::FromTicks(
|
||||||
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
|
Core::Timing::CNTFREQ)};
|
||||||
|
|
||||||
|
return {ticks_time_span.ToSeconds(), GetClockSourceId()};
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) {
|
||||||
|
return TimeSpanType::FromSeconds(GetTimePoint(system).time_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
29
src/core/hle/service/time/tick_based_steady_clock_core.h
Normal file
29
src/core/hle/service/time/tick_based_steady_clock_core.h
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// Copyright 2020 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/steady_clock_core.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::Clock {
|
||||||
|
|
||||||
|
class TickBasedSteadyClockCore final : public SteadyClockCore {
|
||||||
|
public:
|
||||||
|
TimeSpanType GetInternalOffset() const override {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetInternalOffset(TimeSpanType internal_offset) override {}
|
||||||
|
|
||||||
|
SteadyClockTimePoint GetTimePoint(Core::System& system) override;
|
||||||
|
|
||||||
|
TimeSpanType GetCurrentRawTimePoint(Core::System& system) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::Clock
|
|
@ -1,9 +1,7 @@
|
||||||
// Copyright 2018 yuzu emulator team
|
// Copyright 2019 yuzu emulator team
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <ctime>
|
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
|
@ -11,69 +9,18 @@
|
||||||
#include "core/hle/ipc_helpers.h"
|
#include "core/hle/ipc_helpers.h"
|
||||||
#include "core/hle/kernel/client_port.h"
|
#include "core/hle/kernel/client_port.h"
|
||||||
#include "core/hle/kernel/client_session.h"
|
#include "core/hle/kernel/client_session.h"
|
||||||
|
#include "core/hle/kernel/scheduler.h"
|
||||||
#include "core/hle/service/time/interface.h"
|
#include "core/hle/service/time/interface.h"
|
||||||
#include "core/hle/service/time/time.h"
|
#include "core/hle/service/time/time.h"
|
||||||
#include "core/hle/service/time/time_sharedmemory.h"
|
#include "core/hle/service/time/time_sharedmemory.h"
|
||||||
#include "core/settings.h"
|
#include "core/hle/service/time/time_zone_service.h"
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Service::Time {
|
||||||
|
|
||||||
static std::chrono::seconds GetSecondsSinceEpoch() {
|
|
||||||
return std::chrono::duration_cast<std::chrono::seconds>(
|
|
||||||
std::chrono::system_clock::now().time_since_epoch()) +
|
|
||||||
Settings::values.custom_rtc_differential;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
|
|
||||||
CalendarAdditionalInfo& additional_info,
|
|
||||||
[[maybe_unused]] const TimeZoneRule& /*rule*/) {
|
|
||||||
const std::time_t time(posix_time);
|
|
||||||
const std::tm* tm = std::localtime(&time);
|
|
||||||
if (tm == nullptr) {
|
|
||||||
calendar_time = {};
|
|
||||||
additional_info = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900);
|
|
||||||
calendar_time.month = static_cast<u8>(tm->tm_mon + 1);
|
|
||||||
calendar_time.day = static_cast<u8>(tm->tm_mday);
|
|
||||||
calendar_time.hour = static_cast<u8>(tm->tm_hour);
|
|
||||||
calendar_time.minute = static_cast<u8>(tm->tm_min);
|
|
||||||
calendar_time.second = static_cast<u8>(tm->tm_sec);
|
|
||||||
|
|
||||||
additional_info.day_of_week = tm->tm_wday;
|
|
||||||
additional_info.day_of_year = tm->tm_yday;
|
|
||||||
std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
|
|
||||||
additional_info.utc_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u64 CalendarToPosix(const CalendarTime& calendar_time,
|
|
||||||
[[maybe_unused]] const TimeZoneRule& /*rule*/) {
|
|
||||||
std::tm time{};
|
|
||||||
time.tm_year = calendar_time.year - 1900;
|
|
||||||
time.tm_mon = calendar_time.month - 1;
|
|
||||||
time.tm_mday = calendar_time.day;
|
|
||||||
|
|
||||||
time.tm_hour = calendar_time.hour;
|
|
||||||
time.tm_min = calendar_time.minute;
|
|
||||||
time.tm_sec = calendar_time.second;
|
|
||||||
|
|
||||||
std::time_t epoch_time = std::mktime(&time);
|
|
||||||
return static_cast<u64>(epoch_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class ClockContextType {
|
|
||||||
StandardSteady,
|
|
||||||
StandardUserSystem,
|
|
||||||
StandardNetworkSystem,
|
|
||||||
StandardLocalSystem,
|
|
||||||
};
|
|
||||||
|
|
||||||
class ISystemClock final : public ServiceFramework<ISystemClock> {
|
class ISystemClock final : public ServiceFramework<ISystemClock> {
|
||||||
public:
|
public:
|
||||||
ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory,
|
ISystemClock(Clock::SystemClockCore& clock_core)
|
||||||
ClockContextType clock_type)
|
: ServiceFramework("ISystemClock"), clock_core{clock_core} {
|
||||||
: ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) {
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
|
{0, &ISystemClock::GetCurrentTime, "GetCurrentTime"},
|
||||||
|
@ -85,355 +32,298 @@ public:
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
UpdateSharedMemoryContext(system_clock_context);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GetCurrentTime(Kernel::HLERequestContext& ctx) {
|
void GetCurrentTime(Kernel::HLERequestContext& ctx) {
|
||||||
const s64 time_since_epoch{GetSecondsSinceEpoch().count()};
|
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
|
if (!clock_core.IsInitialized()) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_UNINITIALIZED_CLOCK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 posix_time{};
|
||||||
|
if (const ResultCode result{
|
||||||
|
clock_core.GetCurrentTime(Core::System::GetInstance(), posix_time)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
IPC::ResponseBuilder rb{ctx, 4};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.Push<u64>(time_since_epoch);
|
rb.Push<s64>(posix_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
|
void GetSystemClockContext(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
// TODO(ogniK): This should be updated periodically however since we have it stubbed we'll
|
if (!clock_core.IsInitialized()) {
|
||||||
// only update when we get a new context
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
UpdateSharedMemoryContext(system_clock_context);
|
rb.Push(ERROR_UNINITIALIZED_CLOCK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2};
|
Clock::SystemClockContext system_clock_context{};
|
||||||
|
if (const ResultCode result{
|
||||||
|
clock_core.GetClockContext(Core::System::GetInstance(), system_clock_context)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw(system_clock_context);
|
rb.PushRaw(system_clock_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateSharedMemoryContext(const SystemClockContext& clock_context) {
|
Clock::SystemClockCore& clock_core;
|
||||||
switch (clock_type) {
|
|
||||||
case ClockContextType::StandardLocalSystem:
|
|
||||||
shared_memory->SetStandardLocalSystemClockContext(clock_context);
|
|
||||||
break;
|
|
||||||
case ClockContextType::StandardNetworkSystem:
|
|
||||||
shared_memory->SetStandardNetworkSystemClockContext(clock_context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemClockContext system_clock_context{};
|
|
||||||
std::shared_ptr<Service::Time::SharedMemory> shared_memory;
|
|
||||||
ClockContextType clock_type;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
|
class ISteadyClock final : public ServiceFramework<ISteadyClock> {
|
||||||
public:
|
public:
|
||||||
ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system)
|
ISteadyClock(Clock::SteadyClockCore& clock_core)
|
||||||
: ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) {
|
: ServiceFramework("ISteadyClock"), clock_core{clock_core} {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
|
{0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"},
|
||||||
};
|
};
|
||||||
RegisterHandlers(functions);
|
RegisterHandlers(functions);
|
||||||
|
|
||||||
shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
|
void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
const auto time_point = GetCurrentTimePoint();
|
if (!clock_core.IsInitialized()) {
|
||||||
// TODO(ogniK): This should be updated periodically
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
shared_memory->SetStandardSteadyClockTimepoint(time_point);
|
rb.Push(ERROR_UNINITIALIZED_CLOCK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2};
|
const Clock::SteadyClockTimePoint time_point{
|
||||||
|
clock_core.GetCurrentTimePoint(Core::System::GetInstance())};
|
||||||
|
IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw(time_point);
|
rb.PushRaw(time_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
SteadyClockTimePoint GetCurrentTimePoint() const {
|
Clock::SteadyClockCore& clock_core;
|
||||||
const auto& core_timing = system.CoreTiming();
|
|
||||||
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
|
|
||||||
return {static_cast<u64_le>(ms.count() / 1000), {}};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<SharedMemory> shared_memory;
|
|
||||||
Core::System& system;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
|
ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
|
||||||
public:
|
Kernel::Thread* thread, Clock::SystemClockContext user_context,
|
||||||
ITimeZoneService() : ServiceFramework("ITimeZoneService") {
|
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
|
||||||
// clang-format off
|
|
||||||
static const FunctionInfo functions[] = {
|
|
||||||
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
|
|
||||||
{1, nullptr, "SetDeviceLocationName"},
|
|
||||||
{2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"},
|
|
||||||
{3, nullptr, "LoadLocationNameList"},
|
|
||||||
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
|
|
||||||
{5, nullptr, "GetTimeZoneRuleVersion"},
|
|
||||||
{6, nullptr, "GetDeviceLocationNameAndUpdatedTime"},
|
|
||||||
{7, nullptr, "SetDeviceLocationNameWithTimeZoneRule"},
|
|
||||||
{8, nullptr, "ParseTimeZoneBinary"},
|
|
||||||
{20, nullptr, "GetDeviceLocationNameOperationEventReadableHandle"},
|
|
||||||
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
|
|
||||||
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
|
||||||
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
|
|
||||||
{202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
|
|
||||||
};
|
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
RegisterHandlers(functions);
|
auto& time_manager{module->GetTimeManager()};
|
||||||
|
|
||||||
|
clock_snapshot.is_automatic_correction_enabled =
|
||||||
|
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
|
||||||
|
clock_snapshot.user_context = user_context;
|
||||||
|
clock_snapshot.network_context = network_context;
|
||||||
|
|
||||||
|
if (const ResultCode result{
|
||||||
|
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName(
|
||||||
|
clock_snapshot.location_name)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
const auto current_time_point{
|
||||||
LocationName location_name{"UTC"};
|
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(Core::System::GetInstance())};
|
||||||
TimeZoneRule my_time_zone_rule{};
|
if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime(
|
||||||
|
clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)};
|
||||||
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
|
result != RESULT_SUCCESS) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
return result;
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.PushRaw(location_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) {
|
TimeZone::CalendarInfo userCalendarInfo{};
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
if (const ResultCode result{
|
||||||
|
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
clock_snapshot.user_time, userCalendarInfo)};
|
||||||
rb.Push(RESULT_SUCCESS);
|
result != RESULT_SUCCESS) {
|
||||||
rb.Push<u32>(0);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
|
clock_snapshot.user_calendar_time = userCalendarInfo.time;
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
clock_snapshot.user_calendar_additional_time = userCalendarInfo.additiona_info;
|
||||||
|
|
||||||
ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule));
|
if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, current_time_point,
|
||||||
|
clock_snapshot.network_context) != RESULT_SUCCESS) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
clock_snapshot.network_time = 0;
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToCalendarTime(Kernel::HLERequestContext& ctx) {
|
TimeZone::CalendarInfo networkCalendarInfo{};
|
||||||
IPC::RequestParser rp{ctx};
|
if (const ResultCode result{
|
||||||
const u64 posix_time = rp.Pop<u64>();
|
time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules(
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
|
clock_snapshot.network_time, networkCalendarInfo)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
TimeZoneRule time_zone_rule{};
|
return result;
|
||||||
auto buffer = ctx.ReadBuffer();
|
|
||||||
std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
|
|
||||||
|
|
||||||
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
|
|
||||||
CalendarAdditionalInfo additional_info{};
|
|
||||||
|
|
||||||
PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.PushRaw(calendar_time);
|
|
||||||
rb.PushRaw(additional_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
clock_snapshot.network_calendar_time = networkCalendarInfo.time;
|
||||||
IPC::RequestParser rp{ctx};
|
clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additiona_info;
|
||||||
const u64 posix_time = rp.Pop<u64>();
|
clock_snapshot.type = type;
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
|
|
||||||
|
|
||||||
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
|
return RESULT_SUCCESS;
|
||||||
CalendarAdditionalInfo additional_info{};
|
}
|
||||||
|
|
||||||
PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule);
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 10};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.PushRaw(calendar_time);
|
|
||||||
rb.PushRaw(additional_info);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToPosixTime(Kernel::HLERequestContext& ctx) {
|
|
||||||
// TODO(ogniK): Figure out how to handle multiple times
|
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
auto calendar_time = rp.PopRaw<CalendarTime>();
|
|
||||||
auto posix_time = CalendarToPosix(calendar_time, {});
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.PushRaw<u32>(1); // Amount of times we're returning
|
|
||||||
ctx.WriteBuffer(&posix_time, sizeof(u64));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
|
||||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
auto calendar_time = rp.PopRaw<CalendarTime>();
|
|
||||||
auto posix_time = CalendarToPosix(calendar_time, {});
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.PushRaw<u32>(1); // Amount of times we're returning
|
|
||||||
ctx.WriteBuffer(&posix_time, sizeof(u64));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem);
|
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem);
|
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<ISteadyClock>(shared_memory, system);
|
rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<ITimeZoneService>();
|
rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem);
|
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
|
||||||
|
Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()};
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
|
auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()};
|
||||||
|
if (!steady_clock_core.IsInitialized()) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_UNINITIALIZED_CLOCK);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto context{rp.PopRaw<Clock::SystemClockContext>()};
|
||||||
|
const auto current_time_point{
|
||||||
|
steady_clock_core.GetCurrentTimePoint(Core::System::GetInstance())};
|
||||||
|
|
||||||
|
if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) {
|
||||||
|
const auto ticks{Clock::TimeSpanType::FromTicks(
|
||||||
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
|
Core::Timing::CNTFREQ)};
|
||||||
|
const s64 base_time_point{context.offset + current_time_point.time_point -
|
||||||
|
ticks.ToSeconds()};
|
||||||
|
IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushRaw(base_time_point);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(ERROR_TIME_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto initial_type = rp.PopRaw<u8>();
|
const auto type{rp.PopRaw<u8>()};
|
||||||
|
|
||||||
const s64 time_since_epoch{GetSecondsSinceEpoch().count()};
|
Clock::SystemClockContext user_context{};
|
||||||
const std::time_t time(time_since_epoch);
|
if (const ResultCode result{
|
||||||
const std::tm* tm = std::localtime(&time);
|
module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
|
||||||
if (tm == nullptr) {
|
Core::System::GetInstance(), user_context)};
|
||||||
LOG_ERROR(Service_Time, "tm is a nullptr");
|
result != RESULT_SUCCESS) {
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find appropriate error code
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Clock::SystemClockContext network_context{};
|
||||||
|
if (const ResultCode result{
|
||||||
|
module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
|
||||||
|
Core::System::GetInstance(), network_context)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& core_timing = system.CoreTiming();
|
Clock::ClockSnapshot clock_snapshot{};
|
||||||
const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks());
|
if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
|
||||||
const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}};
|
&ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
CalendarTime calendar_time{};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900);
|
rb.Push(result);
|
||||||
calendar_time.month = static_cast<u8>(tm->tm_mon + 1);
|
return;
|
||||||
calendar_time.day = static_cast<u8>(tm->tm_mday);
|
}
|
||||||
calendar_time.hour = static_cast<u8>(tm->tm_hour);
|
|
||||||
calendar_time.minute = static_cast<u8>(tm->tm_min);
|
|
||||||
calendar_time.second = static_cast<u8>(tm->tm_sec);
|
|
||||||
|
|
||||||
ClockSnapshot clock_snapshot{};
|
|
||||||
clock_snapshot.system_posix_time = time_since_epoch;
|
|
||||||
clock_snapshot.network_posix_time = time_since_epoch;
|
|
||||||
clock_snapshot.system_calendar_time = calendar_time;
|
|
||||||
clock_snapshot.network_calendar_time = calendar_time;
|
|
||||||
|
|
||||||
CalendarAdditionalInfo additional_info{};
|
|
||||||
PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
|
|
||||||
|
|
||||||
clock_snapshot.system_calendar_info = additional_info;
|
|
||||||
clock_snapshot.network_calendar_info = additional_info;
|
|
||||||
|
|
||||||
clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
|
|
||||||
clock_snapshot.location_name = LocationName{"UTC"};
|
|
||||||
clock_snapshot.clock_auto_adjustment_enabled = 1;
|
|
||||||
clock_snapshot.type = initial_type;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
|
ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser(
|
void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) {
|
||||||
Kernel::HLERequestContext& ctx) {
|
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
IPC::RequestParser rp{ctx};
|
IPC::RequestParser rp{ctx};
|
||||||
const auto snapshot_a = rp.PopRaw<ClockSnapshot>();
|
const auto type{rp.PopRaw<u8>()};
|
||||||
const auto snapshot_b = rp.PopRaw<ClockSnapshot>();
|
rp.AlignWithPadding();
|
||||||
const u64 difference =
|
|
||||||
snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset;
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 4};
|
const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()};
|
||||||
|
const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()};
|
||||||
|
|
||||||
|
Clock::ClockSnapshot clock_snapshot{};
|
||||||
|
if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal(
|
||||||
|
&ctx.GetThread(), user_context, network_context, type, clock_snapshot)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushRaw<u64>(difference);
|
ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_Time, "called");
|
LOG_DEBUG(Service_Time, "called");
|
||||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder());
|
rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled(
|
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
|
||||||
Kernel::HLERequestContext& ctx) {
|
: ServiceFramework(name), module{std::move(module)}, system{system} {}
|
||||||
// ogniK(TODO): When clock contexts are implemented, the value should be read from the context
|
|
||||||
// instead of our shared memory holder
|
|
||||||
LOG_DEBUG(Service_Time, "called");
|
|
||||||
|
|
||||||
IPC::ResponseBuilder rb{ctx, 3};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled());
|
|
||||||
}
|
|
||||||
|
|
||||||
void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled(
|
|
||||||
Kernel::HLERequestContext& ctx) {
|
|
||||||
IPC::RequestParser rp{ctx};
|
|
||||||
const auto enabled = rp.Pop<u8>();
|
|
||||||
|
|
||||||
LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called");
|
|
||||||
|
|
||||||
// TODO(ogniK): Update clock contexts and correct timespans
|
|
||||||
|
|
||||||
shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0);
|
|
||||||
IPC::ResponseBuilder rb{ctx, 2};
|
|
||||||
rb.Push(RESULT_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
Module::Interface::Interface(std::shared_ptr<Module> time,
|
|
||||||
std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
|
|
||||||
const char* name)
|
|
||||||
: ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)),
|
|
||||||
system(system) {}
|
|
||||||
|
|
||||||
Module::Interface::~Interface() = default;
|
Module::Interface::~Interface() = default;
|
||||||
|
|
||||||
void InstallInterfaces(Core::System& system) {
|
void InstallInterfaces(Core::System& system) {
|
||||||
auto time = std::make_shared<Module>();
|
auto module{std::make_shared<Module>(system)};
|
||||||
auto shared_mem = std::make_shared<SharedMemory>(system);
|
std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
|
||||||
|
std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
|
||||||
std::make_shared<Time>(time, shared_mem, system, "time:a")
|
std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
|
||||||
->InstallAsService(system.ServiceManager());
|
|
||||||
std::make_shared<Time>(time, shared_mem, system, "time:s")
|
|
||||||
->InstallAsService(system.ServiceManager());
|
|
||||||
std::make_shared<Time>(std::move(time), shared_mem, system, "time:u")
|
|
||||||
->InstallAsService(system.ServiceManager());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Time
|
} // namespace Service::Time
|
||||||
|
|
|
@ -4,84 +4,23 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/time_manager.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Service::Time {
|
||||||
|
|
||||||
class SharedMemory;
|
|
||||||
|
|
||||||
struct LocationName {
|
|
||||||
std::array<u8, 0x24> name;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(LocationName) == 0x24, "LocationName is incorrect size");
|
|
||||||
|
|
||||||
struct CalendarTime {
|
|
||||||
u16_le year;
|
|
||||||
u8 month; // Starts at 1
|
|
||||||
u8 day; // Starts at 1
|
|
||||||
u8 hour;
|
|
||||||
u8 minute;
|
|
||||||
u8 second;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size");
|
|
||||||
|
|
||||||
struct CalendarAdditionalInfo {
|
|
||||||
u32_le day_of_week;
|
|
||||||
u32_le day_of_year;
|
|
||||||
std::array<u8, 8> name;
|
|
||||||
u8 is_dst;
|
|
||||||
s32_le utc_offset;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
|
|
||||||
"CalendarAdditionalInfo structure has incorrect size");
|
|
||||||
|
|
||||||
// TODO(mailwl) RE this structure
|
|
||||||
struct TimeZoneRule {
|
|
||||||
INSERT_PADDING_BYTES(0x4000);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SteadyClockTimePoint {
|
|
||||||
using SourceID = std::array<u8, 16>;
|
|
||||||
|
|
||||||
u64_le value;
|
|
||||||
SourceID source_id;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
|
|
||||||
|
|
||||||
struct SystemClockContext {
|
|
||||||
u64_le offset;
|
|
||||||
SteadyClockTimePoint time_point;
|
|
||||||
};
|
|
||||||
static_assert(sizeof(SystemClockContext) == 0x20,
|
|
||||||
"SystemClockContext structure has incorrect size");
|
|
||||||
|
|
||||||
struct ClockSnapshot {
|
|
||||||
SystemClockContext user_clock_context;
|
|
||||||
SystemClockContext network_clock_context;
|
|
||||||
s64_le system_posix_time;
|
|
||||||
s64_le network_posix_time;
|
|
||||||
CalendarTime system_calendar_time;
|
|
||||||
CalendarTime network_calendar_time;
|
|
||||||
CalendarAdditionalInfo system_calendar_info;
|
|
||||||
CalendarAdditionalInfo network_calendar_info;
|
|
||||||
SteadyClockTimePoint steady_clock_timepoint;
|
|
||||||
LocationName location_name;
|
|
||||||
u8 clock_auto_adjustment_enabled;
|
|
||||||
u8 type;
|
|
||||||
u8 version;
|
|
||||||
INSERT_PADDING_BYTES(1);
|
|
||||||
};
|
|
||||||
static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
|
|
||||||
|
|
||||||
class Module final {
|
class Module final {
|
||||||
public:
|
public:
|
||||||
|
Module(Core::System& system) : time_manager{system} {}
|
||||||
|
|
||||||
class Interface : public ServiceFramework<Interface> {
|
class Interface : public ServiceFramework<Interface> {
|
||||||
public:
|
public:
|
||||||
explicit Interface(std::shared_ptr<Module> time,
|
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
|
||||||
std::shared_ptr<SharedMemory> shared_memory, Core::System& system,
|
|
||||||
const char* name);
|
|
||||||
~Interface() override;
|
~Interface() override;
|
||||||
|
|
||||||
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
|
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
|
||||||
|
@ -89,17 +28,29 @@ public:
|
||||||
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
|
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
|
||||||
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
|
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
|
||||||
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
|
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
|
||||||
|
void IsStandardNetworkSystemClockAccuracySufficient(Kernel::HLERequestContext& ctx);
|
||||||
|
void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx);
|
||||||
void GetClockSnapshot(Kernel::HLERequestContext& ctx);
|
void GetClockSnapshot(Kernel::HLERequestContext& ctx);
|
||||||
void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx);
|
void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx);
|
||||||
void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
|
void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx);
|
||||||
void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
|
|
||||||
void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx);
|
private:
|
||||||
|
ResultCode GetClockSnapshotFromSystemClockContextInternal(
|
||||||
|
Kernel::Thread* thread, Clock::SystemClockContext user_context,
|
||||||
|
Clock::SystemClockContext network_context, u8 type,
|
||||||
|
Clock::ClockSnapshot& cloc_snapshot);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::shared_ptr<Module> time;
|
std::shared_ptr<Module> module;
|
||||||
std::shared_ptr<SharedMemory> shared_memory;
|
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TimeManager& GetTimeManager() {
|
||||||
|
return time_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeManager time_manager;
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Registers all Time services with the specified service manager.
|
/// Registers all Time services with the specified service manager.
|
||||||
|
|
137
src/core/hle/service/time/time_manager.cpp
Normal file
137
src/core/hle/service/time/time_manager.cpp
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
#include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h"
|
||||||
|
#include "core/hle/service/time/local_system_clock_context_writer.h"
|
||||||
|
#include "core/hle/service/time/network_system_clock_context_writer.h"
|
||||||
|
#include "core/hle/service/time/time_manager.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
namespace Service::Time {
|
||||||
|
|
||||||
|
constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL};
|
||||||
|
|
||||||
|
static std::chrono::seconds GetSecondsSinceEpoch() {
|
||||||
|
return std::chrono::duration_cast<std::chrono::seconds>(
|
||||||
|
std::chrono::system_clock::now().time_since_epoch()) +
|
||||||
|
Settings::values.custom_rtc_differential;
|
||||||
|
}
|
||||||
|
|
||||||
|
static s64 GetExternalRtcValue() {
|
||||||
|
return GetSecondsSinceEpoch().count();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeManager::TimeManager(Core::System& system)
|
||||||
|
: shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core},
|
||||||
|
standard_network_system_clock_core{standard_steady_clock_core},
|
||||||
|
standard_user_system_clock_core{standard_local_system_clock_core,
|
||||||
|
standard_network_system_clock_core, system},
|
||||||
|
ephemeral_network_system_clock_core{tick_based_steady_clock_core},
|
||||||
|
local_system_clock_context_writer{
|
||||||
|
std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)},
|
||||||
|
network_system_clock_context_writer{
|
||||||
|
std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)},
|
||||||
|
ephemeral_network_system_clock_context_writer{
|
||||||
|
std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()},
|
||||||
|
time_zone_content_manager{*this, system} {
|
||||||
|
|
||||||
|
const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())};
|
||||||
|
SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {});
|
||||||
|
SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds());
|
||||||
|
SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy);
|
||||||
|
SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom());
|
||||||
|
SetupEphemeralNetworkSystemClock();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeManager::~TimeManager() = default;
|
||||||
|
|
||||||
|
void TimeManager::SetupTimeZoneManager(std::string location_name,
|
||||||
|
Clock::SteadyClockTimePoint time_zone_updated_time_point,
|
||||||
|
std::size_t total_location_name_count,
|
||||||
|
u128 time_zone_rule_version,
|
||||||
|
FileSys::VirtualFile& vfs_file) {
|
||||||
|
if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule(
|
||||||
|
location_name, vfs_file) != RESULT_SUCCESS) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point);
|
||||||
|
time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount(
|
||||||
|
total_location_name_count);
|
||||||
|
time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version);
|
||||||
|
time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
|
||||||
|
Clock::TimeSpanType setup_value,
|
||||||
|
Clock::TimeSpanType internal_offset,
|
||||||
|
bool is_rtc_reset_detected) {
|
||||||
|
standard_steady_clock_core.SetClockSourceId(clock_source_id);
|
||||||
|
standard_steady_clock_core.SetSetupValue(setup_value);
|
||||||
|
standard_steady_clock_core.SetInternalOffset(internal_offset);
|
||||||
|
standard_steady_clock_core.MarkAsInitialized();
|
||||||
|
|
||||||
|
const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)};
|
||||||
|
shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeManager::SetupStandardLocalSystemClock(Core::System& system,
|
||||||
|
Clock::SystemClockContext clock_context,
|
||||||
|
s64 posix_time) {
|
||||||
|
standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer);
|
||||||
|
|
||||||
|
const auto current_time_point{
|
||||||
|
standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)};
|
||||||
|
if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) {
|
||||||
|
standard_local_system_clock_core.SetSystemClockContext(clock_context);
|
||||||
|
} else {
|
||||||
|
if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
standard_local_system_clock_core.MarkAsInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
|
||||||
|
Clock::TimeSpanType sufficient_accuracy) {
|
||||||
|
standard_network_system_clock_core.SetUpdateCallbackInstance(
|
||||||
|
network_system_clock_context_writer);
|
||||||
|
|
||||||
|
if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy(
|
||||||
|
sufficient_accuracy);
|
||||||
|
standard_network_system_clock_core.MarkAsInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeManager::SetupStandardUserSystemClock(
|
||||||
|
Core::System& system, bool is_automatic_correction_enabled,
|
||||||
|
Clock::SteadyClockTimePoint steady_clock_time_point) {
|
||||||
|
if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled(
|
||||||
|
system, is_automatic_correction_enabled) != RESULT_SUCCESS) {
|
||||||
|
UNREACHABLE();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point);
|
||||||
|
standard_user_system_clock_core.MarkAsInitialized();
|
||||||
|
shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TimeManager::SetupEphemeralNetworkSystemClock() {
|
||||||
|
ephemeral_network_system_clock_core.SetUpdateCallbackInstance(
|
||||||
|
ephemeral_network_system_clock_context_writer);
|
||||||
|
ephemeral_network_system_clock_core.MarkAsInitialized();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time
|
117
src/core/hle/service/time/time_manager.h
Normal file
117
src/core/hle/service/time/time_manager.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/file_sys/vfs_types.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/ephemeral_network_system_clock_core.h"
|
||||||
|
#include "core/hle/service/time/standard_local_system_clock_core.h"
|
||||||
|
#include "core/hle/service/time/standard_network_system_clock_core.h"
|
||||||
|
#include "core/hle/service/time/standard_steady_clock_core.h"
|
||||||
|
#include "core/hle/service/time/standard_user_system_clock_core.h"
|
||||||
|
#include "core/hle/service/time/tick_based_steady_clock_core.h"
|
||||||
|
#include "core/hle/service/time/time_sharedmemory.h"
|
||||||
|
#include "core/hle/service/time/time_zone_content_manager.h"
|
||||||
|
|
||||||
|
namespace Service::Time {
|
||||||
|
|
||||||
|
namespace Clock {
|
||||||
|
class EphemeralNetworkSystemClockContextWriter;
|
||||||
|
class LocalSystemClockContextWriter;
|
||||||
|
class NetworkSystemClockContextWriter;
|
||||||
|
} // namespace Clock
|
||||||
|
|
||||||
|
// Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783).
|
||||||
|
// This code was released under public domain.
|
||||||
|
|
||||||
|
class TimeManager final {
|
||||||
|
public:
|
||||||
|
explicit TimeManager(Core::System& system);
|
||||||
|
~TimeManager();
|
||||||
|
|
||||||
|
Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() {
|
||||||
|
return standard_steady_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const {
|
||||||
|
return standard_steady_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() {
|
||||||
|
return standard_local_system_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const {
|
||||||
|
return standard_local_system_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() {
|
||||||
|
return standard_network_system_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const {
|
||||||
|
return standard_network_system_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() {
|
||||||
|
return standard_user_system_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const {
|
||||||
|
return standard_user_system_clock_core;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() {
|
||||||
|
return time_zone_content_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const {
|
||||||
|
return time_zone_content_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemory& GetSharedMemory() {
|
||||||
|
return shared_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SharedMemory& GetSharedMemory() const {
|
||||||
|
return shared_memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupTimeZoneManager(std::string location_name,
|
||||||
|
Clock::SteadyClockTimePoint time_zone_updated_time_point,
|
||||||
|
std::size_t total_location_name_count, u128 time_zone_rule_version,
|
||||||
|
FileSys::VirtualFile& vfs_file);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id,
|
||||||
|
Clock::TimeSpanType setup_value,
|
||||||
|
Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected);
|
||||||
|
void SetupStandardLocalSystemClock(Core::System& system,
|
||||||
|
Clock::SystemClockContext clock_context, s64 posix_time);
|
||||||
|
void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context,
|
||||||
|
Clock::TimeSpanType sufficient_accuracy);
|
||||||
|
void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled,
|
||||||
|
Clock::SteadyClockTimePoint steady_clock_time_point);
|
||||||
|
void SetupEphemeralNetworkSystemClock();
|
||||||
|
|
||||||
|
SharedMemory shared_memory;
|
||||||
|
|
||||||
|
Clock::StandardSteadyClockCore standard_steady_clock_core;
|
||||||
|
Clock::TickBasedSteadyClockCore tick_based_steady_clock_core;
|
||||||
|
Clock::StandardLocalSystemClockCore standard_local_system_clock_core;
|
||||||
|
Clock::StandardNetworkSystemClockCore standard_network_system_clock_core;
|
||||||
|
Clock::StandardUserSystemClockCore standard_user_system_clock_core;
|
||||||
|
Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core;
|
||||||
|
|
||||||
|
std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer;
|
||||||
|
std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer;
|
||||||
|
std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter>
|
||||||
|
ephemeral_network_system_clock_context_writer;
|
||||||
|
|
||||||
|
TimeZone::TimeZoneContentManager time_zone_content_manager;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time
|
|
@ -3,20 +3,21 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/core_timing.h"
|
||||||
|
#include "core/core_timing_util.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/steady_clock_core.h"
|
||||||
#include "core/hle/service/time/time_sharedmemory.h"
|
#include "core/hle/service/time/time_sharedmemory.h"
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Service::Time {
|
||||||
const std::size_t SHARED_MEMORY_SIZE = 0x1000;
|
|
||||||
|
static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000};
|
||||||
|
|
||||||
SharedMemory::SharedMemory(Core::System& system) : system(system) {
|
SharedMemory::SharedMemory(Core::System& system) : system(system) {
|
||||||
shared_memory_holder = Kernel::SharedMemory::Create(
|
shared_memory_holder = Kernel::SharedMemory::Create(
|
||||||
system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
|
system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite,
|
||||||
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory");
|
Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory");
|
||||||
|
std::memset(shared_memory_holder->GetPointer(), 0, SHARED_MEMORY_SIZE);
|
||||||
// Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash
|
|
||||||
// if it's set to anything else
|
|
||||||
shared_memory_format.format_version = 14;
|
|
||||||
std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedMemory::~SharedMemory() = default;
|
SharedMemory::~SharedMemory() = default;
|
||||||
|
@ -25,44 +26,32 @@ std::shared_ptr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() cons
|
||||||
return shared_memory_holder;
|
return shared_memory_holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) {
|
void SharedMemory::SetupStandardSteadyClock(Core::System& system,
|
||||||
|
const Common::UUID& clock_source_id,
|
||||||
|
Clock::TimeSpanType current_time_point) {
|
||||||
|
const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks(
|
||||||
|
Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()),
|
||||||
|
Core::Timing::CNTFREQ)};
|
||||||
|
const Clock::SteadyClockContext context{
|
||||||
|
static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds),
|
||||||
|
clock_source_id};
|
||||||
shared_memory_format.standard_steady_clock_timepoint.StoreData(
|
shared_memory_format.standard_steady_clock_timepoint.StoreData(
|
||||||
shared_memory_holder->GetPointer(), timepoint);
|
shared_memory_holder->GetPointer(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) {
|
void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) {
|
||||||
shared_memory_format.standard_local_system_clock_context.StoreData(
|
shared_memory_format.standard_local_system_clock_context.StoreData(
|
||||||
shared_memory_holder->GetPointer(), context);
|
shared_memory_holder->GetPointer(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) {
|
void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) {
|
||||||
shared_memory_format.standard_network_system_clock_context.StoreData(
|
shared_memory_format.standard_network_system_clock_context.StoreData(
|
||||||
shared_memory_holder->GetPointer(), context);
|
shared_memory_holder->GetPointer(), context);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) {
|
void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) {
|
||||||
shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
|
shared_memory_format.standard_user_system_clock_automatic_correction.StoreData(
|
||||||
shared_memory_holder->GetPointer(), enabled);
|
shared_memory_holder->GetPointer(), is_enabled);
|
||||||
}
|
|
||||||
|
|
||||||
SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() {
|
|
||||||
return shared_memory_format.standard_steady_clock_timepoint.ReadData(
|
|
||||||
shared_memory_holder->GetPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() {
|
|
||||||
return shared_memory_format.standard_local_system_clock_context.ReadData(
|
|
||||||
shared_memory_holder->GetPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() {
|
|
||||||
return shared_memory_format.standard_network_system_clock_context.ReadData(
|
|
||||||
shared_memory_holder->GetPointer());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() {
|
|
||||||
return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData(
|
|
||||||
shared_memory_holder->GetPointer());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::Time
|
} // namespace Service::Time
|
||||||
|
|
|
@ -5,11 +5,14 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/uuid.h"
|
||||||
#include "core/hle/kernel/shared_memory.h"
|
#include "core/hle/kernel/shared_memory.h"
|
||||||
#include "core/hle/service/time/time.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
|
||||||
namespace Service::Time {
|
namespace Service::Time {
|
||||||
class SharedMemory {
|
|
||||||
|
class SharedMemory final {
|
||||||
public:
|
public:
|
||||||
explicit SharedMemory(Core::System& system);
|
explicit SharedMemory(Core::System& system);
|
||||||
~SharedMemory();
|
~SharedMemory();
|
||||||
|
@ -17,22 +20,10 @@ public:
|
||||||
// Return the shared memory handle
|
// Return the shared memory handle
|
||||||
std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
|
std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const;
|
||||||
|
|
||||||
// Set memory barriers in shared memory and update them
|
|
||||||
void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint);
|
|
||||||
void SetStandardLocalSystemClockContext(const SystemClockContext& context);
|
|
||||||
void SetStandardNetworkSystemClockContext(const SystemClockContext& context);
|
|
||||||
void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled);
|
|
||||||
|
|
||||||
// Pull from memory barriers in the shared memory
|
|
||||||
SteadyClockTimePoint GetStandardSteadyClockTimepoint();
|
|
||||||
SystemClockContext GetStandardLocalSystemClockContext();
|
|
||||||
SystemClockContext GetStandardNetworkSystemClockContext();
|
|
||||||
bool GetStandardUserSystemClockAutomaticCorrectionEnabled();
|
|
||||||
|
|
||||||
// TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
|
// TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this?
|
||||||
template <typename T, std::size_t Offset>
|
template <typename T, std::size_t Offset>
|
||||||
struct MemoryBarrier {
|
struct MemoryBarrier {
|
||||||
static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable");
|
static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
|
||||||
u32_le read_attempt{};
|
u32_le read_attempt{};
|
||||||
std::array<T, 2> data{};
|
std::array<T, 2> data{};
|
||||||
|
|
||||||
|
@ -57,16 +48,22 @@ public:
|
||||||
|
|
||||||
// Shared memory format
|
// Shared memory format
|
||||||
struct Format {
|
struct Format {
|
||||||
MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint;
|
MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint;
|
||||||
MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context;
|
MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context;
|
||||||
MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context;
|
MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context;
|
||||||
MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
|
MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction;
|
||||||
u32_le format_version;
|
u32_le format_version;
|
||||||
};
|
};
|
||||||
static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
|
static_assert(sizeof(Format) == 0xd8, "Format is an invalid size");
|
||||||
|
|
||||||
|
void SetupStandardSteadyClock(Core::System& system, const Common::UUID& clock_source_id,
|
||||||
|
Clock::TimeSpanType currentTimePoint);
|
||||||
|
void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context);
|
||||||
|
void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context);
|
||||||
|
void SetAutomaticCorrectionEnabled(bool is_enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<Kernel::SharedMemory> shared_memory_holder{};
|
std::shared_ptr<Kernel::SharedMemory> shared_memory_holder;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
Format shared_memory_format{};
|
Format shared_memory_format{};
|
||||||
};
|
};
|
||||||
|
|
125
src/core/hle/service/time/time_zone_content_manager.cpp
Normal file
125
src/core/hle/service/time/time_zone_content_manager.cpp
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/core.h"
|
||||||
|
#include "core/file_sys/content_archive.h"
|
||||||
|
#include "core/file_sys/nca_metadata.h"
|
||||||
|
#include "core/file_sys/registered_cache.h"
|
||||||
|
#include "core/file_sys/romfs.h"
|
||||||
|
#include "core/file_sys/system_archive/system_archive.h"
|
||||||
|
#include "core/hle/service/filesystem/filesystem.h"
|
||||||
|
#include "core/hle/service/time/time_manager.h"
|
||||||
|
#include "core/hle/service/time/time_zone_content_manager.h"
|
||||||
|
|
||||||
|
namespace Service::Time::TimeZone {
|
||||||
|
|
||||||
|
constexpr u64 time_zone_binary_titleid{0x010000000000080E};
|
||||||
|
|
||||||
|
static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) {
|
||||||
|
const auto* nand{system.GetFileSystemController().GetSystemNANDContents()};
|
||||||
|
const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)};
|
||||||
|
|
||||||
|
FileSys::VirtualFile romfs;
|
||||||
|
if (nca) {
|
||||||
|
romfs = nca->GetRomFS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!romfs) {
|
||||||
|
romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!romfs) {
|
||||||
|
LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return FileSys::ExtractRomFS(romfs);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::vector<std::string> BuildLocationNameCache(Core::System& system) {
|
||||||
|
const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)};
|
||||||
|
if (!extracted_romfs) {
|
||||||
|
LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileSys::VirtualFile binary_list{extracted_romfs->GetFile("binaryList.txt")};
|
||||||
|
if (!binary_list) {
|
||||||
|
LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> raw_data(binary_list->GetSize());
|
||||||
|
binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize());
|
||||||
|
|
||||||
|
std::stringstream data_stream{raw_data.data()};
|
||||||
|
std::string name;
|
||||||
|
std::vector<std::string> location_name_cache;
|
||||||
|
while (std::getline(data_stream, name)) {
|
||||||
|
name.pop_back(); // Remove carriage return
|
||||||
|
location_name_cache.emplace_back(std::move(name));
|
||||||
|
}
|
||||||
|
return location_name_cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system)
|
||||||
|
: system{system}, location_name_cache{BuildLocationNameCache(system)} {
|
||||||
|
if (FileSys::VirtualFile vfs_file; GetTimeZoneInfoFile("GMT", vfs_file) == RESULT_SUCCESS) {
|
||||||
|
const auto time_point{
|
||||||
|
time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)};
|
||||||
|
time_manager.SetupTimeZoneManager("GMT", time_point, location_name_cache.size(), {},
|
||||||
|
vfs_file);
|
||||||
|
} else {
|
||||||
|
time_zone_manager.MarkAsInitialized();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules,
|
||||||
|
const std::string& location_name) const {
|
||||||
|
FileSys::VirtualFile vfs_file;
|
||||||
|
if (const ResultCode result{GetTimeZoneInfoFile(location_name, vfs_file)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const {
|
||||||
|
return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) !=
|
||||||
|
location_name_cache.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name,
|
||||||
|
FileSys::VirtualFile& vfs_file) const {
|
||||||
|
if (!IsLocationNameValid(location_name)) {
|
||||||
|
return ERROR_TIME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)};
|
||||||
|
if (!extracted_romfs) {
|
||||||
|
LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid);
|
||||||
|
return ERROR_TIME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileSys::VirtualDir zoneinfo_dir{extracted_romfs->GetSubdirectory("zoneinfo")};
|
||||||
|
if (!zoneinfo_dir) {
|
||||||
|
LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid);
|
||||||
|
return ERROR_TIME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
vfs_file = zoneinfo_dir->GetFile(location_name);
|
||||||
|
if (!vfs_file) {
|
||||||
|
LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid,
|
||||||
|
location_name);
|
||||||
|
return ERROR_TIME_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
return RESULT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time::TimeZone
|
46
src/core/hle/service/time/time_zone_content_manager.h
Normal file
46
src/core/hle/service/time/time_zone_content_manager.h
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "core/hle/service/time/time_zone_manager.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time {
|
||||||
|
class TimeManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Service::Time::TimeZone {
|
||||||
|
|
||||||
|
class TimeZoneContentManager final {
|
||||||
|
public:
|
||||||
|
TimeZoneContentManager(TimeManager& time_manager, Core::System& system);
|
||||||
|
|
||||||
|
TimeZoneManager& GetTimeZoneManager() {
|
||||||
|
return time_zone_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
const TimeZoneManager& GetTimeZoneManager() const {
|
||||||
|
return time_zone_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool IsLocationNameValid(const std::string& location_name) const;
|
||||||
|
ResultCode GetTimeZoneInfoFile(const std::string& location_name,
|
||||||
|
FileSys::VirtualFile& vfs_file) const;
|
||||||
|
|
||||||
|
Core::System& system;
|
||||||
|
TimeZoneManager time_zone_manager;
|
||||||
|
const std::vector<std::string> location_name_cache;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::TimeZone
|
1030
src/core/hle/service/time/time_zone_manager.cpp
Normal file
1030
src/core/hle/service/time/time_zone_manager.cpp
Normal file
File diff suppressed because it is too large
Load diff
53
src/core/hle/service/time/time_zone_manager.h
Normal file
53
src/core/hle/service/time/time_zone_manager.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "core/file_sys/vfs_types.h"
|
||||||
|
#include "core/hle/service/time/clock_types.h"
|
||||||
|
#include "core/hle/service/time/time_zone_types.h"
|
||||||
|
|
||||||
|
namespace Service::Time::TimeZone {
|
||||||
|
|
||||||
|
class TimeZoneManager final {
|
||||||
|
public:
|
||||||
|
TimeZoneManager();
|
||||||
|
~TimeZoneManager();
|
||||||
|
|
||||||
|
void SetTotalLocationNameCount(std::size_t value) {
|
||||||
|
total_location_name_count = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetTimeZoneRuleVersion(const u128& value) {
|
||||||
|
time_zone_rule_version = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MarkAsInitialized() {
|
||||||
|
is_initialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultCode SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name,
|
||||||
|
FileSys::VirtualFile& vfs_file);
|
||||||
|
ResultCode SetUpdatedTime(const Clock::SteadyClockTimePoint& value);
|
||||||
|
ResultCode GetDeviceLocationName(TimeZone::LocationName& value) const;
|
||||||
|
ResultCode ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const;
|
||||||
|
ResultCode ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const;
|
||||||
|
ResultCode ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const;
|
||||||
|
ResultCode ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time,
|
||||||
|
s64& posix_time) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool is_initialized{};
|
||||||
|
TimeZoneRule time_zone_rule{};
|
||||||
|
std::string device_location_name{"GMT"};
|
||||||
|
u128 time_zone_rule_version{};
|
||||||
|
std::size_t total_location_name_count{};
|
||||||
|
Clock::SteadyClockTimePoint time_zone_update_time_point{
|
||||||
|
Clock::SteadyClockTimePoint::GetRandom()};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time::TimeZone
|
148
src/core/hle/service/time/time_zone_service.cpp
Normal file
148
src/core/hle/service/time/time_zone_service.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "common/logging/log.h"
|
||||||
|
#include "core/hle/ipc_helpers.h"
|
||||||
|
#include "core/hle/service/time/time_zone_content_manager.h"
|
||||||
|
#include "core/hle/service/time/time_zone_service.h"
|
||||||
|
#include "core/hle/service/time/time_zone_types.h"
|
||||||
|
|
||||||
|
namespace Service::Time {
|
||||||
|
|
||||||
|
ITimeZoneService ::ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_content_manager)
|
||||||
|
: ServiceFramework("ITimeZoneService"), time_zone_content_manager{time_zone_content_manager} {
|
||||||
|
static const FunctionInfo functions[] = {
|
||||||
|
{0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"},
|
||||||
|
{1, nullptr, "SetDeviceLocationName"},
|
||||||
|
{2, nullptr, "GetTotalLocationNameCount"},
|
||||||
|
{3, nullptr, "LoadLocationNameList"},
|
||||||
|
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
|
||||||
|
{5, nullptr, "GetTimeZoneRuleVersion"},
|
||||||
|
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
|
||||||
|
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
||||||
|
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
|
||||||
|
{202, nullptr, "ToPosixTimeWithMyRule"},
|
||||||
|
};
|
||||||
|
RegisterHandlers(functions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITimeZoneService::GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
|
TimeZone::LocationName location_name{};
|
||||||
|
if (const ResultCode result{
|
||||||
|
time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushRaw(location_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITimeZoneService::LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()};
|
||||||
|
|
||||||
|
std::string location_name;
|
||||||
|
for (const auto& byte : raw_location_name) {
|
||||||
|
// Strip extra bytes
|
||||||
|
if (byte == '\0') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
location_name.push_back(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Time, "called, location_name={}", location_name);
|
||||||
|
|
||||||
|
TimeZone::TimeZoneRule time_zone_rule{};
|
||||||
|
if (const ResultCode result{
|
||||||
|
time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule));
|
||||||
|
std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule));
|
||||||
|
ctx.WriteBuffer(time_zone_rule_outbuffer);
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITimeZoneService::ToCalendarTime(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto posix_time{rp.Pop<s64>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
|
||||||
|
|
||||||
|
TimeZone::TimeZoneRule time_zone_rule{};
|
||||||
|
const auto buffer{ctx.ReadBuffer()};
|
||||||
|
std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
|
||||||
|
|
||||||
|
TimeZone::CalendarInfo calendar_info{};
|
||||||
|
if (const ResultCode result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime(
|
||||||
|
time_zone_rule, posix_time, calendar_info)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushRaw(calendar_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITimeZoneService::ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto posix_time{rp.Pop<s64>()};
|
||||||
|
|
||||||
|
LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time);
|
||||||
|
|
||||||
|
TimeZone::CalendarInfo calendar_info{};
|
||||||
|
if (const ResultCode result{
|
||||||
|
time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules(
|
||||||
|
posix_time, calendar_info)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushRaw(calendar_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) {
|
||||||
|
LOG_DEBUG(Service_Time, "called");
|
||||||
|
|
||||||
|
IPC::RequestParser rp{ctx};
|
||||||
|
const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()};
|
||||||
|
TimeZone::TimeZoneRule time_zone_rule{};
|
||||||
|
std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule));
|
||||||
|
|
||||||
|
s64 posix_time{};
|
||||||
|
if (const ResultCode result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime(
|
||||||
|
time_zone_rule, calendar_time, posix_time)};
|
||||||
|
result != RESULT_SUCCESS) {
|
||||||
|
IPC::ResponseBuilder rb{ctx, 2};
|
||||||
|
rb.Push(result);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(bunnei): Handle multiple times
|
||||||
|
IPC::ResponseBuilder rb{ctx, 3};
|
||||||
|
rb.Push(RESULT_SUCCESS);
|
||||||
|
rb.PushRaw<u32>(1); // Number of times we're returning
|
||||||
|
ctx.WriteBuffer(&posix_time, sizeof(s64));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Service::Time
|
30
src/core/hle/service/time/time_zone_service.h
Normal file
30
src/core/hle/service/time/time_zone_service.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/hle/service/service.h"
|
||||||
|
|
||||||
|
namespace Service::Time {
|
||||||
|
|
||||||
|
namespace TimeZone {
|
||||||
|
class TimeZoneContentManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
class ITimeZoneService final : public ServiceFramework<ITimeZoneService> {
|
||||||
|
public:
|
||||||
|
explicit ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_manager);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void GetDeviceLocationName(Kernel::HLERequestContext& ctx);
|
||||||
|
void LoadTimeZoneRule(Kernel::HLERequestContext& ctx);
|
||||||
|
void ToCalendarTime(Kernel::HLERequestContext& ctx);
|
||||||
|
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx);
|
||||||
|
void ToPosixTime(Kernel::HLERequestContext& ctx);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TimeZone::TimeZoneContentManager& time_zone_content_manager;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Service::Time
|
87
src/core/hle/service/time/time_zone_types.h
Normal file
87
src/core/hle/service/time/time_zone_types.h
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2019 yuzu emulator team
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "common/common_funcs.h"
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "common/swap.h"
|
||||||
|
|
||||||
|
namespace Service::Time::TimeZone {
|
||||||
|
|
||||||
|
using LocationName = std::array<char, 0x24>;
|
||||||
|
|
||||||
|
/// https://switchbrew.org/wiki/Glue_services#ttinfo
|
||||||
|
struct TimeTypeInfo {
|
||||||
|
s32 gmt_offset{};
|
||||||
|
u8 is_dst{};
|
||||||
|
INSERT_PADDING_BYTES(3);
|
||||||
|
s32 abbreviation_list_index{};
|
||||||
|
u8 is_standard_time_daylight{};
|
||||||
|
u8 is_gmt{};
|
||||||
|
INSERT_PADDING_BYTES(2);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TimeTypeInfo) == 0x10, "TimeTypeInfo is incorrect size");
|
||||||
|
|
||||||
|
/// https://switchbrew.org/wiki/Glue_services#TimeZoneRule
|
||||||
|
struct TimeZoneRule {
|
||||||
|
s32 time_count{};
|
||||||
|
s32 type_count{};
|
||||||
|
s32 char_count{};
|
||||||
|
u8 go_back{};
|
||||||
|
u8 go_ahead{};
|
||||||
|
INSERT_PADDING_BYTES(2);
|
||||||
|
std::array<s64, 1000> ats{};
|
||||||
|
std::array<s8, 1000> types{};
|
||||||
|
std::array<TimeTypeInfo, 128> ttis{};
|
||||||
|
std::array<char, 512> chars{};
|
||||||
|
s32 default_type{};
|
||||||
|
INSERT_PADDING_BYTES(0x12C4);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size");
|
||||||
|
|
||||||
|
/// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo
|
||||||
|
struct CalendarAdditionalInfo {
|
||||||
|
u32 day_of_week{};
|
||||||
|
u32 day_of_year{};
|
||||||
|
std::array<char, 8> timezone_name;
|
||||||
|
u32 is_dst{};
|
||||||
|
s32 gmt_offset{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size");
|
||||||
|
|
||||||
|
/// https://switchbrew.org/wiki/Glue_services#CalendarTime
|
||||||
|
struct CalendarTime {
|
||||||
|
s16 year{};
|
||||||
|
s8 month{};
|
||||||
|
s8 day{};
|
||||||
|
s8 hour{};
|
||||||
|
s8 minute{};
|
||||||
|
s8 second{};
|
||||||
|
INSERT_PADDING_BYTES(1);
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size");
|
||||||
|
|
||||||
|
struct CalendarInfo {
|
||||||
|
CalendarTime time{};
|
||||||
|
CalendarAdditionalInfo additiona_info{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size");
|
||||||
|
|
||||||
|
struct TzifHeader {
|
||||||
|
u32_be magic{};
|
||||||
|
u8 version{};
|
||||||
|
INSERT_PADDING_BYTES(15);
|
||||||
|
s32_be ttis_gmt_count{};
|
||||||
|
s32_be ttis_std_count{};
|
||||||
|
s32_be leap_count{};
|
||||||
|
s32_be time_count{};
|
||||||
|
s32_be type_count{};
|
||||||
|
s32_be char_count{};
|
||||||
|
};
|
||||||
|
static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader is incorrect size");
|
||||||
|
|
||||||
|
} // namespace Service::Time::TimeZone
|
Loading…
Reference in a new issue