diff options
Diffstat (limited to 'src')
47 files changed, 3681 insertions, 542 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 7fd226050..1a3647a67 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -96,6 +96,8 @@ add_library(core STATIC | |||
| 96 | file_sys/system_archive/system_archive.h | 96 | file_sys/system_archive/system_archive.h |
| 97 | file_sys/system_archive/system_version.cpp | 97 | file_sys/system_archive/system_version.cpp |
| 98 | file_sys/system_archive/system_version.h | 98 | file_sys/system_archive/system_version.h |
| 99 | file_sys/system_archive/time_zone_binary.cpp | ||
| 100 | file_sys/system_archive/time_zone_binary.h | ||
| 99 | file_sys/vfs.cpp | 101 | file_sys/vfs.cpp |
| 100 | file_sys/vfs.h | 102 | file_sys/vfs.h |
| 101 | file_sys/vfs_concat.cpp | 103 | file_sys/vfs_concat.cpp |
| @@ -461,12 +463,40 @@ add_library(core STATIC | |||
| 461 | hle/service/spl/spl.h | 463 | hle/service/spl/spl.h |
| 462 | hle/service/ssl/ssl.cpp | 464 | hle/service/ssl/ssl.cpp |
| 463 | hle/service/ssl/ssl.h | 465 | hle/service/ssl/ssl.h |
| 466 | hle/service/time/clock_types.h | ||
| 467 | hle/service/time/ephemeral_network_system_clock_context_writer.h | ||
| 468 | hle/service/time/ephemeral_network_system_clock_core.h | ||
| 469 | hle/service/time/errors.h | ||
| 464 | hle/service/time/interface.cpp | 470 | hle/service/time/interface.cpp |
| 465 | hle/service/time/interface.h | 471 | hle/service/time/interface.h |
| 472 | hle/service/time/local_system_clock_context_writer.h | ||
| 473 | hle/service/time/network_system_clock_context_writer.h | ||
| 474 | hle/service/time/standard_local_system_clock_core.h | ||
| 475 | hle/service/time/standard_network_system_clock_core.h | ||
| 476 | hle/service/time/standard_steady_clock_core.cpp | ||
| 477 | hle/service/time/standard_steady_clock_core.h | ||
| 478 | hle/service/time/standard_user_system_clock_core.cpp | ||
| 479 | hle/service/time/standard_user_system_clock_core.h | ||
| 480 | hle/service/time/steady_clock_core.h | ||
| 481 | hle/service/time/system_clock_context_update_callback.cpp | ||
| 482 | hle/service/time/system_clock_context_update_callback.h | ||
| 483 | hle/service/time/system_clock_core.cpp | ||
| 484 | hle/service/time/system_clock_core.h | ||
| 485 | hle/service/time/tick_based_steady_clock_core.cpp | ||
| 486 | hle/service/time/tick_based_steady_clock_core.h | ||
| 466 | hle/service/time/time.cpp | 487 | hle/service/time/time.cpp |
| 467 | hle/service/time/time.h | 488 | hle/service/time/time.h |
| 489 | hle/service/time/time_manager.cpp | ||
| 490 | hle/service/time/time_manager.h | ||
| 468 | hle/service/time/time_sharedmemory.cpp | 491 | hle/service/time/time_sharedmemory.cpp |
| 469 | hle/service/time/time_sharedmemory.h | 492 | hle/service/time/time_sharedmemory.h |
| 493 | hle/service/time/time_zone_content_manager.cpp | ||
| 494 | hle/service/time/time_zone_content_manager.h | ||
| 495 | hle/service/time/time_zone_manager.cpp | ||
| 496 | hle/service/time/time_zone_manager.h | ||
| 497 | hle/service/time/time_zone_service.cpp | ||
| 498 | hle/service/time/time_zone_service.h | ||
| 499 | hle/service/time/time_zone_types.h | ||
| 470 | hle/service/usb/usb.cpp | 500 | hle/service/usb/usb.cpp |
| 471 | hle/service/usb/usb.h | 501 | hle/service/usb/usb.h |
| 472 | hle/service/vi/display/vi_display.cpp | 502 | hle/service/vi/display/vi_display.cpp |
diff --git a/src/core/file_sys/system_archive/system_archive.cpp b/src/core/file_sys/system_archive/system_archive.cpp index e93d100a5..a6696024e 100644 --- a/src/core/file_sys/system_archive/system_archive.cpp +++ b/src/core/file_sys/system_archive/system_archive.cpp | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "core/file_sys/system_archive/shared_font.h" | 9 | #include "core/file_sys/system_archive/shared_font.h" |
| 10 | #include "core/file_sys/system_archive/system_archive.h" | 10 | #include "core/file_sys/system_archive/system_archive.h" |
| 11 | #include "core/file_sys/system_archive/system_version.h" | 11 | #include "core/file_sys/system_archive/system_version.h" |
| 12 | #include "core/file_sys/system_archive/time_zone_binary.h" | ||
| 12 | 13 | ||
| 13 | namespace FileSys::SystemArchive { | 14 | namespace FileSys::SystemArchive { |
| 14 | 15 | ||
| @@ -38,7 +39,7 @@ constexpr std::array<SystemArchiveDescriptor, SYSTEM_ARCHIVE_COUNT> SYSTEM_ARCHI | |||
| 38 | {0x010000000000080B, "LocalNews", nullptr}, | 39 | {0x010000000000080B, "LocalNews", nullptr}, |
| 39 | {0x010000000000080C, "Eula", nullptr}, | 40 | {0x010000000000080C, "Eula", nullptr}, |
| 40 | {0x010000000000080D, "UrlBlackList", nullptr}, | 41 | {0x010000000000080D, "UrlBlackList", nullptr}, |
| 41 | {0x010000000000080E, "TimeZoneBinary", nullptr}, | 42 | {0x010000000000080E, "TimeZoneBinary", &TimeZoneBinary}, |
| 42 | {0x010000000000080F, "CertStoreCruiser", nullptr}, | 43 | {0x010000000000080F, "CertStoreCruiser", nullptr}, |
| 43 | {0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension}, | 44 | {0x0100000000000810, "FontNintendoExtension", &FontNintendoExtension}, |
| 44 | {0x0100000000000811, "FontStandard", &FontStandard}, | 45 | {0x0100000000000811, "FontStandard", &FontStandard}, |
diff --git a/src/core/file_sys/system_archive/time_zone_binary.cpp b/src/core/file_sys/system_archive/time_zone_binary.cpp new file mode 100644 index 000000000..9806bd197 --- /dev/null +++ b/src/core/file_sys/system_archive/time_zone_binary.cpp | |||
| @@ -0,0 +1,657 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/swap.h" | ||
| 6 | #include "core/file_sys/system_archive/time_zone_binary.h" | ||
| 7 | #include "core/file_sys/vfs_vector.h" | ||
| 8 | #include "core/hle/service/time/time_zone_types.h" | ||
| 9 | |||
| 10 | namespace FileSys::SystemArchive { | ||
| 11 | |||
| 12 | static constexpr std::array<u8, 9633> LOCATION_NAMES{ | ||
| 13 | 0x43, 0x45, 0x54, 0x0d, 0x0a, 0x43, 0x53, 0x54, 0x36, 0x43, 0x44, 0x54, 0x0d, 0x0a, 0x43, 0x75, | ||
| 14 | 0x62, 0x61, 0x0d, 0x0a, 0x45, 0x45, 0x54, 0x0d, 0x0a, 0x45, 0x67, 0x79, 0x70, 0x74, 0x0d, 0x0a, | ||
| 15 | 0x45, 0x69, 0x72, 0x65, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x0d, 0x0a, 0x45, 0x53, 0x54, 0x35, 0x45, | ||
| 16 | 0x44, 0x54, 0x0d, 0x0a, 0x47, 0x42, 0x0d, 0x0a, 0x47, 0x42, 0x2d, 0x45, 0x69, 0x72, 0x65, 0x0d, | ||
| 17 | 0x0a, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54, | ||
| 18 | 0x2d, 0x30, 0x0d, 0x0a, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77, | ||
| 19 | 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x48, 0x6f, 0x6e, 0x67, 0x6b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x48, | ||
| 20 | 0x53, 0x54, 0x0d, 0x0a, 0x49, 0x63, 0x65, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x49, 0x72, 0x61, | ||
| 21 | 0x6e, 0x0d, 0x0a, 0x49, 0x73, 0x72, 0x61, 0x65, 0x6c, 0x0d, 0x0a, 0x4a, 0x61, 0x6d, 0x61, 0x69, | ||
| 22 | 0x63, 0x61, 0x0d, 0x0a, 0x4a, 0x61, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x4b, 0x77, 0x61, 0x6a, 0x61, | ||
| 23 | 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x4c, 0x69, 0x62, 0x79, 0x61, 0x0d, 0x0a, 0x4d, 0x45, 0x54, | ||
| 24 | 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x0d, 0x0a, 0x4d, 0x53, 0x54, 0x37, 0x4d, 0x44, 0x54, 0x0d, 0x0a, | ||
| 25 | 0x4e, 0x61, 0x76, 0x61, 0x6a, 0x6f, 0x0d, 0x0a, 0x4e, 0x5a, 0x0d, 0x0a, 0x4e, 0x5a, 0x2d, 0x43, | ||
| 26 | 0x48, 0x41, 0x54, 0x0d, 0x0a, 0x50, 0x6f, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x50, 0x6f, 0x72, | ||
| 27 | 0x74, 0x75, 0x67, 0x61, 0x6c, 0x0d, 0x0a, 0x50, 0x52, 0x43, 0x0d, 0x0a, 0x50, 0x53, 0x54, 0x38, | ||
| 28 | 0x50, 0x44, 0x54, 0x0d, 0x0a, 0x52, 0x4f, 0x43, 0x0d, 0x0a, 0x52, 0x4f, 0x4b, 0x0d, 0x0a, 0x53, | ||
| 29 | 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x54, 0x75, 0x72, 0x6b, 0x65, 0x79, | ||
| 30 | 0x0d, 0x0a, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x55, 0x6e, 0x69, 0x76, 0x65, 0x72, 0x73, 0x61, 0x6c, | ||
| 31 | 0x0d, 0x0a, 0x55, 0x54, 0x43, 0x0d, 0x0a, 0x57, 0x2d, 0x53, 0x55, 0x0d, 0x0a, 0x57, 0x45, 0x54, | ||
| 32 | 0x0d, 0x0a, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, | ||
| 33 | 0x62, 0x69, 0x64, 0x6a, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, | ||
| 34 | 0x63, 0x63, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x64, | ||
| 35 | 0x69, 0x73, 0x5f, 0x41, 0x62, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, | ||
| 36 | 0x2f, 0x41, 0x6c, 0x67, 0x69, 0x65, 0x72, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, | ||
| 37 | 0x2f, 0x41, 0x73, 0x6d, 0x61, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 38 | 0x41, 0x73, 0x6d, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, | ||
| 39 | 0x61, 0x6d, 0x61, 0x6b, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, | ||
| 40 | 0x6e, 0x67, 0x75, 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x6e, | ||
| 41 | 0x6a, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x73, | ||
| 42 | 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x74, | ||
| 43 | 0x79, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x72, 0x61, 0x7a, | ||
| 44 | 0x7a, 0x61, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 45 | 0x42, 0x75, 0x6a, 0x75, 0x6d, 0x62, 0x75, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, | ||
| 46 | 0x61, 0x2f, 0x43, 0x61, 0x69, 0x72, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 47 | 0x43, 0x61, 0x73, 0x61, 0x62, 0x6c, 0x61, 0x6e, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, | ||
| 48 | 0x63, 0x61, 0x2f, 0x43, 0x65, 0x75, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, | ||
| 49 | 0x2f, 0x43, 0x6f, 0x6e, 0x61, 0x6b, 0x72, 0x79, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, | ||
| 50 | 0x2f, 0x44, 0x61, 0x6b, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, | ||
| 51 | 0x61, 0x72, 0x5f, 0x65, 0x73, 0x5f, 0x53, 0x61, 0x6c, 0x61, 0x61, 0x6d, 0x0d, 0x0a, 0x41, 0x66, | ||
| 52 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6a, 0x69, 0x62, 0x6f, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x41, | ||
| 53 | 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x75, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x66, | ||
| 54 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x41, 0x61, 0x69, 0x75, 0x6e, 0x0d, 0x0a, 0x41, | ||
| 55 | 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x72, 0x65, 0x65, 0x74, 0x6f, 0x77, 0x6e, 0x0d, 0x0a, | ||
| 56 | 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x61, 0x62, 0x6f, 0x72, 0x6f, 0x6e, 0x65, 0x0d, | ||
| 57 | 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x61, 0x72, 0x65, 0x0d, 0x0a, | ||
| 58 | 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x6f, 0x68, 0x61, 0x6e, 0x6e, 0x65, 0x73, 0x62, | ||
| 59 | 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, 0x75, 0x62, 0x61, | ||
| 60 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x70, 0x61, 0x6c, 0x61, | ||
| 61 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x68, 0x61, 0x72, 0x74, 0x6f, 0x75, | ||
| 62 | 0x6d, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x67, 0x61, 0x6c, 0x69, | ||
| 63 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x69, 0x6e, 0x73, 0x68, 0x61, 0x73, | ||
| 64 | 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x67, 0x6f, 0x73, 0x0d, | ||
| 65 | 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x62, 0x72, 0x65, 0x76, 0x69, 0x6c, | ||
| 66 | 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x6d, 0x65, 0x0d, | ||
| 67 | 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x61, 0x6e, 0x64, 0x61, 0x0d, 0x0a, | ||
| 68 | 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x62, 0x75, 0x6d, 0x62, 0x61, 0x73, 0x68, | ||
| 69 | 0x69, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x75, 0x73, 0x61, 0x6b, 0x61, | ||
| 70 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6c, 0x61, 0x62, 0x6f, 0x0d, | ||
| 71 | 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x70, 0x75, 0x74, 0x6f, 0x0d, 0x0a, | ||
| 72 | 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x73, 0x65, 0x72, 0x75, 0x0d, 0x0a, 0x41, | ||
| 73 | 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x62, 0x61, 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, | ||
| 74 | 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x67, 0x61, 0x64, 0x69, 0x73, 0x68, 0x75, 0x0d, | ||
| 75 | 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x72, 0x6f, 0x76, 0x69, 0x61, | ||
| 76 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x69, 0x72, 0x6f, 0x62, 0x69, | ||
| 77 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x64, 0x6a, 0x61, 0x6d, 0x65, 0x6e, | ||
| 78 | 0x61, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x61, 0x6d, 0x65, 0x79, | ||
| 79 | 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x75, 0x61, 0x6b, 0x63, 0x68, | ||
| 80 | 0x6f, 0x74, 0x74, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x75, 0x61, 0x67, | ||
| 81 | 0x61, 0x64, 0x6f, 0x75, 0x67, 0x6f, 0x75, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 82 | 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x2d, 0x4e, 0x6f, 0x76, 0x6f, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, | ||
| 83 | 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f, 0x5f, 0x54, 0x6f, 0x6d, 0x65, 0x0d, 0x0a, 0x41, 0x66, 0x72, | ||
| 84 | 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6d, 0x62, 0x75, 0x6b, 0x74, 0x75, 0x0d, 0x0a, 0x41, 0x66, | ||
| 85 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x72, 0x69, 0x70, 0x6f, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x66, | ||
| 86 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x75, 0x6e, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x66, 0x72, 0x69, | ||
| 87 | 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x64, 0x68, 0x6f, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 88 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x64, 0x61, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 89 | 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x63, 0x68, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 90 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x67, 0x75, 0x69, 0x6c, 0x6c, 0x61, 0x0d, 0x0a, | ||
| 91 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x6e, 0x74, 0x69, 0x67, 0x75, 0x61, 0x0d, | ||
| 92 | 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x61, 0x67, 0x75, 0x61, 0x69, | ||
| 93 | 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x75, 0x62, | ||
| 94 | 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x73, 0x75, 0x6e, 0x63, | ||
| 95 | 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x74, 0x69, | ||
| 96 | 0x6b, 0x6f, 0x6b, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, | ||
| 97 | 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68, | ||
| 98 | 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x69, | ||
| 99 | 0x61, 0x5f, 0x42, 0x61, 0x6e, 0x64, 0x65, 0x72, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 100 | 0x69, 0x63, 0x61, 0x2f, 0x42, 0x61, 0x72, 0x62, 0x61, 0x64, 0x6f, 0x73, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 101 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 102 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x65, 0x6c, 0x69, 0x7a, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 103 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6c, 0x61, 0x6e, 0x63, 0x2d, 0x53, 0x61, 0x62, 0x6c, 0x6f, | ||
| 104 | 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, 0x61, 0x5f, 0x56, | ||
| 105 | 0x69, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, | ||
| 106 | 0x67, 0x6f, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x6f, | ||
| 107 | 0x69, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x42, 0x75, 0x65, | ||
| 108 | 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 109 | 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x5f, 0x42, 0x61, 0x79, | ||
| 110 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x6d, 0x70, 0x6f, 0x5f, | ||
| 111 | 0x47, 0x72, 0x61, 0x6e, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 112 | 0x43, 0x61, 0x6e, 0x63, 0x75, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 113 | 0x43, 0x61, 0x72, 0x61, 0x63, 0x61, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 114 | 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 115 | 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x65, 0x6e, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 116 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x79, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 117 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x63, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 118 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x68, 0x75, 0x61, 0x68, 0x75, 0x61, 0x0d, | ||
| 119 | 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x61, 0x6c, 0x5f, 0x48, | ||
| 120 | 0x61, 0x72, 0x62, 0x6f, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 121 | 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 122 | 0x2f, 0x43, 0x6f, 0x73, 0x74, 0x61, 0x5f, 0x52, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 123 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 124 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x69, 0x61, 0x62, 0x61, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 125 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x61, 0x63, 0x61, 0x6f, 0x0d, 0x0a, 0x41, | ||
| 126 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x6e, 0x6d, 0x61, 0x72, 0x6b, 0x73, 0x68, | ||
| 127 | 0x61, 0x76, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77, | ||
| 128 | 0x73, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x77, | ||
| 129 | 0x73, 0x6f, 0x6e, 0x5f, 0x43, 0x72, 0x65, 0x65, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 130 | 0x63, 0x61, 0x2f, 0x44, 0x65, 0x6e, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 131 | 0x63, 0x61, 0x2f, 0x44, 0x65, 0x74, 0x72, 0x6f, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 132 | 0x69, 0x63, 0x61, 0x2f, 0x44, 0x6f, 0x6d, 0x69, 0x6e, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 133 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x64, 0x6d, 0x6f, 0x6e, 0x74, 0x6f, 0x6e, 0x0d, 0x0a, | ||
| 134 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x69, 0x72, 0x75, 0x6e, 0x65, 0x70, 0x65, | ||
| 135 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, 0x6c, 0x5f, 0x53, 0x61, 0x6c, | ||
| 136 | 0x76, 0x61, 0x64, 0x6f, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x45, | ||
| 137 | 0x6e, 0x73, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 138 | 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x61, 0x6c, 0x65, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 139 | 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x4e, 0x65, 0x6c, 0x73, 0x6f, 0x6e, 0x0d, | ||
| 140 | 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x46, 0x6f, 0x72, 0x74, 0x5f, 0x57, 0x61, | ||
| 141 | 0x79, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x6c, 0x61, | ||
| 142 | 0x63, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 143 | 0x47, 0x6f, 0x64, 0x74, 0x68, 0x61, 0x62, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 144 | 0x2f, 0x47, 0x6f, 0x6f, 0x73, 0x65, 0x5f, 0x42, 0x61, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 145 | 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x61, 0x6e, 0x64, 0x5f, 0x54, 0x75, 0x72, 0x6b, 0x0d, 0x0a, | ||
| 146 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x72, 0x65, 0x6e, 0x61, 0x64, 0x61, 0x0d, | ||
| 147 | 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x65, 0x6c, 0x6f, | ||
| 148 | 0x75, 0x70, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x47, 0x75, 0x61, | ||
| 149 | 0x74, 0x65, 0x6d, 0x61, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 150 | 0x47, 0x75, 0x61, 0x79, 0x61, 0x71, 0x75, 0x69, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 151 | 0x63, 0x61, 0x2f, 0x47, 0x75, 0x79, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 152 | 0x63, 0x61, 0x2f, 0x48, 0x61, 0x6c, 0x69, 0x66, 0x61, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 153 | 0x69, 0x63, 0x61, 0x2f, 0x48, 0x61, 0x76, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 154 | 0x69, 0x63, 0x61, 0x2f, 0x48, 0x65, 0x72, 0x6d, 0x6f, 0x73, 0x69, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a, | ||
| 155 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, | ||
| 156 | 0x6f, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, | ||
| 157 | 0x75, 0x76, 0x69, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x71, | ||
| 158 | 0x61, 0x6c, 0x75, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, | ||
| 159 | 0x61, 0x6d, 0x61, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 160 | 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4a, | ||
| 161 | 0x75, 0x6e, 0x65, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, | ||
| 162 | 0x6e, 0x6f, 0x78, 0x5f, 0x49, 0x4e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 163 | 0x4b, 0x72, 0x61, 0x6c, 0x65, 0x6e, 0x64, 0x69, 0x6a, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 164 | 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x50, 0x61, 0x7a, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 165 | 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x69, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 166 | 0x61, 0x2f, 0x4c, 0x6f, 0x73, 0x5f, 0x41, 0x6e, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x0d, 0x0a, 0x41, | ||
| 167 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c, | ||
| 168 | 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4c, 0x6f, 0x77, 0x65, 0x72, | ||
| 169 | 0x5f, 0x50, 0x72, 0x69, 0x6e, 0x63, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 170 | 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x65, 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 171 | 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x75, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 172 | 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x6e, 0x61, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 173 | 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x67, 0x6f, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 174 | 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x74, 0x69, 0x6e, 0x69, 0x71, 0x75, 0x65, 0x0d, 0x0a, | ||
| 175 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x72, 0x6f, | ||
| 176 | 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x7a, 0x61, 0x74, | ||
| 177 | 0x6c, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x6e, | ||
| 178 | 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, | ||
| 179 | 0x6e, 0x6f, 0x6d, 0x69, 0x6e, 0x65, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 180 | 0x2f, 0x4d, 0x65, 0x72, 0x69, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 181 | 0x2f, 0x4d, 0x65, 0x74, 0x6c, 0x61, 0x6b, 0x61, 0x74, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 182 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x5f, 0x43, 0x69, 0x74, 0x79, | ||
| 183 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x69, 0x71, 0x75, 0x65, 0x6c, | ||
| 184 | 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x63, | ||
| 185 | 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, | ||
| 186 | 0x74, 0x65, 0x72, 0x72, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 187 | 0x4d, 0x6f, 0x6e, 0x74, 0x65, 0x76, 0x69, 0x64, 0x65, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 188 | 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x72, 0x65, 0x61, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 189 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x73, 0x65, 0x72, 0x72, 0x61, 0x74, | ||
| 190 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x61, 0x73, 0x73, 0x61, 0x75, | ||
| 191 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x5f, 0x59, 0x6f, | ||
| 192 | 0x72, 0x6b, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x69, 0x70, 0x69, | ||
| 193 | 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x6d, | ||
| 194 | 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, | ||
| 195 | 0x68, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4f, 0x6a, 0x69, 0x6e, | ||
| 196 | 0x61, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e, | ||
| 197 | 0x61, 0x6d, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x61, 0x6e, | ||
| 198 | 0x67, 0x6e, 0x69, 0x72, 0x74, 0x75, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 199 | 0x61, 0x2f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x61, 0x72, 0x69, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 200 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x68, 0x6f, 0x65, 0x6e, 0x69, 0x78, 0x0d, 0x0a, 0x41, | ||
| 201 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x2d, 0x61, 0x75, 0x2d, 0x50, | ||
| 202 | 0x72, 0x69, 0x6e, 0x63, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, | ||
| 203 | 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 204 | 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x6f, 0x5f, 0x56, 0x65, 0x6c, 0x68, 0x6f, 0x0d, 0x0a, | ||
| 205 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x6f, 0x66, 0x5f, | ||
| 206 | 0x53, 0x70, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x50, | ||
| 207 | 0x75, 0x65, 0x72, 0x74, 0x6f, 0x5f, 0x52, 0x69, 0x63, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 208 | 0x69, 0x63, 0x61, 0x2f, 0x50, 0x75, 0x6e, 0x74, 0x61, 0x5f, 0x41, 0x72, 0x65, 0x6e, 0x61, 0x73, | ||
| 209 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x61, 0x69, 0x6e, 0x79, 0x5f, | ||
| 210 | 0x52, 0x69, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, | ||
| 211 | 0x61, 0x6e, 0x6b, 0x69, 0x6e, 0x5f, 0x49, 0x6e, 0x6c, 0x65, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 212 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x63, 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 213 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x67, 0x69, 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 214 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x75, 0x74, 0x65, 0x0d, 0x0a, 0x41, | ||
| 215 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x42, 0x72, 0x61, 0x6e, 0x63, | ||
| 216 | 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x73, 0x61, 0x72, | ||
| 217 | 0x69, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, | ||
| 218 | 0x61, 0x72, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, | ||
| 219 | 0x6e, 0x74, 0x61, 0x5f, 0x49, 0x73, 0x61, 0x62, 0x65, 0x6c, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 220 | 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x69, 0x61, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 221 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x74, 0x6f, 0x5f, 0x44, 0x6f, 0x6d, 0x69, | ||
| 222 | 0x6e, 0x67, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x61, 0x6f, | ||
| 223 | 0x5f, 0x50, 0x61, 0x75, 0x6c, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 224 | 0x53, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x73, 0x75, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 225 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x68, 0x69, 0x70, 0x72, 0x6f, 0x63, 0x6b, 0x0d, 0x0a, | ||
| 226 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x69, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41, | ||
| 227 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x42, 0x61, 0x72, 0x74, 0x68, 0x65, | ||
| 228 | 0x6c, 0x65, 0x6d, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, | ||
| 229 | 0x5f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 230 | 0x53, 0x74, 0x5f, 0x4b, 0x69, 0x74, 0x74, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 231 | 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x4c, 0x75, 0x63, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 232 | 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x54, 0x68, 0x6f, 0x6d, 0x61, 0x73, 0x0d, 0x0a, 0x41, | ||
| 233 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x74, 0x5f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, | ||
| 234 | 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x77, 0x69, 0x66, 0x74, | ||
| 235 | 0x5f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 236 | 0x61, 0x2f, 0x54, 0x65, 0x67, 0x75, 0x63, 0x69, 0x67, 0x61, 0x6c, 0x70, 0x61, 0x0d, 0x0a, 0x41, | ||
| 237 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6d, | ||
| 238 | 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x68, 0x75, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x42, 0x61, | ||
| 239 | 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x69, 0x6a, 0x75, 0x61, | ||
| 240 | 0x6e, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, 0x6f, | ||
| 241 | 0x6e, 0x74, 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x54, 0x6f, 0x72, | ||
| 242 | 0x74, 0x6f, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x56, 0x61, | ||
| 243 | 0x6e, 0x63, 0x6f, 0x75, 0x76, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 244 | 0x2f, 0x56, 0x69, 0x72, 0x67, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 245 | 0x2f, 0x57, 0x68, 0x69, 0x74, 0x65, 0x68, 0x6f, 0x72, 0x73, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, | ||
| 246 | 0x72, 0x69, 0x63, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x6e, 0x69, 0x70, 0x65, 0x67, 0x0d, 0x0a, 0x41, | ||
| 247 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x61, 0x74, 0x0d, 0x0a, | ||
| 248 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x59, 0x65, 0x6c, 0x6c, 0x6f, 0x77, 0x6b, 0x6e, | ||
| 249 | 0x69, 0x66, 0x65, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, | ||
| 250 | 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x42, 0x75, 0x65, 0x6e, 0x6f, 0x73, 0x5f, 0x41, 0x69, | ||
| 251 | 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, | ||
| 252 | 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x61, 0x74, 0x61, 0x6d, 0x61, 0x72, 0x63, 0x61, | ||
| 253 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, | ||
| 254 | 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x64, 0x52, 0x69, 0x76, 0x61, 0x64, 0x61, 0x76, | ||
| 255 | 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, | ||
| 256 | 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x43, 0x6f, 0x72, 0x64, 0x6f, 0x62, 0x61, 0x0d, 0x0a, 0x41, | ||
| 257 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, | ||
| 258 | 0x2f, 0x4a, 0x75, 0x6a, 0x75, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 259 | 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4c, 0x61, 0x5f, 0x52, 0x69, 0x6f, | ||
| 260 | 0x6a, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, | ||
| 261 | 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x4d, 0x65, 0x6e, 0x64, 0x6f, 0x7a, 0x61, 0x0d, 0x0a, 0x41, | ||
| 262 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, | ||
| 263 | 0x2f, 0x52, 0x69, 0x6f, 0x5f, 0x47, 0x61, 0x6c, 0x6c, 0x65, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x41, | ||
| 264 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, | ||
| 265 | 0x2f, 0x53, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, | ||
| 266 | 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4a, 0x75, | ||
| 267 | 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, | ||
| 268 | 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4c, 0x75, 0x69, 0x73, 0x0d, 0x0a, | ||
| 269 | 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, | ||
| 270 | 0x61, 0x2f, 0x54, 0x75, 0x63, 0x75, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, | ||
| 271 | 0x63, 0x61, 0x2f, 0x41, 0x72, 0x67, 0x65, 0x6e, 0x74, 0x69, 0x6e, 0x61, 0x2f, 0x55, 0x73, 0x68, | ||
| 272 | 0x75, 0x61, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, | ||
| 273 | 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x70, 0x6f, 0x6c, | ||
| 274 | 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, | ||
| 275 | 0x61, 0x6e, 0x61, 0x2f, 0x4b, 0x6e, 0x6f, 0x78, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 276 | 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x4d, 0x61, 0x72, 0x65, 0x6e, 0x67, | ||
| 277 | 0x6f, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, | ||
| 278 | 0x6e, 0x61, 0x2f, 0x50, 0x65, 0x74, 0x65, 0x72, 0x73, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41, | ||
| 279 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x54, | ||
| 280 | 0x65, 0x6c, 0x6c, 0x5f, 0x43, 0x69, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, | ||
| 281 | 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x56, 0x65, 0x76, 0x61, 0x79, 0x0d, | ||
| 282 | 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, | ||
| 283 | 0x2f, 0x56, 0x69, 0x6e, 0x63, 0x65, 0x6e, 0x6e, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 284 | 0x69, 0x63, 0x61, 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2f, 0x57, 0x69, 0x6e, 0x61, | ||
| 285 | 0x6d, 0x61, 0x63, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e, | ||
| 286 | 0x74, 0x75, 0x63, 0x6b, 0x79, 0x2f, 0x4c, 0x6f, 0x75, 0x69, 0x73, 0x76, 0x69, 0x6c, 0x6c, 0x65, | ||
| 287 | 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4b, 0x65, 0x6e, 0x74, 0x75, 0x63, | ||
| 288 | 0x6b, 0x79, 0x2f, 0x4d, 0x6f, 0x6e, 0x74, 0x69, 0x63, 0x65, 0x6c, 0x6c, 0x6f, 0x0d, 0x0a, 0x41, | ||
| 289 | 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, | ||
| 290 | 0x6f, 0x74, 0x61, 0x2f, 0x42, 0x65, 0x75, 0x6c, 0x61, 0x68, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, | ||
| 291 | 0x69, 0x63, 0x61, 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, | ||
| 292 | 0x2f, 0x43, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6d, 0x65, 0x72, 0x69, 0x63, 0x61, | ||
| 293 | 0x2f, 0x4e, 0x6f, 0x72, 0x74, 0x68, 0x5f, 0x44, 0x61, 0x6b, 0x6f, 0x74, 0x61, 0x2f, 0x4e, 0x65, | ||
| 294 | 0x77, 0x5f, 0x53, 0x61, 0x6c, 0x65, 0x6d, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, | ||
| 295 | 0x69, 0x63, 0x61, 0x2f, 0x43, 0x61, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, | ||
| 296 | 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x61, 0x76, 0x69, 0x73, 0x0d, 0x0a, 0x41, 0x6e, 0x74, | ||
| 297 | 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x44, 0x75, 0x6d, 0x6f, 0x6e, 0x74, 0x44, 0x55, | ||
| 298 | 0x72, 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, | ||
| 299 | 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x71, 0x75, 0x61, 0x72, 0x69, 0x65, 0x0d, 0x0a, 0x41, 0x6e, | ||
| 300 | 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x61, 0x77, 0x73, 0x6f, 0x6e, 0x0d, | ||
| 301 | 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x4d, 0x63, 0x4d, 0x75, | ||
| 302 | 0x72, 0x64, 0x6f, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, | ||
| 303 | 0x50, 0x61, 0x6c, 0x6d, 0x65, 0x72, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, | ||
| 304 | 0x63, 0x61, 0x2f, 0x52, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, | ||
| 305 | 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f, 0x50, 0x6f, 0x6c, | ||
| 306 | 0x65, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, 0x53, 0x79, | ||
| 307 | 0x6f, 0x77, 0x61, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, 0x61, 0x2f, | ||
| 308 | 0x54, 0x72, 0x6f, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x6e, 0x74, 0x61, 0x72, 0x63, 0x74, 0x69, 0x63, | ||
| 309 | 0x61, 0x2f, 0x56, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x72, 0x63, 0x74, 0x69, 0x63, | ||
| 310 | 0x2f, 0x4c, 0x6f, 0x6e, 0x67, 0x79, 0x65, 0x61, 0x72, 0x62, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41, | ||
| 311 | 0x73, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, | ||
| 312 | 0x6c, 0x6d, 0x61, 0x74, 0x79, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6d, 0x6d, 0x61, | ||
| 313 | 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x6e, 0x61, 0x64, 0x79, 0x72, 0x0d, 0x0a, | ||
| 314 | 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x71, 0x74, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 315 | 0x2f, 0x41, 0x71, 0x74, 0x6f, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73, | ||
| 316 | 0x68, 0x67, 0x61, 0x62, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x73, 0x68, | ||
| 317 | 0x6b, 0x68, 0x61, 0x62, 0x61, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x41, 0x74, 0x79, | ||
| 318 | 0x72, 0x61, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x67, 0x68, 0x64, 0x61, | ||
| 319 | 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x68, 0x72, 0x61, 0x69, 0x6e, 0x0d, | ||
| 320 | 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x61, 0x6b, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 321 | 0x2f, 0x42, 0x61, 0x6e, 0x67, 0x6b, 0x6f, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, | ||
| 322 | 0x61, 0x72, 0x6e, 0x61, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x65, 0x69, | ||
| 323 | 0x72, 0x75, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x69, 0x73, 0x68, 0x6b, 0x65, | ||
| 324 | 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x75, 0x6e, 0x65, 0x69, 0x0d, 0x0a, | ||
| 325 | 0x41, 0x73, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6c, 0x63, 0x75, 0x74, 0x74, 0x61, 0x0d, 0x0a, 0x41, | ||
| 326 | 0x73, 0x69, 0x61, 0x2f, 0x43, 0x68, 0x69, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, | ||
| 327 | 0x43, 0x68, 0x6f, 0x69, 0x62, 0x61, 0x6c, 0x73, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 328 | 0x2f, 0x43, 0x68, 0x6f, 0x6e, 0x67, 0x71, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 329 | 0x2f, 0x43, 0x68, 0x75, 0x6e, 0x67, 0x6b, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 330 | 0x2f, 0x43, 0x6f, 0x6c, 0x6f, 0x6d, 0x62, 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, | ||
| 331 | 0x61, 0x63, 0x63, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x6d, 0x61, 0x73, | ||
| 332 | 0x63, 0x75, 0x73, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x68, 0x61, 0x6b, 0x61, 0x0d, | ||
| 333 | 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x69, 0x6c, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 334 | 0x2f, 0x44, 0x75, 0x62, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x44, 0x75, 0x73, | ||
| 335 | 0x68, 0x61, 0x6e, 0x62, 0x65, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x46, 0x61, 0x6d, 0x61, | ||
| 336 | 0x67, 0x75, 0x73, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x47, 0x61, 0x7a, 0x61, | ||
| 337 | 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x61, 0x72, 0x62, 0x69, 0x6e, 0x0d, 0x0a, 0x41, | ||
| 338 | 0x73, 0x69, 0x61, 0x2f, 0x48, 0x65, 0x62, 0x72, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 339 | 0x2f, 0x48, 0x6f, 0x6e, 0x67, 0x5f, 0x4b, 0x6f, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 340 | 0x2f, 0x48, 0x6f, 0x76, 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x48, 0x6f, 0x5f, 0x43, | ||
| 341 | 0x68, 0x69, 0x5f, 0x4d, 0x69, 0x6e, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x72, | ||
| 342 | 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x49, 0x73, 0x74, 0x61, | ||
| 343 | 0x6e, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x6b, 0x61, 0x72, | ||
| 344 | 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x61, 0x79, 0x61, 0x70, 0x75, 0x72, | ||
| 345 | 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4a, 0x65, 0x72, 0x75, 0x73, 0x61, 0x6c, 0x65, | ||
| 346 | 0x6d, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x62, 0x75, 0x6c, 0x0d, 0x0a, 0x41, | ||
| 347 | 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x6d, 0x63, 0x68, 0x61, 0x74, 0x6b, 0x61, 0x0d, 0x0a, 0x41, | ||
| 348 | 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x61, 0x72, 0x61, 0x63, 0x68, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, | ||
| 349 | 0x61, 0x2f, 0x4b, 0x61, 0x73, 0x68, 0x67, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, | ||
| 350 | 0x4b, 0x61, 0x74, 0x68, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, | ||
| 351 | 0x4b, 0x61, 0x74, 0x6d, 0x61, 0x6e, 0x64, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, | ||
| 352 | 0x68, 0x61, 0x6e, 0x64, 0x79, 0x67, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x6f, | ||
| 353 | 0x6c, 0x6b, 0x61, 0x74, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x72, 0x61, 0x73, | ||
| 354 | 0x6e, 0x6f, 0x79, 0x61, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, 0x75, | ||
| 355 | 0x61, 0x6c, 0x61, 0x5f, 0x4c, 0x75, 0x6d, 0x70, 0x75, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 356 | 0x2f, 0x4b, 0x75, 0x63, 0x68, 0x69, 0x6e, 0x67, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4b, | ||
| 357 | 0x75, 0x77, 0x61, 0x69, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, | ||
| 358 | 0x6f, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x63, 0x61, 0x75, 0x0d, 0x0a, 0x41, | ||
| 359 | 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x61, 0x67, 0x61, 0x64, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, | ||
| 360 | 0x61, 0x2f, 0x4d, 0x61, 0x6b, 0x61, 0x73, 0x73, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 361 | 0x2f, 0x4d, 0x61, 0x6e, 0x69, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4d, 0x75, | ||
| 362 | 0x73, 0x63, 0x61, 0x74, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, | ||
| 363 | 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, 0x6b, 0x75, 0x7a, | ||
| 364 | 0x6e, 0x65, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4e, 0x6f, 0x76, 0x6f, | ||
| 365 | 0x73, 0x69, 0x62, 0x69, 0x72, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x6d, | ||
| 366 | 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x4f, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x41, | ||
| 367 | 0x73, 0x69, 0x61, 0x2f, 0x50, 0x68, 0x6e, 0x6f, 0x6d, 0x5f, 0x50, 0x65, 0x6e, 0x68, 0x0d, 0x0a, | ||
| 368 | 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x6f, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x61, 0x6b, 0x0d, 0x0a, | ||
| 369 | 0x41, 0x73, 0x69, 0x61, 0x2f, 0x50, 0x79, 0x6f, 0x6e, 0x67, 0x79, 0x61, 0x6e, 0x67, 0x0d, 0x0a, | ||
| 370 | 0x41, 0x73, 0x69, 0x61, 0x2f, 0x51, 0x61, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 371 | 0x2f, 0x51, 0x79, 0x7a, 0x79, 0x6c, 0x6f, 0x72, 0x64, 0x61, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 372 | 0x2f, 0x52, 0x61, 0x6e, 0x67, 0x6f, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x52, | ||
| 373 | 0x69, 0x79, 0x61, 0x64, 0x68, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x69, 0x67, | ||
| 374 | 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6b, 0x68, 0x61, 0x6c, 0x69, | ||
| 375 | 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x6b, 0x61, 0x6e, | ||
| 376 | 0x64, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x53, 0x65, 0x6f, 0x75, 0x6c, 0x0d, 0x0a, 0x41, | ||
| 377 | 0x73, 0x69, 0x61, 0x2f, 0x53, 0x68, 0x61, 0x6e, 0x67, 0x68, 0x61, 0x69, 0x0d, 0x0a, 0x41, 0x73, | ||
| 378 | 0x69, 0x61, 0x2f, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70, 0x6f, 0x72, 0x65, 0x0d, 0x0a, 0x41, 0x73, | ||
| 379 | 0x69, 0x61, 0x2f, 0x53, 0x72, 0x65, 0x64, 0x6e, 0x65, 0x6b, 0x6f, 0x6c, 0x79, 0x6d, 0x73, 0x6b, | ||
| 380 | 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x69, 0x70, 0x65, 0x69, 0x0d, 0x0a, 0x41, | ||
| 381 | 0x73, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x68, 0x6b, 0x65, 0x6e, 0x74, 0x0d, 0x0a, 0x41, 0x73, | ||
| 382 | 0x69, 0x61, 0x2f, 0x54, 0x62, 0x69, 0x6c, 0x69, 0x73, 0x69, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, | ||
| 383 | 0x2f, 0x54, 0x65, 0x68, 0x72, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x65, | ||
| 384 | 0x6c, 0x5f, 0x41, 0x76, 0x69, 0x76, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, | ||
| 385 | 0x6d, 0x62, 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x68, 0x69, 0x6d, 0x70, 0x68, | ||
| 386 | 0x75, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6b, 0x79, 0x6f, 0x0d, 0x0a, 0x41, | ||
| 387 | 0x73, 0x69, 0x61, 0x2f, 0x54, 0x6f, 0x6d, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, | ||
| 388 | 0x55, 0x6a, 0x75, 0x6e, 0x67, 0x5f, 0x50, 0x61, 0x6e, 0x64, 0x61, 0x6e, 0x67, 0x0d, 0x0a, 0x41, | ||
| 389 | 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x61, 0x6e, 0x62, 0x61, 0x61, 0x74, 0x61, 0x72, 0x0d, | ||
| 390 | 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x6c, 0x61, 0x6e, 0x5f, 0x42, 0x61, 0x74, 0x6f, 0x72, | ||
| 391 | 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, 0x55, 0x72, 0x75, 0x6d, 0x71, 0x69, 0x0d, 0x0a, 0x41, | ||
| 392 | 0x73, 0x69, 0x61, 0x2f, 0x55, 0x73, 0x74, 0x2d, 0x4e, 0x65, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x73, | ||
| 393 | 0x69, 0x61, 0x2f, 0x56, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x73, | ||
| 394 | 0x69, 0x61, 0x2f, 0x56, 0x6c, 0x61, 0x64, 0x69, 0x76, 0x6f, 0x73, 0x74, 0x6f, 0x6b, 0x0d, 0x0a, | ||
| 395 | 0x41, 0x73, 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6b, 0x75, 0x74, 0x73, 0x6b, 0x0d, 0x0a, 0x41, 0x73, | ||
| 396 | 0x69, 0x61, 0x2f, 0x59, 0x61, 0x6e, 0x67, 0x6f, 0x6e, 0x0d, 0x0a, 0x41, 0x73, 0x69, 0x61, 0x2f, | ||
| 397 | 0x59, 0x65, 0x6b, 0x61, 0x74, 0x65, 0x72, 0x69, 0x6e, 0x62, 0x75, 0x72, 0x67, 0x0d, 0x0a, 0x41, | ||
| 398 | 0x73, 0x69, 0x61, 0x2f, 0x59, 0x65, 0x72, 0x65, 0x76, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c, | ||
| 399 | 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x41, 0x7a, 0x6f, 0x72, 0x65, 0x73, 0x0d, 0x0a, 0x41, 0x74, | ||
| 400 | 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x42, 0x65, 0x72, 0x6d, 0x75, 0x64, 0x61, 0x0d, 0x0a, | ||
| 401 | 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x6e, 0x61, 0x72, 0x79, 0x0d, | ||
| 402 | 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x43, 0x61, 0x70, 0x65, 0x5f, 0x56, | ||
| 403 | 0x65, 0x72, 0x64, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x46, | ||
| 404 | 0x61, 0x65, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, | ||
| 405 | 0x46, 0x61, 0x72, 0x6f, 0x65, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, | ||
| 406 | 0x4a, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x79, 0x65, 0x6e, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, | ||
| 407 | 0x74, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x64, 0x65, 0x69, 0x72, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c, | ||
| 408 | 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x52, 0x65, 0x79, 0x6b, 0x6a, 0x61, 0x76, 0x69, 0x6b, 0x0d, | ||
| 409 | 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, 0x63, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x5f, | ||
| 410 | 0x47, 0x65, 0x6f, 0x72, 0x67, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, 0x74, 0x69, | ||
| 411 | 0x63, 0x2f, 0x53, 0x74, 0x61, 0x6e, 0x6c, 0x65, 0x79, 0x0d, 0x0a, 0x41, 0x74, 0x6c, 0x61, 0x6e, | ||
| 412 | 0x74, 0x69, 0x63, 0x2f, 0x53, 0x74, 0x5f, 0x48, 0x65, 0x6c, 0x65, 0x6e, 0x61, 0x0d, 0x0a, 0x41, | ||
| 413 | 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x43, 0x54, 0x0d, 0x0a, 0x41, 0x75, | ||
| 414 | 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x41, 0x64, 0x65, 0x6c, 0x61, 0x69, 0x64, 0x65, | ||
| 415 | 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x42, 0x72, 0x69, 0x73, | ||
| 416 | 0x62, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, | ||
| 417 | 0x42, 0x72, 0x6f, 0x6b, 0x65, 0x6e, 0x5f, 0x48, 0x69, 0x6c, 0x6c, 0x0d, 0x0a, 0x41, 0x75, 0x73, | ||
| 418 | 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x61, 0x6e, 0x62, 0x65, 0x72, 0x72, 0x61, 0x0d, | ||
| 419 | 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x43, 0x75, 0x72, 0x72, 0x69, | ||
| 420 | 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x44, 0x61, 0x72, | ||
| 421 | 0x77, 0x69, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x45, | ||
| 422 | 0x75, 0x63, 0x6c, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, | ||
| 423 | 0x48, 0x6f, 0x62, 0x61, 0x72, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, | ||
| 424 | 0x61, 0x2f, 0x4c, 0x48, 0x49, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, | ||
| 425 | 0x2f, 0x4c, 0x69, 0x6e, 0x64, 0x65, 0x6d, 0x61, 0x6e, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, | ||
| 426 | 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4c, 0x6f, 0x72, 0x64, 0x5f, 0x48, 0x6f, 0x77, 0x65, 0x0d, 0x0a, | ||
| 427 | 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4d, 0x65, 0x6c, 0x62, 0x6f, 0x75, | ||
| 428 | 0x72, 0x6e, 0x65, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x4e, | ||
| 429 | 0x6f, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, | ||
| 430 | 0x4e, 0x53, 0x57, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x50, | ||
| 431 | 0x65, 0x72, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, | ||
| 432 | 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, | ||
| 433 | 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x6f, 0x75, 0x74, 0x68, 0x0d, 0x0a, 0x41, 0x75, 0x73, | ||
| 434 | 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x53, 0x79, 0x64, 0x6e, 0x65, 0x79, 0x0d, 0x0a, 0x41, | ||
| 435 | 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x54, 0x61, 0x73, 0x6d, 0x61, 0x6e, 0x69, | ||
| 436 | 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x2f, 0x56, 0x69, 0x63, | ||
| 437 | 0x74, 0x6f, 0x72, 0x69, 0x61, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, | ||
| 438 | 0x2f, 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x41, 0x75, 0x73, 0x74, 0x72, 0x61, 0x6c, 0x69, 0x61, | ||
| 439 | 0x2f, 0x59, 0x61, 0x6e, 0x63, 0x6f, 0x77, 0x69, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61, | ||
| 440 | 0x7a, 0x69, 0x6c, 0x2f, 0x41, 0x63, 0x72, 0x65, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c, | ||
| 441 | 0x2f, 0x44, 0x65, 0x4e, 0x6f, 0x72, 0x6f, 0x6e, 0x68, 0x61, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, | ||
| 442 | 0x69, 0x6c, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x42, 0x72, 0x61, 0x7a, 0x69, 0x6c, 0x2f, | ||
| 443 | 0x57, 0x65, 0x73, 0x74, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x41, 0x74, 0x6c, | ||
| 444 | 0x61, 0x6e, 0x74, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x43, 0x65, | ||
| 445 | 0x6e, 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61, | ||
| 446 | 0x73, 0x74, 0x2d, 0x53, 0x61, 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d, | ||
| 447 | 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x6e, 0x0d, | ||
| 448 | 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, | ||
| 449 | 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x4e, 0x65, 0x77, 0x66, 0x6f, 0x75, 0x6e, | ||
| 450 | 0x64, 0x6c, 0x61, 0x6e, 0x64, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x50, 0x61, | ||
| 451 | 0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, 0x64, 0x61, 0x2f, 0x53, 0x61, | ||
| 452 | 0x73, 0x6b, 0x61, 0x74, 0x63, 0x68, 0x65, 0x77, 0x61, 0x6e, 0x0d, 0x0a, 0x43, 0x61, 0x6e, 0x61, | ||
| 453 | 0x64, 0x61, 0x2f, 0x59, 0x75, 0x6b, 0x6f, 0x6e, 0x0d, 0x0a, 0x43, 0x68, 0x69, 0x6c, 0x65, 0x2f, | ||
| 454 | 0x43, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x65, 0x6e, 0x74, 0x61, 0x6c, 0x0d, 0x0a, 0x43, 0x68, 0x69, | ||
| 455 | 0x6c, 0x65, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, 0x49, 0x73, 0x6c, 0x61, 0x6e, 0x64, 0x0d, | ||
| 456 | 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, | ||
| 457 | 0x54, 0x2b, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x0d, 0x0a, | ||
| 458 | 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, | ||
| 459 | 0x47, 0x4d, 0x54, 0x2b, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, | ||
| 460 | 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x32, 0x0d, 0x0a, 0x45, | ||
| 461 | 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, | ||
| 462 | 0x54, 0x2b, 0x34, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x35, 0x0d, 0x0a, | ||
| 463 | 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, | ||
| 464 | 0x4d, 0x54, 0x2b, 0x37, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x38, 0x0d, | ||
| 465 | 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2b, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, | ||
| 466 | 0x47, 0x4d, 0x54, 0x2d, 0x30, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, | ||
| 467 | 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x30, 0x0d, 0x0a, 0x45, 0x74, | ||
| 468 | 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x31, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, | ||
| 469 | 0x54, 0x2d, 0x31, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x33, | ||
| 470 | 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x31, 0x34, 0x0d, 0x0a, 0x45, 0x74, | ||
| 471 | 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x32, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, | ||
| 472 | 0x2d, 0x33, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x34, 0x0d, 0x0a, 0x45, | ||
| 473 | 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x35, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, | ||
| 474 | 0x54, 0x2d, 0x36, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x37, 0x0d, 0x0a, | ||
| 475 | 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x2d, 0x38, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, | ||
| 476 | 0x4d, 0x54, 0x2d, 0x39, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x47, 0x4d, 0x54, 0x30, 0x0d, 0x0a, | ||
| 477 | 0x45, 0x74, 0x63, 0x2f, 0x47, 0x72, 0x65, 0x65, 0x6e, 0x77, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x45, | ||
| 478 | 0x74, 0x63, 0x2f, 0x55, 0x43, 0x54, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x6e, 0x69, 0x76, | ||
| 479 | 0x65, 0x72, 0x73, 0x61, 0x6c, 0x0d, 0x0a, 0x45, 0x74, 0x63, 0x2f, 0x55, 0x54, 0x43, 0x0d, 0x0a, | ||
| 480 | 0x45, 0x74, 0x63, 0x2f, 0x5a, 0x75, 0x6c, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, | ||
| 481 | 0x2f, 0x41, 0x6d, 0x73, 0x74, 0x65, 0x72, 0x64, 0x61, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, | ||
| 482 | 0x70, 0x65, 0x2f, 0x41, 0x6e, 0x64, 0x6f, 0x72, 0x72, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, | ||
| 483 | 0x70, 0x65, 0x2f, 0x41, 0x73, 0x74, 0x72, 0x61, 0x6b, 0x68, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75, | ||
| 484 | 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x41, 0x74, 0x68, 0x65, 0x6e, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, | ||
| 485 | 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x66, 0x61, 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, | ||
| 486 | 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x6c, 0x67, 0x72, 0x61, 0x64, 0x65, 0x0d, 0x0a, 0x45, 0x75, | ||
| 487 | 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x65, 0x72, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, | ||
| 488 | 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x61, 0x74, 0x69, 0x73, 0x6c, 0x61, 0x76, 0x61, 0x0d, 0x0a, | ||
| 489 | 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x72, 0x75, 0x73, 0x73, 0x65, 0x6c, 0x73, 0x0d, | ||
| 490 | 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x63, 0x68, 0x61, 0x72, 0x65, 0x73, | ||
| 491 | 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x64, 0x61, 0x70, 0x65, | ||
| 492 | 0x73, 0x74, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x42, 0x75, 0x73, 0x69, 0x6e, | ||
| 493 | 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x68, 0x69, 0x73, | ||
| 494 | 0x69, 0x6e, 0x61, 0x75, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x43, 0x6f, 0x70, | ||
| 495 | 0x65, 0x6e, 0x68, 0x61, 0x67, 0x65, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, | ||
| 496 | 0x44, 0x75, 0x62, 0x6c, 0x69, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x47, | ||
| 497 | 0x69, 0x62, 0x72, 0x61, 0x6c, 0x74, 0x61, 0x72, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, | ||
| 498 | 0x2f, 0x47, 0x75, 0x65, 0x72, 0x6e, 0x73, 0x65, 0x79, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, | ||
| 499 | 0x65, 0x2f, 0x48, 0x65, 0x6c, 0x73, 0x69, 0x6e, 0x6b, 0x69, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, | ||
| 500 | 0x70, 0x65, 0x2f, 0x49, 0x73, 0x6c, 0x65, 0x5f, 0x6f, 0x66, 0x5f, 0x4d, 0x61, 0x6e, 0x0d, 0x0a, | ||
| 501 | 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x49, 0x73, 0x74, 0x61, 0x6e, 0x62, 0x75, 0x6c, 0x0d, | ||
| 502 | 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4a, 0x65, 0x72, 0x73, 0x65, 0x79, 0x0d, 0x0a, | ||
| 503 | 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x61, 0x6c, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x72, | ||
| 504 | 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x65, 0x76, 0x0d, | ||
| 505 | 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4b, 0x69, 0x72, 0x6f, 0x76, 0x0d, 0x0a, 0x45, | ||
| 506 | 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x69, 0x73, 0x62, 0x6f, 0x6e, 0x0d, 0x0a, 0x45, 0x75, | ||
| 507 | 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6a, 0x75, 0x62, 0x6c, 0x6a, 0x61, 0x6e, 0x61, 0x0d, 0x0a, | ||
| 508 | 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x6f, 0x6e, 0x64, 0x6f, 0x6e, 0x0d, 0x0a, 0x45, | ||
| 509 | 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4c, 0x75, 0x78, 0x65, 0x6d, 0x62, 0x6f, 0x75, 0x72, 0x67, | ||
| 510 | 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x64, 0x72, 0x69, 0x64, 0x0d, | ||
| 511 | 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x6c, 0x74, 0x61, 0x0d, 0x0a, 0x45, | ||
| 512 | 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x61, 0x72, 0x69, 0x65, 0x68, 0x61, 0x6d, 0x6e, 0x0d, | ||
| 513 | 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x69, 0x6e, 0x73, 0x6b, 0x0d, 0x0a, 0x45, | ||
| 514 | 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x6e, 0x61, 0x63, 0x6f, 0x0d, 0x0a, 0x45, 0x75, | ||
| 515 | 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x4d, 0x6f, 0x73, 0x63, 0x6f, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72, | ||
| 516 | 0x6f, 0x70, 0x65, 0x2f, 0x4e, 0x69, 0x63, 0x6f, 0x73, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, | ||
| 517 | 0x6f, 0x70, 0x65, 0x2f, 0x4f, 0x73, 0x6c, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, | ||
| 518 | 0x2f, 0x50, 0x61, 0x72, 0x69, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x50, | ||
| 519 | 0x6f, 0x64, 0x67, 0x6f, 0x72, 0x69, 0x63, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, | ||
| 520 | 0x2f, 0x50, 0x72, 0x61, 0x67, 0x75, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, | ||
| 521 | 0x52, 0x69, 0x67, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x52, 0x6f, 0x6d, | ||
| 522 | 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6d, 0x61, 0x72, 0x61, | ||
| 523 | 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x6e, 0x5f, 0x4d, 0x61, 0x72, | ||
| 524 | 0x69, 0x6e, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, 0x61, | ||
| 525 | 0x6a, 0x65, 0x76, 0x6f, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x61, 0x72, | ||
| 526 | 0x61, 0x74, 0x6f, 0x76, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x69, 0x6d, | ||
| 527 | 0x66, 0x65, 0x72, 0x6f, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, | ||
| 528 | 0x53, 0x6b, 0x6f, 0x70, 0x6a, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, | ||
| 529 | 0x6f, 0x66, 0x69, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x53, 0x74, 0x6f, | ||
| 530 | 0x63, 0x6b, 0x68, 0x6f, 0x6c, 0x6d, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, | ||
| 531 | 0x61, 0x6c, 0x6c, 0x69, 0x6e, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, | ||
| 532 | 0x69, 0x72, 0x61, 0x6e, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x54, 0x69, | ||
| 533 | 0x72, 0x61, 0x73, 0x70, 0x6f, 0x6c, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x55, | ||
| 534 | 0x6c, 0x79, 0x61, 0x6e, 0x6f, 0x76, 0x73, 0x6b, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, | ||
| 535 | 0x2f, 0x55, 0x7a, 0x68, 0x67, 0x6f, 0x72, 0x6f, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, | ||
| 536 | 0x65, 0x2f, 0x56, 0x61, 0x64, 0x75, 0x7a, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, | ||
| 537 | 0x56, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6e, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, | ||
| 538 | 0x56, 0x69, 0x65, 0x6e, 0x6e, 0x61, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, | ||
| 539 | 0x69, 0x6c, 0x6e, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x56, | ||
| 540 | 0x6f, 0x6c, 0x67, 0x6f, 0x67, 0x72, 0x61, 0x64, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, | ||
| 541 | 0x2f, 0x57, 0x61, 0x72, 0x73, 0x61, 0x77, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, | ||
| 542 | 0x5a, 0x61, 0x67, 0x72, 0x65, 0x62, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, 0x65, 0x2f, 0x5a, | ||
| 543 | 0x61, 0x70, 0x6f, 0x72, 0x6f, 0x7a, 0x68, 0x79, 0x65, 0x0d, 0x0a, 0x45, 0x75, 0x72, 0x6f, 0x70, | ||
| 544 | 0x65, 0x2f, 0x5a, 0x75, 0x72, 0x69, 0x63, 0x68, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, | ||
| 545 | 0x2f, 0x41, 0x6e, 0x74, 0x61, 0x6e, 0x61, 0x6e, 0x61, 0x72, 0x69, 0x76, 0x6f, 0x0d, 0x0a, 0x49, | ||
| 546 | 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e, | ||
| 547 | 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x68, 0x72, 0x69, 0x73, 0x74, 0x6d, 0x61, 0x73, 0x0d, 0x0a, | ||
| 548 | 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x63, 0x6f, 0x73, 0x0d, 0x0a, 0x49, 0x6e, | ||
| 549 | 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x43, 0x6f, 0x6d, 0x6f, 0x72, 0x6f, 0x0d, 0x0a, 0x49, 0x6e, 0x64, | ||
| 550 | 0x69, 0x61, 0x6e, 0x2f, 0x4b, 0x65, 0x72, 0x67, 0x75, 0x65, 0x6c, 0x65, 0x6e, 0x0d, 0x0a, 0x49, | ||
| 551 | 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x68, 0x65, 0x0d, 0x0a, 0x49, 0x6e, 0x64, 0x69, | ||
| 552 | 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x6c, 0x64, 0x69, 0x76, 0x65, 0x73, 0x0d, 0x0a, 0x49, 0x6e, 0x64, | ||
| 553 | 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x75, 0x72, 0x69, 0x74, 0x69, 0x75, 0x73, 0x0d, 0x0a, 0x49, | ||
| 554 | 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x4d, 0x61, 0x79, 0x6f, 0x74, 0x74, 0x65, 0x0d, 0x0a, 0x49, | ||
| 555 | 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x2f, 0x52, 0x65, 0x75, 0x6e, 0x69, 0x6f, 0x6e, 0x0d, 0x0a, 0x4d, | ||
| 556 | 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x4e, 0x6f, 0x72, 0x74, 0x65, 0x0d, | ||
| 557 | 0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x42, 0x61, 0x6a, 0x61, 0x53, 0x75, 0x72, 0x0d, | ||
| 558 | 0x0a, 0x4d, 0x65, 0x78, 0x69, 0x63, 0x6f, 0x2f, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x0d, | ||
| 559 | 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x70, 0x69, 0x61, 0x0d, 0x0a, 0x50, | ||
| 560 | 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x41, 0x75, 0x63, 0x6b, 0x6c, 0x61, 0x6e, 0x64, 0x0d, | ||
| 561 | 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x42, 0x6f, 0x75, 0x67, 0x61, 0x69, 0x6e, | ||
| 562 | 0x76, 0x69, 0x6c, 0x6c, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x43, | ||
| 563 | 0x68, 0x61, 0x74, 0x68, 0x61, 0x6d, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, | ||
| 564 | 0x43, 0x68, 0x75, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, | ||
| 565 | 0x61, 0x73, 0x74, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, | ||
| 566 | 0x66, 0x61, 0x74, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x45, 0x6e, | ||
| 567 | 0x64, 0x65, 0x72, 0x62, 0x75, 0x72, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, | ||
| 568 | 0x2f, 0x46, 0x61, 0x6b, 0x61, 0x6f, 0x66, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, | ||
| 569 | 0x63, 0x2f, 0x46, 0x69, 0x6a, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, | ||
| 570 | 0x46, 0x75, 0x6e, 0x61, 0x66, 0x75, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, | ||
| 571 | 0x63, 0x2f, 0x47, 0x61, 0x6c, 0x61, 0x70, 0x61, 0x67, 0x6f, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63, | ||
| 572 | 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x61, 0x6d, 0x62, 0x69, 0x65, 0x72, 0x0d, 0x0a, 0x50, 0x61, | ||
| 573 | 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x64, 0x61, 0x6c, 0x63, 0x61, 0x6e, 0x61, | ||
| 574 | 0x6c, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x47, 0x75, 0x61, 0x6d, 0x0d, | ||
| 575 | 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x48, 0x6f, 0x6e, 0x6f, 0x6c, 0x75, 0x6c, | ||
| 576 | 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4a, 0x6f, 0x68, 0x6e, 0x73, | ||
| 577 | 0x74, 0x6f, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4b, 0x69, 0x72, | ||
| 578 | 0x69, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, | ||
| 579 | 0x2f, 0x4b, 0x6f, 0x73, 0x72, 0x61, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, | ||
| 580 | 0x2f, 0x4b, 0x77, 0x61, 0x6a, 0x61, 0x6c, 0x65, 0x69, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, | ||
| 581 | 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x6a, 0x75, 0x72, 0x6f, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, | ||
| 582 | 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x61, 0x72, 0x71, 0x75, 0x65, 0x73, 0x61, 0x73, 0x0d, 0x0a, 0x50, | ||
| 583 | 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4d, 0x69, 0x64, 0x77, 0x61, 0x79, 0x0d, 0x0a, 0x50, | ||
| 584 | 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x61, 0x75, 0x72, 0x75, 0x0d, 0x0a, 0x50, 0x61, | ||
| 585 | 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x69, 0x75, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, | ||
| 586 | 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x72, 0x66, 0x6f, 0x6c, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, | ||
| 587 | 0x69, 0x66, 0x69, 0x63, 0x2f, 0x4e, 0x6f, 0x75, 0x6d, 0x65, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, | ||
| 588 | 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x67, 0x6f, 0x5f, 0x50, 0x61, 0x67, 0x6f, 0x0d, 0x0a, | ||
| 589 | 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x61, 0x6c, 0x61, 0x75, 0x0d, 0x0a, 0x50, | ||
| 590 | 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x69, 0x74, 0x63, 0x61, 0x69, 0x72, 0x6e, 0x0d, | ||
| 591 | 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x68, 0x6e, 0x70, 0x65, 0x69, | ||
| 592 | 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x6e, 0x61, 0x70, 0x65, | ||
| 593 | 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, 0x50, 0x6f, 0x72, 0x74, 0x5f, 0x4d, | ||
| 594 | 0x6f, 0x72, 0x65, 0x73, 0x62, 0x79, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, 0x2f, | ||
| 595 | 0x52, 0x61, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x67, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, | ||
| 596 | 0x69, 0x63, 0x2f, 0x53, 0x61, 0x69, 0x70, 0x61, 0x6e, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, | ||
| 597 | 0x69, 0x63, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, | ||
| 598 | 0x63, 0x2f, 0x54, 0x61, 0x68, 0x69, 0x74, 0x69, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, | ||
| 599 | 0x63, 0x2f, 0x54, 0x61, 0x72, 0x61, 0x77, 0x61, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, | ||
| 600 | 0x63, 0x2f, 0x54, 0x6f, 0x6e, 0x67, 0x61, 0x74, 0x61, 0x70, 0x75, 0x0d, 0x0a, 0x50, 0x61, 0x63, | ||
| 601 | 0x69, 0x66, 0x69, 0x63, 0x2f, 0x54, 0x72, 0x75, 0x6b, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, | ||
| 602 | 0x69, 0x63, 0x2f, 0x57, 0x61, 0x6b, 0x65, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, | ||
| 603 | 0x2f, 0x57, 0x61, 0x6c, 0x6c, 0x69, 0x73, 0x0d, 0x0a, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, 0x63, | ||
| 604 | 0x2f, 0x59, 0x61, 0x70, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x61, 0x73, 0x6b, 0x61, 0x0d, | ||
| 605 | 0x0a, 0x55, 0x53, 0x2f, 0x41, 0x6c, 0x65, 0x75, 0x74, 0x69, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53, | ||
| 606 | 0x2f, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x43, 0x65, 0x6e, | ||
| 607 | 0x74, 0x72, 0x61, 0x6c, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x2d, 0x49, 0x6e, | ||
| 608 | 0x64, 0x69, 0x61, 0x6e, 0x61, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x45, 0x61, 0x73, 0x74, 0x65, 0x72, | ||
| 609 | 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x48, 0x61, 0x77, 0x61, 0x69, 0x69, 0x0d, 0x0a, 0x55, 0x53, | ||
| 610 | 0x2f, 0x49, 0x6e, 0x64, 0x69, 0x61, 0x6e, 0x61, 0x2d, 0x53, 0x74, 0x61, 0x72, 0x6b, 0x65, 0x0d, | ||
| 611 | 0x0a, 0x55, 0x53, 0x2f, 0x4d, 0x69, 0x63, 0x68, 0x69, 0x67, 0x61, 0x6e, 0x0d, 0x0a, 0x55, 0x53, | ||
| 612 | 0x2f, 0x4d, 0x6f, 0x75, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61, | ||
| 613 | 0x63, 0x69, 0x66, 0x69, 0x63, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x50, 0x61, 0x63, 0x69, 0x66, 0x69, | ||
| 614 | 0x63, 0x2d, 0x4e, 0x65, 0x77, 0x0d, 0x0a, 0x55, 0x53, 0x2f, 0x53, 0x61, 0x6d, 0x6f, 0x61, 0x0d, | ||
| 615 | 0x0a}; | ||
| 616 | |||
| 617 | static VirtualFile GenerateDefaultTimeZoneFile() { | ||
| 618 | struct { | ||
| 619 | s64_be at; | ||
| 620 | INSERT_PADDING_BYTES(7); | ||
| 621 | std::array<char, 4> time_zone_chars; | ||
| 622 | INSERT_PADDING_BYTES(2); | ||
| 623 | std::array<char, 6> time_zone_name; | ||
| 624 | } time_zone_info{}; | ||
| 625 | |||
| 626 | const VirtualFile file{std::make_shared<VectorVfsFile>( | ||
| 627 | std::vector<u8>(sizeof(Service::Time::TimeZone::TzifHeader) + sizeof(time_zone_info)), | ||
| 628 | "GMT")}; | ||
| 629 | |||
| 630 | Service::Time::TimeZone::TzifHeader header{}; | ||
| 631 | header.magic = 0x545a6966; | ||
| 632 | header.version = 0x32; | ||
| 633 | header.ttis_gmt_count = 0x1; | ||
| 634 | header.ttis_std_count = 0x1; | ||
| 635 | header.time_count = 0x1; | ||
| 636 | header.type_count = 0x1; | ||
| 637 | header.char_count = 0x4; | ||
| 638 | file->WriteObject(header, 0); | ||
| 639 | |||
| 640 | time_zone_info.at = 0xf8; | ||
| 641 | time_zone_info.time_zone_chars = {'G', 'M', 'T', '\0'}; | ||
| 642 | time_zone_info.time_zone_name = {'\n', 'G', 'M', 'T', '0', '\n'}; | ||
| 643 | file->WriteObject(time_zone_info, sizeof(Service::Time::TimeZone::TzifHeader)); | ||
| 644 | |||
| 645 | return file; | ||
| 646 | } | ||
| 647 | |||
| 648 | VirtualDir TimeZoneBinary() { | ||
| 649 | const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>( | ||
| 650 | std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{}, | ||
| 651 | "zoneinfo")}; | ||
| 652 | const std::vector<VirtualFile> root_files{ | ||
| 653 | std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")}; | ||
| 654 | return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data"); | ||
| 655 | } | ||
| 656 | |||
| 657 | } // namespace FileSys::SystemArchive | ||
diff --git a/src/core/file_sys/system_archive/time_zone_binary.h b/src/core/file_sys/system_archive/time_zone_binary.h new file mode 100644 index 000000000..ed2b78227 --- /dev/null +++ b/src/core/file_sys/system_archive/time_zone_binary.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | #include "core/file_sys/vfs_types.h" | ||
| 9 | |||
| 10 | namespace FileSys::SystemArchive { | ||
| 11 | |||
| 12 | VirtualDir TimeZoneBinary(); | ||
| 13 | |||
| 14 | } // namespace FileSys::SystemArchive | ||
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 7e3e311fb..cfac8ca9a 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -211,7 +211,7 @@ protected: | |||
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | ProfileManager& profile_manager; | 213 | ProfileManager& profile_manager; |
| 214 | Common::UUID user_id; ///< The user id this profile refers to. | 214 | Common::UUID user_id{Common::INVALID_UUID}; ///< The user id this profile refers to. |
| 215 | }; | 215 | }; |
| 216 | 216 | ||
| 217 | class IProfile final : public IProfileCommon { | 217 | class IProfile final : public IProfileCommon { |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 3e756e59e..eb8c81645 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -16,17 +16,17 @@ namespace Service::Account { | |||
| 16 | using Common::UUID; | 16 | using Common::UUID; |
| 17 | 17 | ||
| 18 | struct UserRaw { | 18 | struct UserRaw { |
| 19 | UUID uuid; | 19 | UUID uuid{Common::INVALID_UUID}; |
| 20 | UUID uuid2; | 20 | UUID uuid2{Common::INVALID_UUID}; |
| 21 | u64 timestamp; | 21 | u64 timestamp{}; |
| 22 | ProfileUsername username; | 22 | ProfileUsername username{}; |
| 23 | ProfileData extra_data; | 23 | ProfileData extra_data{}; |
| 24 | }; | 24 | }; |
| 25 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); | 25 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); |
| 26 | 26 | ||
| 27 | struct ProfileDataRaw { | 27 | struct ProfileDataRaw { |
| 28 | INSERT_PADDING_BYTES(0x10); | 28 | INSERT_PADDING_BYTES(0x10); |
| 29 | std::array<UserRaw, MAX_USERS> users; | 29 | std::array<UserRaw, MAX_USERS> users{}; |
| 30 | }; | 30 | }; |
| 31 | static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size."); | 31 | static_assert(sizeof(ProfileDataRaw) == 0x650, "ProfileDataRaw has incorrect size."); |
| 32 | 32 | ||
| @@ -238,7 +238,7 @@ UserIDArray ProfileManager::GetOpenUsers() const { | |||
| 238 | std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) { | 238 | std::transform(profiles.begin(), profiles.end(), output.begin(), [](const ProfileInfo& p) { |
| 239 | if (p.is_open) | 239 | if (p.is_open) |
| 240 | return p.user_uuid; | 240 | return p.user_uuid; |
| 241 | return UUID{}; | 241 | return UUID{Common::INVALID_UUID}; |
| 242 | }); | 242 | }); |
| 243 | std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; }); | 243 | std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; }); |
| 244 | return output; | 244 | return output; |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 5a6d28925..5310637a6 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -13,9 +13,10 @@ | |||
| 13 | #include "core/hle/result.h" | 13 | #include "core/hle/result.h" |
| 14 | 14 | ||
| 15 | namespace Service::Account { | 15 | namespace Service::Account { |
| 16 | constexpr std::size_t MAX_USERS = 8; | ||
| 17 | 16 | ||
| 18 | constexpr std::size_t profile_username_size = 32; | 17 | constexpr std::size_t MAX_USERS{8}; |
| 18 | constexpr std::size_t profile_username_size{32}; | ||
| 19 | |||
| 19 | using ProfileUsername = std::array<u8, profile_username_size>; | 20 | using ProfileUsername = std::array<u8, profile_username_size>; |
| 20 | using UserIDArray = std::array<Common::UUID, MAX_USERS>; | 21 | using UserIDArray = std::array<Common::UUID, MAX_USERS>; |
| 21 | 22 | ||
| @@ -23,8 +24,8 @@ using UserIDArray = std::array<Common::UUID, MAX_USERS>; | |||
| 23 | /// TODO: RE this structure | 24 | /// TODO: RE this structure |
| 24 | struct ProfileData { | 25 | struct ProfileData { |
| 25 | INSERT_PADDING_WORDS(1); | 26 | INSERT_PADDING_WORDS(1); |
| 26 | u32 icon_id; | 27 | u32 icon_id{}; |
| 27 | u8 bg_color_id; | 28 | u8 bg_color_id{}; |
| 28 | INSERT_PADDING_BYTES(0x7); | 29 | INSERT_PADDING_BYTES(0x7); |
| 29 | INSERT_PADDING_BYTES(0x10); | 30 | INSERT_PADDING_BYTES(0x10); |
| 30 | INSERT_PADDING_BYTES(0x60); | 31 | INSERT_PADDING_BYTES(0x60); |
| @@ -34,17 +35,17 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect | |||
| 34 | /// This holds general information about a users profile. This is where we store all the information | 35 | /// This holds general information about a users profile. This is where we store all the information |
| 35 | /// based on a specific user | 36 | /// based on a specific user |
| 36 | struct ProfileInfo { | 37 | struct ProfileInfo { |
| 37 | Common::UUID user_uuid; | 38 | Common::UUID user_uuid{Common::INVALID_UUID}; |
| 38 | ProfileUsername username; | 39 | ProfileUsername username{}; |
| 39 | u64 creation_time; | 40 | u64 creation_time{}; |
| 40 | ProfileData data; // TODO(ognik): Work out what this is | 41 | ProfileData data{}; // TODO(ognik): Work out what this is |
| 41 | bool is_open; | 42 | bool is_open{}; |
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | struct ProfileBase { | 45 | struct ProfileBase { |
| 45 | Common::UUID user_uuid; | 46 | Common::UUID user_uuid{Common::INVALID_UUID}; |
| 46 | u64_le timestamp; | 47 | u64_le timestamp{}; |
| 47 | ProfileUsername username; | 48 | ProfileUsername username{}; |
| 48 | 49 | ||
| 49 | // Zero out all the fields to make the profile slot considered "Empty" | 50 | // Zero out all the fields to make the profile slot considered "Empty" |
| 50 | void Invalidate() { | 51 | void Invalidate() { |
| @@ -101,7 +102,7 @@ private: | |||
| 101 | bool RemoveProfileAtIndex(std::size_t index); | 102 | bool RemoveProfileAtIndex(std::size_t index); |
| 102 | 103 | ||
| 103 | std::array<ProfileInfo, MAX_USERS> profiles{}; | 104 | std::array<ProfileInfo, MAX_USERS> profiles{}; |
| 104 | std::size_t user_count = 0; | 105 | std::size_t user_count{}; |
| 105 | Common::UUID last_opened_user{Common::INVALID_UUID}; | 106 | Common::UUID last_opened_user{Common::INVALID_UUID}; |
| 106 | }; | 107 | }; |
| 107 | 108 | ||
diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 219176c31..6aadb3ea8 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp | |||
| @@ -241,7 +241,7 @@ private: | |||
| 241 | bool has_received_friend_request; | 241 | bool has_received_friend_request; |
| 242 | }; | 242 | }; |
| 243 | 243 | ||
| 244 | Common::UUID uuid; | 244 | Common::UUID uuid{Common::INVALID_UUID}; |
| 245 | Kernel::EventPair notification_event; | 245 | Kernel::EventPair notification_event; |
| 246 | std::queue<SizedNotificationInfo> notifications; | 246 | std::queue<SizedNotificationInfo> notifications; |
| 247 | States states{}; | 247 | States states{}; |
diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 38ad78a0d..fc742816a 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h | |||
| @@ -10,13 +10,13 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::Mii { | 11 | namespace Service::Mii { |
| 12 | 12 | ||
| 13 | constexpr std::size_t MAX_MIIS = 100; | 13 | constexpr std::size_t MAX_MIIS{100}; |
| 14 | constexpr u32 INVALID_INDEX = 0xFFFFFFFF; | 14 | constexpr u32 INVALID_INDEX{0xFFFFFFFF}; |
| 15 | 15 | ||
| 16 | struct RandomParameters { | 16 | struct RandomParameters { |
| 17 | u32 unknown_1; | 17 | u32 unknown_1{}; |
| 18 | u32 unknown_2; | 18 | u32 unknown_2{}; |
| 19 | u32 unknown_3; | 19 | u32 unknown_3{}; |
| 20 | }; | 20 | }; |
| 21 | static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size."); | 21 | static_assert(sizeof(RandomParameters) == 0xC, "RandomParameters has incorrect size."); |
| 22 | 22 | ||
| @@ -30,57 +30,57 @@ enum class Source : u32 { | |||
| 30 | std::ostream& operator<<(std::ostream& os, Source source); | 30 | std::ostream& operator<<(std::ostream& os, Source source); |
| 31 | 31 | ||
| 32 | struct MiiInfo { | 32 | struct MiiInfo { |
| 33 | Common::UUID uuid; | 33 | Common::UUID uuid{Common::INVALID_UUID}; |
| 34 | std::array<char16_t, 11> name; | 34 | std::array<char16_t, 11> name{}; |
| 35 | u8 font_region; | 35 | u8 font_region{}; |
| 36 | u8 favorite_color; | 36 | u8 favorite_color{}; |
| 37 | u8 gender; | 37 | u8 gender{}; |
| 38 | u8 height; | 38 | u8 height{}; |
| 39 | u8 weight; | 39 | u8 weight{}; |
| 40 | u8 mii_type; | 40 | u8 mii_type{}; |
| 41 | u8 mii_region; | 41 | u8 mii_region{}; |
| 42 | u8 face_type; | 42 | u8 face_type{}; |
| 43 | u8 face_color; | 43 | u8 face_color{}; |
| 44 | u8 face_wrinkle; | 44 | u8 face_wrinkle{}; |
| 45 | u8 face_makeup; | 45 | u8 face_makeup{}; |
| 46 | u8 hair_type; | 46 | u8 hair_type{}; |
| 47 | u8 hair_color; | 47 | u8 hair_color{}; |
| 48 | bool hair_flip; | 48 | bool hair_flip{}; |
| 49 | u8 eye_type; | 49 | u8 eye_type{}; |
| 50 | u8 eye_color; | 50 | u8 eye_color{}; |
| 51 | u8 eye_scale; | 51 | u8 eye_scale{}; |
| 52 | u8 eye_aspect_ratio; | 52 | u8 eye_aspect_ratio{}; |
| 53 | u8 eye_rotate; | 53 | u8 eye_rotate{}; |
| 54 | u8 eye_x; | 54 | u8 eye_x{}; |
| 55 | u8 eye_y; | 55 | u8 eye_y{}; |
| 56 | u8 eyebrow_type; | 56 | u8 eyebrow_type{}; |
| 57 | u8 eyebrow_color; | 57 | u8 eyebrow_color{}; |
| 58 | u8 eyebrow_scale; | 58 | u8 eyebrow_scale{}; |
| 59 | u8 eyebrow_aspect_ratio; | 59 | u8 eyebrow_aspect_ratio{}; |
| 60 | u8 eyebrow_rotate; | 60 | u8 eyebrow_rotate{}; |
| 61 | u8 eyebrow_x; | 61 | u8 eyebrow_x{}; |
| 62 | u8 eyebrow_y; | 62 | u8 eyebrow_y{}; |
| 63 | u8 nose_type; | 63 | u8 nose_type{}; |
| 64 | u8 nose_scale; | 64 | u8 nose_scale{}; |
| 65 | u8 nose_y; | 65 | u8 nose_y{}; |
| 66 | u8 mouth_type; | 66 | u8 mouth_type{}; |
| 67 | u8 mouth_color; | 67 | u8 mouth_color{}; |
| 68 | u8 mouth_scale; | 68 | u8 mouth_scale{}; |
| 69 | u8 mouth_aspect_ratio; | 69 | u8 mouth_aspect_ratio{}; |
| 70 | u8 mouth_y; | 70 | u8 mouth_y{}; |
| 71 | u8 facial_hair_color; | 71 | u8 facial_hair_color{}; |
| 72 | u8 beard_type; | 72 | u8 beard_type{}; |
| 73 | u8 mustache_type; | 73 | u8 mustache_type{}; |
| 74 | u8 mustache_scale; | 74 | u8 mustache_scale{}; |
| 75 | u8 mustache_y; | 75 | u8 mustache_y{}; |
| 76 | u8 glasses_type; | 76 | u8 glasses_type{}; |
| 77 | u8 glasses_color; | 77 | u8 glasses_color{}; |
| 78 | u8 glasses_scale; | 78 | u8 glasses_scale{}; |
| 79 | u8 glasses_y; | 79 | u8 glasses_y{}; |
| 80 | u8 mole_type; | 80 | u8 mole_type{}; |
| 81 | u8 mole_scale; | 81 | u8 mole_scale{}; |
| 82 | u8 mole_x; | 82 | u8 mole_x{}; |
| 83 | u8 mole_y; | 83 | u8 mole_y{}; |
| 84 | INSERT_PADDING_BYTES(1); | 84 | INSERT_PADDING_BYTES(1); |
| 85 | 85 | ||
| 86 | std::u16string Name() const; | 86 | std::u16string Name() const; |
| @@ -94,14 +94,14 @@ bool operator!=(const MiiInfo& lhs, const MiiInfo& rhs); | |||
| 94 | 94 | ||
| 95 | #pragma pack(push, 4) | 95 | #pragma pack(push, 4) |
| 96 | struct MiiInfoElement { | 96 | struct MiiInfoElement { |
| 97 | MiiInfo info; | 97 | MiiInfo info{}; |
| 98 | Source source; | 98 | Source source{}; |
| 99 | }; | 99 | }; |
| 100 | static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size."); | 100 | static_assert(sizeof(MiiInfoElement) == 0x5C, "MiiInfoElement has incorrect size."); |
| 101 | 101 | ||
| 102 | struct MiiStoreBitFields { | 102 | struct MiiStoreBitFields { |
| 103 | union { | 103 | union { |
| 104 | u32 word_0; | 104 | u32 word_0{}; |
| 105 | 105 | ||
| 106 | BitField<24, 8, u32> hair_type; | 106 | BitField<24, 8, u32> hair_type; |
| 107 | BitField<23, 1, u32> mole_type; | 107 | BitField<23, 1, u32> mole_type; |
| @@ -112,7 +112,7 @@ struct MiiStoreBitFields { | |||
| 112 | }; | 112 | }; |
| 113 | 113 | ||
| 114 | union { | 114 | union { |
| 115 | u32 word_1; | 115 | u32 word_1{}; |
| 116 | 116 | ||
| 117 | BitField<31, 1, u32> gender; | 117 | BitField<31, 1, u32> gender; |
| 118 | BitField<24, 7, u32> eye_color; | 118 | BitField<24, 7, u32> eye_color; |
| @@ -122,7 +122,7 @@ struct MiiStoreBitFields { | |||
| 122 | }; | 122 | }; |
| 123 | 123 | ||
| 124 | union { | 124 | union { |
| 125 | u32 word_2; | 125 | u32 word_2{}; |
| 126 | 126 | ||
| 127 | BitField<31, 1, u32> mii_type; | 127 | BitField<31, 1, u32> mii_type; |
| 128 | BitField<24, 7, u32> glasses_color; | 128 | BitField<24, 7, u32> glasses_color; |
| @@ -135,7 +135,7 @@ struct MiiStoreBitFields { | |||
| 135 | }; | 135 | }; |
| 136 | 136 | ||
| 137 | union { | 137 | union { |
| 138 | u32 word_3; | 138 | u32 word_3{}; |
| 139 | 139 | ||
| 140 | BitField<29, 3, u32> mustache_type; | 140 | BitField<29, 3, u32> mustache_type; |
| 141 | BitField<24, 5, u32> eyebrow_type; | 141 | BitField<24, 5, u32> eyebrow_type; |
| @@ -148,7 +148,7 @@ struct MiiStoreBitFields { | |||
| 148 | }; | 148 | }; |
| 149 | 149 | ||
| 150 | union { | 150 | union { |
| 151 | u32 word_4; | 151 | u32 word_4{}; |
| 152 | 152 | ||
| 153 | BitField<29, 3, u32> eye_rotate; | 153 | BitField<29, 3, u32> eye_rotate; |
| 154 | BitField<24, 5, u32> mustache_y; | 154 | BitField<24, 5, u32> mustache_y; |
| @@ -160,7 +160,7 @@ struct MiiStoreBitFields { | |||
| 160 | }; | 160 | }; |
| 161 | 161 | ||
| 162 | union { | 162 | union { |
| 163 | u32 word_5; | 163 | u32 word_5{}; |
| 164 | 164 | ||
| 165 | BitField<24, 5, u32> glasses_type; | 165 | BitField<24, 5, u32> glasses_type; |
| 166 | BitField<20, 4, u32> face_type; | 166 | BitField<20, 4, u32> face_type; |
| @@ -172,7 +172,7 @@ struct MiiStoreBitFields { | |||
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | union { | 174 | union { |
| 175 | u32 word_6; | 175 | u32 word_6{}; |
| 176 | 176 | ||
| 177 | BitField<28, 4, u32> eyebrow_rotate; | 177 | BitField<28, 4, u32> eyebrow_rotate; |
| 178 | BitField<24, 4, u32> eyebrow_scale; | 178 | BitField<24, 4, u32> eyebrow_scale; |
| @@ -192,30 +192,30 @@ struct MiiStoreData { | |||
| 192 | // This corresponds to the above structure MiiStoreBitFields. I did it like this because the | 192 | // This corresponds to the above structure MiiStoreBitFields. I did it like this because the |
| 193 | // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is | 193 | // BitField<> type makes this (and any thing that contains it) not trivially copyable, which is |
| 194 | // not suitable for our uses. | 194 | // not suitable for our uses. |
| 195 | std::array<u8, 0x1C> data; | 195 | std::array<u8, 0x1C> data{}; |
| 196 | static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); | 196 | static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); |
| 197 | 197 | ||
| 198 | std::array<char16_t, 10> name; | 198 | std::array<char16_t, 10> name{}; |
| 199 | Common::UUID uuid; | 199 | Common::UUID uuid{Common::INVALID_UUID}; |
| 200 | u16 crc_1; | 200 | u16 crc_1{}; |
| 201 | u16 crc_2; | 201 | u16 crc_2{}; |
| 202 | 202 | ||
| 203 | std::u16string Name() const; | 203 | std::u16string Name() const; |
| 204 | }; | 204 | }; |
| 205 | static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); | 205 | static_assert(sizeof(MiiStoreData) == 0x44, "MiiStoreData has incorrect size."); |
| 206 | 206 | ||
| 207 | struct MiiStoreDataElement { | 207 | struct MiiStoreDataElement { |
| 208 | MiiStoreData data; | 208 | MiiStoreData data{}; |
| 209 | Source source; | 209 | Source source{}; |
| 210 | }; | 210 | }; |
| 211 | static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); | 211 | static_assert(sizeof(MiiStoreDataElement) == 0x48, "MiiStoreDataElement has incorrect size."); |
| 212 | 212 | ||
| 213 | struct MiiDatabase { | 213 | struct MiiDatabase { |
| 214 | u32 magic; // 'NFDB' | 214 | u32 magic{}; // 'NFDB' |
| 215 | std::array<MiiStoreData, MAX_MIIS> miis; | 215 | std::array<MiiStoreData, MAX_MIIS> miis{}; |
| 216 | INSERT_PADDING_BYTES(1); | 216 | INSERT_PADDING_BYTES(1); |
| 217 | u8 count; | 217 | u8 count{}; |
| 218 | u16 crc; | 218 | u16 crc{}; |
| 219 | }; | 219 | }; |
| 220 | static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); | 220 | static_assert(sizeof(MiiDatabase) == 0x1A98, "MiiDatabase has incorrect size."); |
| 221 | #pragma pack(pop) | 221 | #pragma pack(pop) |
| @@ -266,8 +266,8 @@ private: | |||
| 266 | void EnsureDatabasePartition(); | 266 | void EnsureDatabasePartition(); |
| 267 | 267 | ||
| 268 | MiiDatabase database; | 268 | MiiDatabase database; |
| 269 | bool updated_flag = false; | 269 | bool updated_flag{}; |
| 270 | bool is_test_mode_enabled = false; | 270 | bool is_test_mode_enabled{}; |
| 271 | }; | 271 | }; |
| 272 | 272 | ||
| 273 | }; // namespace Service::Mii | 273 | }; // namespace Service::Mii |
diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h new file mode 100644 index 000000000..72e1921ec --- /dev/null +++ b/src/core/hle/service/time/clock_types.h | |||
| @@ -0,0 +1,103 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_funcs.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "common/uuid.h" | ||
| 10 | #include "core/hle/service/time/errors.h" | ||
| 11 | #include "core/hle/service/time/time_zone_types.h" | ||
| 12 | |||
| 13 | namespace Service::Time::Clock { | ||
| 14 | |||
| 15 | /// https://switchbrew.org/wiki/Glue_services#SteadyClockTimePoint | ||
| 16 | struct SteadyClockTimePoint { | ||
| 17 | s64 time_point; | ||
| 18 | Common::UUID clock_source_id; | ||
| 19 | |||
| 20 | ResultCode GetSpanBetween(SteadyClockTimePoint other, s64& span) const { | ||
| 21 | span = 0; | ||
| 22 | |||
| 23 | if (clock_source_id != other.clock_source_id) { | ||
| 24 | return ERROR_TIME_MISMATCH; | ||
| 25 | } | ||
| 26 | |||
| 27 | span = other.time_point - time_point; | ||
| 28 | |||
| 29 | return RESULT_SUCCESS; | ||
| 30 | } | ||
| 31 | |||
| 32 | static SteadyClockTimePoint GetRandom() { | ||
| 33 | return {0, Common::UUID::Generate()}; | ||
| 34 | } | ||
| 35 | }; | ||
| 36 | static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); | ||
| 37 | static_assert(std::is_trivially_copyable_v<SteadyClockTimePoint>, | ||
| 38 | "SteadyClockTimePoint must be trivially copyable"); | ||
| 39 | |||
| 40 | struct SteadyClockContext { | ||
| 41 | u64 internal_offset; | ||
| 42 | Common::UUID steady_time_point; | ||
| 43 | }; | ||
| 44 | static_assert(sizeof(SteadyClockContext) == 0x18, "SteadyClockContext is incorrect size"); | ||
| 45 | static_assert(std::is_trivially_copyable_v<SteadyClockContext>, | ||
| 46 | "SteadyClockContext must be trivially copyable"); | ||
| 47 | |||
| 48 | struct SystemClockContext { | ||
| 49 | s64 offset; | ||
| 50 | SteadyClockTimePoint steady_time_point; | ||
| 51 | }; | ||
| 52 | static_assert(sizeof(SystemClockContext) == 0x20, "SystemClockContext is incorrect size"); | ||
| 53 | static_assert(std::is_trivially_copyable_v<SystemClockContext>, | ||
| 54 | "SystemClockContext must be trivially copyable"); | ||
| 55 | |||
| 56 | /// https://switchbrew.org/wiki/Glue_services#TimeSpanType | ||
| 57 | struct TimeSpanType { | ||
| 58 | s64 nanoseconds{}; | ||
| 59 | static constexpr s64 ns_per_second{1000000000ULL}; | ||
| 60 | |||
| 61 | s64 ToSeconds() const { | ||
| 62 | return nanoseconds / ns_per_second; | ||
| 63 | } | ||
| 64 | |||
| 65 | static TimeSpanType FromSeconds(s64 seconds) { | ||
| 66 | return {seconds * ns_per_second}; | ||
| 67 | } | ||
| 68 | |||
| 69 | static TimeSpanType FromTicks(u64 ticks, u64 frequency) { | ||
| 70 | return FromSeconds(static_cast<s64>(ticks) / static_cast<s64>(frequency)); | ||
| 71 | } | ||
| 72 | }; | ||
| 73 | static_assert(sizeof(TimeSpanType) == 8, "TimeSpanType is incorrect size"); | ||
| 74 | |||
| 75 | struct ClockSnapshot { | ||
| 76 | SystemClockContext user_context{}; | ||
| 77 | SystemClockContext network_context{}; | ||
| 78 | s64 user_time{}; | ||
| 79 | s64 network_time{}; | ||
| 80 | TimeZone::CalendarTime user_calendar_time{}; | ||
| 81 | TimeZone::CalendarTime network_calendar_time{}; | ||
| 82 | TimeZone::CalendarAdditionalInfo user_calendar_additional_time{}; | ||
| 83 | TimeZone::CalendarAdditionalInfo network_calendar_additional_time{}; | ||
| 84 | SteadyClockTimePoint steady_clock_time_point{}; | ||
| 85 | TimeZone::LocationName location_name{}; | ||
| 86 | u8 is_automatic_correction_enabled{}; | ||
| 87 | u8 type{}; | ||
| 88 | INSERT_PADDING_BYTES(0x2); | ||
| 89 | |||
| 90 | static ResultCode GetCurrentTime(s64& current_time, | ||
| 91 | const SteadyClockTimePoint& steady_clock_time_point, | ||
| 92 | const SystemClockContext& context) { | ||
| 93 | if (steady_clock_time_point.clock_source_id != context.steady_time_point.clock_source_id) { | ||
| 94 | current_time = 0; | ||
| 95 | return ERROR_TIME_MISMATCH; | ||
| 96 | } | ||
| 97 | current_time = steady_clock_time_point.time_point + context.offset; | ||
| 98 | return RESULT_SUCCESS; | ||
| 99 | } | ||
| 100 | }; | ||
| 101 | static_assert(sizeof(ClockSnapshot) == 0xD0, "ClockSnapshot is incorrect size"); | ||
| 102 | |||
| 103 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h new file mode 100644 index 000000000..42893e3f6 --- /dev/null +++ b/src/core/hle/service/time/ephemeral_network_system_clock_context_writer.h | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | class EphemeralNetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { | ||
| 12 | public: | ||
| 13 | EphemeralNetworkSystemClockContextWriter() : SystemClockContextUpdateCallback{} {} | ||
| 14 | }; | ||
| 15 | |||
| 16 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/ephemeral_network_system_clock_core.h b/src/core/hle/service/time/ephemeral_network_system_clock_core.h new file mode 100644 index 000000000..4c6cdef86 --- /dev/null +++ b/src/core/hle/service/time/ephemeral_network_system_clock_core.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/system_clock_core.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | class EphemeralNetworkSystemClockCore final : public SystemClockCore { | ||
| 12 | public: | ||
| 13 | explicit EphemeralNetworkSystemClockCore(SteadyClockCore& steady_clock_core) | ||
| 14 | : SystemClockCore{steady_clock_core} {} | ||
| 15 | }; | ||
| 16 | |||
| 17 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/errors.h b/src/core/hle/service/time/errors.h new file mode 100644 index 000000000..8501a3e8c --- /dev/null +++ b/src/core/hle/service/time/errors.h | |||
| @@ -0,0 +1,22 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/result.h" | ||
| 8 | |||
| 9 | namespace Service::Time { | ||
| 10 | |||
| 11 | constexpr ResultCode ERROR_PERMISSION_DENIED{ErrorModule::Time, 1}; | ||
| 12 | constexpr ResultCode ERROR_TIME_MISMATCH{ErrorModule::Time, 102}; | ||
| 13 | constexpr ResultCode ERROR_UNINITIALIZED_CLOCK{ErrorModule::Time, 103}; | ||
| 14 | constexpr ResultCode ERROR_TIME_NOT_FOUND{ErrorModule::Time, 200}; | ||
| 15 | constexpr ResultCode ERROR_OVERFLOW{ErrorModule::Time, 201}; | ||
| 16 | constexpr ResultCode ERROR_LOCATION_NAME_TOO_LONG{ErrorModule::Time, 801}; | ||
| 17 | constexpr ResultCode ERROR_OUT_OF_RANGE{ErrorModule::Time, 902}; | ||
| 18 | constexpr ResultCode ERROR_TIME_ZONE_CONVERSION_FAILED{ErrorModule::Time, 903}; | ||
| 19 | constexpr ResultCode ERROR_TIME_ZONE_NOT_FOUND{ErrorModule::Time, 989}; | ||
| 20 | constexpr ResultCode ERROR_NOT_IMPLEMENTED{ErrorModule::Time, 990}; | ||
| 21 | |||
| 22 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/interface.cpp b/src/core/hle/service/time/interface.cpp index bc74f1e1d..1660bbdb8 100644 --- a/src/core/hle/service/time/interface.cpp +++ b/src/core/hle/service/time/interface.cpp | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2019 yuzu emulator team |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| @@ -6,9 +6,8 @@ | |||
| 6 | 6 | ||
| 7 | namespace Service::Time { | 7 | namespace Service::Time { |
| 8 | 8 | ||
| 9 | Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, | 9 | Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 10 | Core::System& system, const char* name) | 10 | : Module::Interface(std::move(module), system, name) { |
| 11 | : Module::Interface(std::move(time), std::move(shared_memory), system, name) { | ||
| 12 | // clang-format off | 11 | // clang-format off |
| 13 | static const FunctionInfo functions[] = { | 12 | static const FunctionInfo functions[] = { |
| 14 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, | 13 | {0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"}, |
| @@ -22,15 +21,15 @@ Time::Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_me | |||
| 22 | {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, | 21 | {31, nullptr, "GetEphemeralNetworkClockOperationEventReadableHandle"}, |
| 23 | {50, nullptr, "SetStandardSteadyClockInternalOffset"}, | 22 | {50, nullptr, "SetStandardSteadyClockInternalOffset"}, |
| 24 | {51, nullptr, "GetStandardSteadyClockRtcValue"}, | 23 | {51, nullptr, "GetStandardSteadyClockRtcValue"}, |
| 25 | {100, &Time::IsStandardUserSystemClockAutomaticCorrectionEnabled, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, | 24 | {100, nullptr, "IsStandardUserSystemClockAutomaticCorrectionEnabled"}, |
| 26 | {101, &Time::SetStandardUserSystemClockAutomaticCorrectionEnabled, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, | 25 | {101, nullptr, "SetStandardUserSystemClockAutomaticCorrectionEnabled"}, |
| 27 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, | 26 | {102, nullptr, "GetStandardUserSystemClockInitialYear"}, |
| 28 | {200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"}, | 27 | {200, &Time::IsStandardNetworkSystemClockAccuracySufficient, "IsStandardNetworkSystemClockAccuracySufficient"}, |
| 29 | {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, | 28 | {201, nullptr, "GetStandardUserSystemClockAutomaticCorrectionUpdatedTime"}, |
| 30 | {300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"}, | 29 | {300, &Time::CalculateMonotonicSystemClockBaseTimePoint, "CalculateMonotonicSystemClockBaseTimePoint"}, |
| 31 | {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, | 30 | {400, &Time::GetClockSnapshot, "GetClockSnapshot"}, |
| 32 | {401, nullptr, "GetClockSnapshotFromSystemClockContext"}, | 31 | {401, &Time::GetClockSnapshotFromSystemClockContext, "GetClockSnapshotFromSystemClockContext"}, |
| 33 | {500, &Time::CalculateStandardUserSystemClockDifferenceByUser, "CalculateStandardUserSystemClockDifferenceByUser"}, | 32 | {500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"}, |
| 34 | {501, nullptr, "CalculateSpanBetween"}, | 33 | {501, nullptr, "CalculateSpanBetween"}, |
| 35 | }; | 34 | }; |
| 36 | // clang-format on | 35 | // clang-format on |
diff --git a/src/core/hle/service/time/interface.h b/src/core/hle/service/time/interface.h index 5c63a07f4..4f49e1f07 100644 --- a/src/core/hle/service/time/interface.h +++ b/src/core/hle/service/time/interface.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2019 yuzu emulator team |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| @@ -6,14 +6,15 @@ | |||
| 6 | 6 | ||
| 7 | #include "core/hle/service/time/time.h" | 7 | #include "core/hle/service/time/time.h" |
| 8 | 8 | ||
| 9 | namespace Service::Time { | 9 | namespace Core { |
| 10 | class System; | ||
| 11 | } | ||
| 10 | 12 | ||
| 11 | class SharedMemory; | 13 | namespace Service::Time { |
| 12 | 14 | ||
| 13 | class Time final : public Module::Interface { | 15 | class Time final : public Module::Interface { |
| 14 | public: | 16 | public: |
| 15 | explicit Time(std::shared_ptr<Module> time, std::shared_ptr<SharedMemory> shared_memory, | 17 | explicit Time(std::shared_ptr<Module> time, Core::System& system, const char* name); |
| 16 | Core::System& system, const char* name); | ||
| 17 | ~Time() override; | 18 | ~Time() override; |
| 18 | }; | 19 | }; |
| 19 | 20 | ||
diff --git a/src/core/hle/service/time/local_system_clock_context_writer.h b/src/core/hle/service/time/local_system_clock_context_writer.h new file mode 100644 index 000000000..7050844c6 --- /dev/null +++ b/src/core/hle/service/time/local_system_clock_context_writer.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/errors.h" | ||
| 8 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 9 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 10 | |||
| 11 | namespace Service::Time::Clock { | ||
| 12 | |||
| 13 | class LocalSystemClockContextWriter final : public SystemClockContextUpdateCallback { | ||
| 14 | public: | ||
| 15 | explicit LocalSystemClockContextWriter(SharedMemory& shared_memory) | ||
| 16 | : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {} | ||
| 17 | |||
| 18 | protected: | ||
| 19 | ResultCode Update() override { | ||
| 20 | shared_memory.UpdateLocalSystemClockContext(context); | ||
| 21 | return RESULT_SUCCESS; | ||
| 22 | } | ||
| 23 | |||
| 24 | private: | ||
| 25 | SharedMemory& shared_memory; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/network_system_clock_context_writer.h b/src/core/hle/service/time/network_system_clock_context_writer.h new file mode 100644 index 000000000..94d8788ff --- /dev/null +++ b/src/core/hle/service/time/network_system_clock_context_writer.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/errors.h" | ||
| 8 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 9 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 10 | |||
| 11 | namespace Service::Time::Clock { | ||
| 12 | |||
| 13 | class NetworkSystemClockContextWriter final : public SystemClockContextUpdateCallback { | ||
| 14 | public: | ||
| 15 | explicit NetworkSystemClockContextWriter(SharedMemory& shared_memory) | ||
| 16 | : SystemClockContextUpdateCallback{}, shared_memory{shared_memory} {} | ||
| 17 | |||
| 18 | protected: | ||
| 19 | ResultCode Update() override { | ||
| 20 | shared_memory.UpdateNetworkSystemClockContext(context); | ||
| 21 | return RESULT_SUCCESS; | ||
| 22 | } | ||
| 23 | |||
| 24 | private: | ||
| 25 | SharedMemory& shared_memory; | ||
| 26 | }; | ||
| 27 | |||
| 28 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_local_system_clock_core.h b/src/core/hle/service/time/standard_local_system_clock_core.h new file mode 100644 index 000000000..8c1882eb1 --- /dev/null +++ b/src/core/hle/service/time/standard_local_system_clock_core.h | |||
| @@ -0,0 +1,17 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/system_clock_core.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | class StandardLocalSystemClockCore final : public SystemClockCore { | ||
| 12 | public: | ||
| 13 | explicit StandardLocalSystemClockCore(SteadyClockCore& steady_clock_core) | ||
| 14 | : SystemClockCore{steady_clock_core} {} | ||
| 15 | }; | ||
| 16 | |||
| 17 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_network_system_clock_core.h b/src/core/hle/service/time/standard_network_system_clock_core.h new file mode 100644 index 000000000..3f505c37c --- /dev/null +++ b/src/core/hle/service/time/standard_network_system_clock_core.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/clock_types.h" | ||
| 8 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 9 | #include "core/hle/service/time/system_clock_core.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Time::Clock { | ||
| 16 | |||
| 17 | class StandardNetworkSystemClockCore final : public SystemClockCore { | ||
| 18 | public: | ||
| 19 | explicit StandardNetworkSystemClockCore(SteadyClockCore& steady_clock_core) | ||
| 20 | : SystemClockCore{steady_clock_core} {} | ||
| 21 | |||
| 22 | void SetStandardNetworkClockSufficientAccuracy(TimeSpanType value) { | ||
| 23 | standard_network_clock_sufficient_accuracy = value; | ||
| 24 | } | ||
| 25 | |||
| 26 | bool IsStandardNetworkSystemClockAccuracySufficient(Core::System& system) { | ||
| 27 | SystemClockContext context{}; | ||
| 28 | if (GetClockContext(system, context) != RESULT_SUCCESS) { | ||
| 29 | return {}; | ||
| 30 | } | ||
| 31 | |||
| 32 | s64 span{}; | ||
| 33 | if (context.steady_time_point.GetSpanBetween( | ||
| 34 | GetSteadyClockCore().GetCurrentTimePoint(system), span) != RESULT_SUCCESS) { | ||
| 35 | return {}; | ||
| 36 | } | ||
| 37 | |||
| 38 | return TimeSpanType{span}.nanoseconds < | ||
| 39 | standard_network_clock_sufficient_accuracy.nanoseconds; | ||
| 40 | } | ||
| 41 | |||
| 42 | private: | ||
| 43 | TimeSpanType standard_network_clock_sufficient_accuracy{}; | ||
| 44 | }; | ||
| 45 | |||
| 46 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_steady_clock_core.cpp b/src/core/hle/service/time/standard_steady_clock_core.cpp new file mode 100644 index 000000000..ca1a783fc --- /dev/null +++ b/src/core/hle/service/time/standard_steady_clock_core.cpp | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/core_timing_util.h" | ||
| 8 | #include "core/hle/service/time/standard_steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Service::Time::Clock { | ||
| 11 | |||
| 12 | TimeSpanType StandardSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { | ||
| 13 | const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( | ||
| 14 | Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), | ||
| 15 | Core::Timing::CNTFREQ)}; | ||
| 16 | TimeSpanType raw_time_point{setup_value.nanoseconds + ticks_time_span.nanoseconds}; | ||
| 17 | |||
| 18 | if (raw_time_point.nanoseconds < cached_raw_time_point.nanoseconds) { | ||
| 19 | raw_time_point.nanoseconds = cached_raw_time_point.nanoseconds; | ||
| 20 | } | ||
| 21 | |||
| 22 | cached_raw_time_point = raw_time_point; | ||
| 23 | return raw_time_point; | ||
| 24 | } | ||
| 25 | |||
| 26 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_steady_clock_core.h b/src/core/hle/service/time/standard_steady_clock_core.h new file mode 100644 index 000000000..f56f3fd95 --- /dev/null +++ b/src/core/hle/service/time/standard_steady_clock_core.h | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/clock_types.h" | ||
| 8 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Time::Clock { | ||
| 15 | |||
| 16 | class StandardSteadyClockCore final : public SteadyClockCore { | ||
| 17 | public: | ||
| 18 | SteadyClockTimePoint GetTimePoint(Core::System& system) override { | ||
| 19 | return {GetCurrentRawTimePoint(system).ToSeconds(), GetClockSourceId()}; | ||
| 20 | } | ||
| 21 | |||
| 22 | TimeSpanType GetInternalOffset() const override { | ||
| 23 | return internal_offset; | ||
| 24 | } | ||
| 25 | |||
| 26 | void SetInternalOffset(TimeSpanType value) override { | ||
| 27 | internal_offset = value; | ||
| 28 | } | ||
| 29 | |||
| 30 | TimeSpanType GetCurrentRawTimePoint(Core::System& system) override; | ||
| 31 | |||
| 32 | void SetSetupValue(TimeSpanType value) { | ||
| 33 | setup_value = value; | ||
| 34 | } | ||
| 35 | |||
| 36 | private: | ||
| 37 | TimeSpanType setup_value{}; | ||
| 38 | TimeSpanType internal_offset{}; | ||
| 39 | TimeSpanType cached_raw_time_point{}; | ||
| 40 | }; | ||
| 41 | |||
| 42 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.cpp b/src/core/hle/service/time/standard_user_system_clock_core.cpp new file mode 100644 index 000000000..8af17091c --- /dev/null +++ b/src/core/hle/service/time/standard_user_system_clock_core.cpp | |||
| @@ -0,0 +1,77 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/hle/kernel/writable_event.h" | ||
| 8 | #include "core/hle/service/time/standard_local_system_clock_core.h" | ||
| 9 | #include "core/hle/service/time/standard_network_system_clock_core.h" | ||
| 10 | #include "core/hle/service/time/standard_user_system_clock_core.h" | ||
| 11 | |||
| 12 | namespace Service::Time::Clock { | ||
| 13 | |||
| 14 | StandardUserSystemClockCore::StandardUserSystemClockCore( | ||
| 15 | StandardLocalSystemClockCore& local_system_clock_core, | ||
| 16 | StandardNetworkSystemClockCore& network_system_clock_core, Core::System& system) | ||
| 17 | : SystemClockCore(local_system_clock_core.GetSteadyClockCore()), | ||
| 18 | local_system_clock_core{local_system_clock_core}, | ||
| 19 | network_system_clock_core{network_system_clock_core}, auto_correction_enabled{}, | ||
| 20 | auto_correction_time{SteadyClockTimePoint::GetRandom()}, | ||
| 21 | auto_correction_event{Kernel::WritableEvent::CreateEventPair( | ||
| 22 | system.Kernel(), "StandardUserSystemClockCore:AutoCorrectionEvent")} {} | ||
| 23 | |||
| 24 | ResultCode StandardUserSystemClockCore::SetAutomaticCorrectionEnabled(Core::System& system, | ||
| 25 | bool value) { | ||
| 26 | if (const ResultCode result{ApplyAutomaticCorrection(system, value)}; | ||
| 27 | result != RESULT_SUCCESS) { | ||
| 28 | return result; | ||
| 29 | } | ||
| 30 | |||
| 31 | auto_correction_enabled = value; | ||
| 32 | |||
| 33 | return RESULT_SUCCESS; | ||
| 34 | } | ||
| 35 | |||
| 36 | ResultCode StandardUserSystemClockCore::GetClockContext(Core::System& system, | ||
| 37 | SystemClockContext& context) const { | ||
| 38 | if (const ResultCode result{ApplyAutomaticCorrection(system, false)}; | ||
| 39 | result != RESULT_SUCCESS) { | ||
| 40 | return result; | ||
| 41 | } | ||
| 42 | |||
| 43 | return local_system_clock_core.GetClockContext(system, context); | ||
| 44 | } | ||
| 45 | |||
| 46 | ResultCode StandardUserSystemClockCore::Flush(const SystemClockContext& context) { | ||
| 47 | UNREACHABLE(); | ||
| 48 | return ERROR_NOT_IMPLEMENTED; | ||
| 49 | } | ||
| 50 | |||
| 51 | ResultCode StandardUserSystemClockCore::SetClockContext(const SystemClockContext& context) { | ||
| 52 | UNREACHABLE(); | ||
| 53 | return ERROR_NOT_IMPLEMENTED; | ||
| 54 | } | ||
| 55 | |||
| 56 | ResultCode StandardUserSystemClockCore::ApplyAutomaticCorrection(Core::System& system, | ||
| 57 | bool value) const { | ||
| 58 | if (auto_correction_enabled == value) { | ||
| 59 | return RESULT_SUCCESS; | ||
| 60 | } | ||
| 61 | |||
| 62 | if (!network_system_clock_core.IsClockSetup(system)) { | ||
| 63 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 64 | } | ||
| 65 | |||
| 66 | SystemClockContext context{}; | ||
| 67 | if (const ResultCode result{network_system_clock_core.GetClockContext(system, context)}; | ||
| 68 | result != RESULT_SUCCESS) { | ||
| 69 | return result; | ||
| 70 | } | ||
| 71 | |||
| 72 | local_system_clock_core.SetClockContext(context); | ||
| 73 | |||
| 74 | return RESULT_SUCCESS; | ||
| 75 | } | ||
| 76 | |||
| 77 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/standard_user_system_clock_core.h b/src/core/hle/service/time/standard_user_system_clock_core.h new file mode 100644 index 000000000..ef3d468b7 --- /dev/null +++ b/src/core/hle/service/time/standard_user_system_clock_core.h | |||
| @@ -0,0 +1,57 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/kernel/writable_event.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | #include "core/hle/service/time/system_clock_core.h" | ||
| 10 | |||
| 11 | namespace Core { | ||
| 12 | class System; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Time::Clock { | ||
| 16 | |||
| 17 | class StandardLocalSystemClockCore; | ||
| 18 | class StandardNetworkSystemClockCore; | ||
| 19 | |||
| 20 | class StandardUserSystemClockCore final : public SystemClockCore { | ||
| 21 | public: | ||
| 22 | StandardUserSystemClockCore(StandardLocalSystemClockCore& local_system_clock_core, | ||
| 23 | StandardNetworkSystemClockCore& network_system_clock_core, | ||
| 24 | Core::System& system); | ||
| 25 | |||
| 26 | ResultCode SetAutomaticCorrectionEnabled(Core::System& system, bool value); | ||
| 27 | |||
| 28 | ResultCode GetClockContext(Core::System& system, SystemClockContext& context) const override; | ||
| 29 | |||
| 30 | bool IsAutomaticCorrectionEnabled() const { | ||
| 31 | return auto_correction_enabled; | ||
| 32 | } | ||
| 33 | |||
| 34 | void SetAutomaticCorrectionUpdatedTime(SteadyClockTimePoint steady_clock_time_point) { | ||
| 35 | auto_correction_time = steady_clock_time_point; | ||
| 36 | } | ||
| 37 | |||
| 38 | protected: | ||
| 39 | ResultCode Flush(const SystemClockContext& context) override; | ||
| 40 | |||
| 41 | ResultCode SetClockContext(const SystemClockContext&) override; | ||
| 42 | |||
| 43 | ResultCode ApplyAutomaticCorrection(Core::System& system, bool value) const; | ||
| 44 | |||
| 45 | const SteadyClockTimePoint& GetAutomaticCorrectionUpdatedTime() const { | ||
| 46 | return auto_correction_time; | ||
| 47 | } | ||
| 48 | |||
| 49 | private: | ||
| 50 | StandardLocalSystemClockCore& local_system_clock_core; | ||
| 51 | StandardNetworkSystemClockCore& network_system_clock_core; | ||
| 52 | bool auto_correction_enabled{}; | ||
| 53 | SteadyClockTimePoint auto_correction_time; | ||
| 54 | Kernel::EventPair auto_correction_event; | ||
| 55 | }; | ||
| 56 | |||
| 57 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h new file mode 100644 index 000000000..84af3d105 --- /dev/null +++ b/src/core/hle/service/time/steady_clock_core.h | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/uuid.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Time::Clock { | ||
| 15 | |||
| 16 | class SteadyClockCore { | ||
| 17 | public: | ||
| 18 | SteadyClockCore() = default; | ||
| 19 | |||
| 20 | const Common::UUID& GetClockSourceId() const { | ||
| 21 | return clock_source_id; | ||
| 22 | } | ||
| 23 | |||
| 24 | void SetClockSourceId(const Common::UUID& value) { | ||
| 25 | clock_source_id = value; | ||
| 26 | } | ||
| 27 | |||
| 28 | virtual TimeSpanType GetInternalOffset() const = 0; | ||
| 29 | |||
| 30 | virtual void SetInternalOffset(TimeSpanType internal_offset) = 0; | ||
| 31 | |||
| 32 | virtual SteadyClockTimePoint GetTimePoint(Core::System& system) = 0; | ||
| 33 | |||
| 34 | virtual TimeSpanType GetCurrentRawTimePoint(Core::System& system) = 0; | ||
| 35 | |||
| 36 | SteadyClockTimePoint GetCurrentTimePoint(Core::System& system) { | ||
| 37 | SteadyClockTimePoint result{GetTimePoint(system)}; | ||
| 38 | result.time_point += GetInternalOffset().ToSeconds(); | ||
| 39 | return result; | ||
| 40 | } | ||
| 41 | |||
| 42 | bool IsInitialized() const { | ||
| 43 | return is_initialized; | ||
| 44 | } | ||
| 45 | |||
| 46 | void MarkAsInitialized() { | ||
| 47 | is_initialized = true; | ||
| 48 | } | ||
| 49 | |||
| 50 | private: | ||
| 51 | Common::UUID clock_source_id{Common::UUID::Generate()}; | ||
| 52 | bool is_initialized{}; | ||
| 53 | }; | ||
| 54 | |||
| 55 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.cpp b/src/core/hle/service/time/system_clock_context_update_callback.cpp new file mode 100644 index 000000000..5cdb80703 --- /dev/null +++ b/src/core/hle/service/time/system_clock_context_update_callback.cpp | |||
| @@ -0,0 +1,55 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/kernel/writable_event.h" | ||
| 6 | #include "core/hle/service/time/errors.h" | ||
| 7 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | SystemClockContextUpdateCallback::SystemClockContextUpdateCallback() = default; | ||
| 12 | SystemClockContextUpdateCallback::~SystemClockContextUpdateCallback() = default; | ||
| 13 | |||
| 14 | bool SystemClockContextUpdateCallback::NeedUpdate(const SystemClockContext& value) const { | ||
| 15 | if (has_context) { | ||
| 16 | return context.offset != value.offset || | ||
| 17 | context.steady_time_point.clock_source_id != value.steady_time_point.clock_source_id; | ||
| 18 | } | ||
| 19 | |||
| 20 | return true; | ||
| 21 | } | ||
| 22 | |||
| 23 | void SystemClockContextUpdateCallback::RegisterOperationEvent( | ||
| 24 | std::shared_ptr<Kernel::WritableEvent>&& writable_event) { | ||
| 25 | operation_event_list.emplace_back(std::move(writable_event)); | ||
| 26 | } | ||
| 27 | |||
| 28 | void SystemClockContextUpdateCallback::BroadcastOperationEvent() { | ||
| 29 | for (const auto& writable_event : operation_event_list) { | ||
| 30 | writable_event->Signal(); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | ResultCode SystemClockContextUpdateCallback::Update(const SystemClockContext& value) { | ||
| 35 | ResultCode result{RESULT_SUCCESS}; | ||
| 36 | |||
| 37 | if (NeedUpdate(value)) { | ||
| 38 | context = value; | ||
| 39 | has_context = true; | ||
| 40 | |||
| 41 | result = Update(); | ||
| 42 | |||
| 43 | if (result == RESULT_SUCCESS) { | ||
| 44 | BroadcastOperationEvent(); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | |||
| 48 | return result; | ||
| 49 | } | ||
| 50 | |||
| 51 | ResultCode SystemClockContextUpdateCallback::Update() { | ||
| 52 | return RESULT_SUCCESS; | ||
| 53 | } | ||
| 54 | |||
| 55 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_context_update_callback.h b/src/core/hle/service/time/system_clock_context_update_callback.h new file mode 100644 index 000000000..6260de6c3 --- /dev/null +++ b/src/core/hle/service/time/system_clock_context_update_callback.h | |||
| @@ -0,0 +1,43 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <vector> | ||
| 8 | |||
| 9 | #include "core/hle/service/time/clock_types.h" | ||
| 10 | |||
| 11 | namespace Kernel { | ||
| 12 | class WritableEvent; | ||
| 13 | } | ||
| 14 | |||
| 15 | namespace Service::Time::Clock { | ||
| 16 | |||
| 17 | // Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). | ||
| 18 | // This code was released under public domain. | ||
| 19 | |||
| 20 | class SystemClockContextUpdateCallback { | ||
| 21 | public: | ||
| 22 | SystemClockContextUpdateCallback(); | ||
| 23 | ~SystemClockContextUpdateCallback(); | ||
| 24 | |||
| 25 | bool NeedUpdate(const SystemClockContext& value) const; | ||
| 26 | |||
| 27 | void RegisterOperationEvent(std::shared_ptr<Kernel::WritableEvent>&& writable_event); | ||
| 28 | |||
| 29 | void BroadcastOperationEvent(); | ||
| 30 | |||
| 31 | ResultCode Update(const SystemClockContext& value); | ||
| 32 | |||
| 33 | protected: | ||
| 34 | virtual ResultCode Update(); | ||
| 35 | |||
| 36 | SystemClockContext context{}; | ||
| 37 | |||
| 38 | private: | ||
| 39 | bool has_context{}; | ||
| 40 | std::vector<std::shared_ptr<Kernel::WritableEvent>> operation_event_list; | ||
| 41 | }; | ||
| 42 | |||
| 43 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_core.cpp b/src/core/hle/service/time/system_clock_core.cpp new file mode 100644 index 000000000..1a3ab8cfa --- /dev/null +++ b/src/core/hle/service/time/system_clock_core.cpp | |||
| @@ -0,0 +1,72 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 6 | #include "core/hle/service/time/system_clock_context_update_callback.h" | ||
| 7 | #include "core/hle/service/time/system_clock_core.h" | ||
| 8 | |||
| 9 | namespace Service::Time::Clock { | ||
| 10 | |||
| 11 | SystemClockCore::SystemClockCore(SteadyClockCore& steady_clock_core) | ||
| 12 | : steady_clock_core{steady_clock_core}, is_initialized{} { | ||
| 13 | context.steady_time_point.clock_source_id = steady_clock_core.GetClockSourceId(); | ||
| 14 | } | ||
| 15 | |||
| 16 | SystemClockCore ::~SystemClockCore() = default; | ||
| 17 | |||
| 18 | ResultCode SystemClockCore::GetCurrentTime(Core::System& system, s64& posix_time) const { | ||
| 19 | posix_time = 0; | ||
| 20 | |||
| 21 | const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 22 | |||
| 23 | SystemClockContext clock_context{}; | ||
| 24 | if (const ResultCode result{GetClockContext(system, clock_context)}; result != RESULT_SUCCESS) { | ||
| 25 | return result; | ||
| 26 | } | ||
| 27 | |||
| 28 | if (current_time_point.clock_source_id != clock_context.steady_time_point.clock_source_id) { | ||
| 29 | return ERROR_TIME_MISMATCH; | ||
| 30 | } | ||
| 31 | |||
| 32 | posix_time = clock_context.offset + current_time_point.time_point; | ||
| 33 | |||
| 34 | return RESULT_SUCCESS; | ||
| 35 | } | ||
| 36 | |||
| 37 | ResultCode SystemClockCore::SetCurrentTime(Core::System& system, s64 posix_time) { | ||
| 38 | const SteadyClockTimePoint current_time_point{steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 39 | const SystemClockContext clock_context{posix_time - current_time_point.time_point, | ||
| 40 | current_time_point}; | ||
| 41 | |||
| 42 | if (const ResultCode result{SetClockContext(clock_context)}; result != RESULT_SUCCESS) { | ||
| 43 | return result; | ||
| 44 | } | ||
| 45 | return Flush(clock_context); | ||
| 46 | } | ||
| 47 | |||
| 48 | ResultCode SystemClockCore::Flush(const SystemClockContext& context) { | ||
| 49 | if (!system_clock_context_update_callback) { | ||
| 50 | return RESULT_SUCCESS; | ||
| 51 | } | ||
| 52 | return system_clock_context_update_callback->Update(context); | ||
| 53 | } | ||
| 54 | |||
| 55 | ResultCode SystemClockCore::SetSystemClockContext(const SystemClockContext& context) { | ||
| 56 | if (const ResultCode result{SetClockContext(context)}; result != RESULT_SUCCESS) { | ||
| 57 | return result; | ||
| 58 | } | ||
| 59 | return Flush(context); | ||
| 60 | } | ||
| 61 | |||
| 62 | bool SystemClockCore::IsClockSetup(Core::System& system) const { | ||
| 63 | SystemClockContext value{}; | ||
| 64 | if (GetClockContext(system, value) == RESULT_SUCCESS) { | ||
| 65 | const SteadyClockTimePoint steady_clock_time_point{ | ||
| 66 | steady_clock_core.GetCurrentTimePoint(system)}; | ||
| 67 | return steady_clock_time_point.clock_source_id == value.steady_time_point.clock_source_id; | ||
| 68 | } | ||
| 69 | return {}; | ||
| 70 | } | ||
| 71 | |||
| 72 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/system_clock_core.h b/src/core/hle/service/time/system_clock_core.h new file mode 100644 index 000000000..54407a6c5 --- /dev/null +++ b/src/core/hle/service/time/system_clock_core.h | |||
| @@ -0,0 +1,71 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Time::Clock { | ||
| 15 | |||
| 16 | class SteadyClockCore; | ||
| 17 | class SystemClockContextUpdateCallback; | ||
| 18 | |||
| 19 | // Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). | ||
| 20 | // This code was released under public domain. | ||
| 21 | |||
| 22 | class SystemClockCore { | ||
| 23 | public: | ||
| 24 | explicit SystemClockCore(SteadyClockCore& steady_clock_core); | ||
| 25 | ~SystemClockCore(); | ||
| 26 | |||
| 27 | SteadyClockCore& GetSteadyClockCore() const { | ||
| 28 | return steady_clock_core; | ||
| 29 | } | ||
| 30 | |||
| 31 | ResultCode GetCurrentTime(Core::System& system, s64& posix_time) const; | ||
| 32 | |||
| 33 | ResultCode SetCurrentTime(Core::System& system, s64 posix_time); | ||
| 34 | |||
| 35 | virtual ResultCode GetClockContext([[maybe_unused]] Core::System& system, | ||
| 36 | SystemClockContext& value) const { | ||
| 37 | value = context; | ||
| 38 | return RESULT_SUCCESS; | ||
| 39 | } | ||
| 40 | |||
| 41 | virtual ResultCode SetClockContext(const SystemClockContext& value) { | ||
| 42 | context = value; | ||
| 43 | return RESULT_SUCCESS; | ||
| 44 | } | ||
| 45 | |||
| 46 | virtual ResultCode Flush(const SystemClockContext& context); | ||
| 47 | |||
| 48 | void SetUpdateCallbackInstance(std::shared_ptr<SystemClockContextUpdateCallback> callback) { | ||
| 49 | system_clock_context_update_callback = std::move(callback); | ||
| 50 | } | ||
| 51 | |||
| 52 | ResultCode SetSystemClockContext(const SystemClockContext& context); | ||
| 53 | |||
| 54 | bool IsInitialized() const { | ||
| 55 | return is_initialized; | ||
| 56 | } | ||
| 57 | |||
| 58 | void MarkAsInitialized() { | ||
| 59 | is_initialized = true; | ||
| 60 | } | ||
| 61 | |||
| 62 | bool IsClockSetup(Core::System& system) const; | ||
| 63 | |||
| 64 | private: | ||
| 65 | SteadyClockCore& steady_clock_core; | ||
| 66 | SystemClockContext context{}; | ||
| 67 | bool is_initialized{}; | ||
| 68 | std::shared_ptr<SystemClockContextUpdateCallback> system_clock_context_update_callback; | ||
| 69 | }; | ||
| 70 | |||
| 71 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.cpp b/src/core/hle/service/time/tick_based_steady_clock_core.cpp new file mode 100644 index 000000000..c77b98189 --- /dev/null +++ b/src/core/hle/service/time/tick_based_steady_clock_core.cpp | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/core_timing_util.h" | ||
| 8 | #include "core/hle/service/time/tick_based_steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Service::Time::Clock { | ||
| 11 | |||
| 12 | SteadyClockTimePoint TickBasedSteadyClockCore::GetTimePoint(Core::System& system) { | ||
| 13 | const TimeSpanType ticks_time_span{TimeSpanType::FromTicks( | ||
| 14 | Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), | ||
| 15 | Core::Timing::CNTFREQ)}; | ||
| 16 | |||
| 17 | return {ticks_time_span.ToSeconds(), GetClockSourceId()}; | ||
| 18 | } | ||
| 19 | |||
| 20 | TimeSpanType TickBasedSteadyClockCore::GetCurrentRawTimePoint(Core::System& system) { | ||
| 21 | return TimeSpanType::FromSeconds(GetTimePoint(system).time_point); | ||
| 22 | } | ||
| 23 | |||
| 24 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/tick_based_steady_clock_core.h b/src/core/hle/service/time/tick_based_steady_clock_core.h new file mode 100644 index 000000000..1a5a53fd7 --- /dev/null +++ b/src/core/hle/service/time/tick_based_steady_clock_core.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // Copyright 2020 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/time/clock_types.h" | ||
| 8 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 9 | |||
| 10 | namespace Core { | ||
| 11 | class System; | ||
| 12 | } | ||
| 13 | |||
| 14 | namespace Service::Time::Clock { | ||
| 15 | |||
| 16 | class TickBasedSteadyClockCore final : public SteadyClockCore { | ||
| 17 | public: | ||
| 18 | TimeSpanType GetInternalOffset() const override { | ||
| 19 | return {}; | ||
| 20 | } | ||
| 21 | |||
| 22 | void SetInternalOffset(TimeSpanType internal_offset) override {} | ||
| 23 | |||
| 24 | SteadyClockTimePoint GetTimePoint(Core::System& system) override; | ||
| 25 | |||
| 26 | TimeSpanType GetCurrentRawTimePoint(Core::System& system) override; | ||
| 27 | }; | ||
| 28 | |||
| 29 | } // namespace Service::Time::Clock | ||
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index 6ee77c5f9..8ef4efcef 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -1,9 +1,7 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2019 yuzu emulator team |
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <chrono> | ||
| 6 | #include <ctime> | ||
| 7 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 6 | #include "core/core.h" |
| 9 | #include "core/core_timing.h" | 7 | #include "core/core_timing.h" |
| @@ -11,429 +9,321 @@ | |||
| 11 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| 12 | #include "core/hle/kernel/client_port.h" | 10 | #include "core/hle/kernel/client_port.h" |
| 13 | #include "core/hle/kernel/client_session.h" | 11 | #include "core/hle/kernel/client_session.h" |
| 12 | #include "core/hle/kernel/scheduler.h" | ||
| 14 | #include "core/hle/service/time/interface.h" | 13 | #include "core/hle/service/time/interface.h" |
| 15 | #include "core/hle/service/time/time.h" | 14 | #include "core/hle/service/time/time.h" |
| 16 | #include "core/hle/service/time/time_sharedmemory.h" | 15 | #include "core/hle/service/time/time_sharedmemory.h" |
| 17 | #include "core/settings.h" | 16 | #include "core/hle/service/time/time_zone_service.h" |
| 18 | 17 | ||
| 19 | namespace Service::Time { | 18 | namespace Service::Time { |
| 20 | 19 | ||
| 21 | static std::chrono::seconds GetSecondsSinceEpoch() { | ||
| 22 | return std::chrono::duration_cast<std::chrono::seconds>( | ||
| 23 | std::chrono::system_clock::now().time_since_epoch()) + | ||
| 24 | Settings::values.custom_rtc_differential; | ||
| 25 | } | ||
| 26 | |||
| 27 | static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time, | ||
| 28 | CalendarAdditionalInfo& additional_info, | ||
| 29 | [[maybe_unused]] const TimeZoneRule& /*rule*/) { | ||
| 30 | const std::time_t time(posix_time); | ||
| 31 | const std::tm* tm = std::localtime(&time); | ||
| 32 | if (tm == nullptr) { | ||
| 33 | calendar_time = {}; | ||
| 34 | additional_info = {}; | ||
| 35 | return; | ||
| 36 | } | ||
| 37 | calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); | ||
| 38 | calendar_time.month = static_cast<u8>(tm->tm_mon + 1); | ||
| 39 | calendar_time.day = static_cast<u8>(tm->tm_mday); | ||
| 40 | calendar_time.hour = static_cast<u8>(tm->tm_hour); | ||
| 41 | calendar_time.minute = static_cast<u8>(tm->tm_min); | ||
| 42 | calendar_time.second = static_cast<u8>(tm->tm_sec); | ||
| 43 | |||
| 44 | additional_info.day_of_week = tm->tm_wday; | ||
| 45 | additional_info.day_of_year = tm->tm_yday; | ||
| 46 | std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC")); | ||
| 47 | additional_info.utc_offset = 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | static u64 CalendarToPosix(const CalendarTime& calendar_time, | ||
| 51 | [[maybe_unused]] const TimeZoneRule& /*rule*/) { | ||
| 52 | std::tm time{}; | ||
| 53 | time.tm_year = calendar_time.year - 1900; | ||
| 54 | time.tm_mon = calendar_time.month - 1; | ||
| 55 | time.tm_mday = calendar_time.day; | ||
| 56 | |||
| 57 | time.tm_hour = calendar_time.hour; | ||
| 58 | time.tm_min = calendar_time.minute; | ||
| 59 | time.tm_sec = calendar_time.second; | ||
| 60 | |||
| 61 | std::time_t epoch_time = std::mktime(&time); | ||
| 62 | return static_cast<u64>(epoch_time); | ||
| 63 | } | ||
| 64 | |||
| 65 | enum class ClockContextType { | ||
| 66 | StandardSteady, | ||
| 67 | StandardUserSystem, | ||
| 68 | StandardNetworkSystem, | ||
| 69 | StandardLocalSystem, | ||
| 70 | }; | ||
| 71 | |||
| 72 | class ISystemClock final : public ServiceFramework<ISystemClock> { | 20 | class ISystemClock final : public ServiceFramework<ISystemClock> { |
| 73 | public: | 21 | public: |
| 74 | ISystemClock(std::shared_ptr<Service::Time::SharedMemory> shared_memory, | 22 | ISystemClock(Clock::SystemClockCore& clock_core) |
| 75 | ClockContextType clock_type) | 23 | : ServiceFramework("ISystemClock"), clock_core{clock_core} { |
| 76 | : ServiceFramework("ISystemClock"), shared_memory(shared_memory), clock_type(clock_type) { | ||
| 77 | // clang-format off | 24 | // clang-format off |
| 78 | static const FunctionInfo functions[] = { | 25 | static const FunctionInfo functions[] = { |
| 79 | {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, | 26 | {0, &ISystemClock::GetCurrentTime, "GetCurrentTime"}, |
| 80 | {1, nullptr, "SetCurrentTime"}, | 27 | {1, nullptr, "SetCurrentTime"}, |
| 81 | {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, | 28 | {2, &ISystemClock::GetSystemClockContext, "GetSystemClockContext"}, |
| 82 | {3, nullptr, "SetSystemClockContext"}, | 29 | {3, nullptr, "SetSystemClockContext"}, |
| 83 | {4, nullptr, "GetOperationEventReadableHandle"}, | 30 | {4, nullptr, "GetOperationEventReadableHandle"}, |
| 84 | }; | 31 | }; |
| 85 | // clang-format on | 32 | // clang-format on |
| 86 | 33 | ||
| 87 | RegisterHandlers(functions); | 34 | RegisterHandlers(functions); |
| 88 | UpdateSharedMemoryContext(system_clock_context); | ||
| 89 | } | 35 | } |
| 90 | 36 | ||
| 91 | private: | 37 | private: |
| 92 | void GetCurrentTime(Kernel::HLERequestContext& ctx) { | 38 | void GetCurrentTime(Kernel::HLERequestContext& ctx) { |
| 93 | const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; | ||
| 94 | LOG_DEBUG(Service_Time, "called"); | 39 | LOG_DEBUG(Service_Time, "called"); |
| 95 | 40 | ||
| 41 | if (!clock_core.IsInitialized()) { | ||
| 42 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 43 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | ||
| 44 | return; | ||
| 45 | } | ||
| 46 | |||
| 47 | s64 posix_time{}; | ||
| 48 | if (const ResultCode result{ | ||
| 49 | clock_core.GetCurrentTime(Core::System::GetInstance(), posix_time)}; | ||
| 50 | result != RESULT_SUCCESS) { | ||
| 51 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 52 | rb.Push(result); | ||
| 53 | return; | ||
| 54 | } | ||
| 55 | |||
| 96 | IPC::ResponseBuilder rb{ctx, 4}; | 56 | IPC::ResponseBuilder rb{ctx, 4}; |
| 97 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 98 | rb.Push<u64>(time_since_epoch); | 58 | rb.Push<s64>(posix_time); |
| 99 | } | 59 | } |
| 100 | 60 | ||
| 101 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { | 61 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { |
| 102 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 62 | LOG_DEBUG(Service_Time, "called"); |
| 63 | |||
| 64 | if (!clock_core.IsInitialized()) { | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 66 | rb.Push(ERROR_UNINITIALIZED_CLOCK); | ||
| 67 | return; | ||
| 68 | } | ||
| 103 | 69 | ||
| 104 | // TODO(ogniK): This should be updated periodically however since we have it stubbed we'll | 70 | Clock::SystemClockContext system_clock_context{}; |
| 105 | // only update when we get a new context | 71 | if (const ResultCode result{ |
| 106 | UpdateSharedMemoryContext(system_clock_context); | 72 | clock_core.GetClockContext(Core::System::GetInstance(), system_clock_context)}; |
| 73 | result != RESULT_SUCCESS) { | ||
| 74 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 75 | rb.Push(result); | ||
| 76 | return; | ||
| 77 | } | ||
| 107 | 78 | ||
| 108 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; | 79 | IPC::ResponseBuilder rb{ctx, sizeof(Clock::SystemClockContext) / 4 + 2}; |
| 109 | rb.Push(RESULT_SUCCESS); | 80 | rb.Push(RESULT_SUCCESS); |
| 110 | rb.PushRaw(system_clock_context); | 81 | rb.PushRaw(system_clock_context); |
| 111 | } | 82 | } |
| 112 | 83 | ||
| 113 | void UpdateSharedMemoryContext(const SystemClockContext& clock_context) { | 84 | Clock::SystemClockCore& clock_core; |
| 114 | switch (clock_type) { | ||
| 115 | case ClockContextType::StandardLocalSystem: | ||
| 116 | shared_memory->SetStandardLocalSystemClockContext(clock_context); | ||
| 117 | break; | ||
| 118 | case ClockContextType::StandardNetworkSystem: | ||
| 119 | shared_memory->SetStandardNetworkSystemClockContext(clock_context); | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | SystemClockContext system_clock_context{}; | ||
| 125 | std::shared_ptr<Service::Time::SharedMemory> shared_memory; | ||
| 126 | ClockContextType clock_type; | ||
| 127 | }; | 85 | }; |
| 128 | 86 | ||
| 129 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { | 87 | class ISteadyClock final : public ServiceFramework<ISteadyClock> { |
| 130 | public: | 88 | public: |
| 131 | ISteadyClock(std::shared_ptr<SharedMemory> shared_memory, Core::System& system) | 89 | ISteadyClock(Clock::SteadyClockCore& clock_core) |
| 132 | : ServiceFramework("ISteadyClock"), shared_memory(shared_memory), system(system) { | 90 | : ServiceFramework("ISteadyClock"), clock_core{clock_core} { |
| 133 | static const FunctionInfo functions[] = { | 91 | static const FunctionInfo functions[] = { |
| 134 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, | 92 | {0, &ISteadyClock::GetCurrentTimePoint, "GetCurrentTimePoint"}, |
| 135 | }; | 93 | }; |
| 136 | RegisterHandlers(functions); | 94 | RegisterHandlers(functions); |
| 137 | |||
| 138 | shared_memory->SetStandardSteadyClockTimepoint(GetCurrentTimePoint()); | ||
| 139 | } | 95 | } |
| 140 | 96 | ||
| 141 | private: | 97 | private: |
| 142 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { | 98 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { |
| 143 | LOG_DEBUG(Service_Time, "called"); | 99 | LOG_DEBUG(Service_Time, "called"); |
| 144 | 100 | ||
| 145 | const auto time_point = GetCurrentTimePoint(); | 101 | if (!clock_core.IsInitialized()) { |
| 146 | // TODO(ogniK): This should be updated periodically | 102 | IPC::ResponseBuilder rb{ctx, 2}; |
| 147 | shared_memory->SetStandardSteadyClockTimepoint(time_point); | 103 | rb.Push(ERROR_UNINITIALIZED_CLOCK); |
| 104 | return; | ||
| 105 | } | ||
| 148 | 106 | ||
| 149 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; | 107 | const Clock::SteadyClockTimePoint time_point{ |
| 108 | clock_core.GetCurrentTimePoint(Core::System::GetInstance())}; | ||
| 109 | IPC::ResponseBuilder rb{ctx, (sizeof(Clock::SteadyClockTimePoint) / 4) + 2}; | ||
| 150 | rb.Push(RESULT_SUCCESS); | 110 | rb.Push(RESULT_SUCCESS); |
| 151 | rb.PushRaw(time_point); | 111 | rb.PushRaw(time_point); |
| 152 | } | 112 | } |
| 153 | 113 | ||
| 154 | SteadyClockTimePoint GetCurrentTimePoint() const { | 114 | Clock::SteadyClockCore& clock_core; |
| 155 | const auto& core_timing = system.CoreTiming(); | ||
| 156 | const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); | ||
| 157 | return {static_cast<u64_le>(ms.count() / 1000), {}}; | ||
| 158 | } | ||
| 159 | |||
| 160 | std::shared_ptr<SharedMemory> shared_memory; | ||
| 161 | Core::System& system; | ||
| 162 | }; | 115 | }; |
| 163 | 116 | ||
| 164 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { | 117 | ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal( |
| 165 | public: | 118 | Kernel::Thread* thread, Clock::SystemClockContext user_context, |
| 166 | ITimeZoneService() : ServiceFramework("ITimeZoneService") { | 119 | Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) { |
| 167 | // clang-format off | ||
| 168 | static const FunctionInfo functions[] = { | ||
| 169 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, | ||
| 170 | {1, nullptr, "SetDeviceLocationName"}, | ||
| 171 | {2, &ITimeZoneService::GetTotalLocationNameCount, "GetTotalLocationNameCount"}, | ||
| 172 | {3, nullptr, "LoadLocationNameList"}, | ||
| 173 | {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, | ||
| 174 | {5, nullptr, "GetTimeZoneRuleVersion"}, | ||
| 175 | {6, nullptr, "GetDeviceLocationNameAndUpdatedTime"}, | ||
| 176 | {7, nullptr, "SetDeviceLocationNameWithTimeZoneRule"}, | ||
| 177 | {8, nullptr, "ParseTimeZoneBinary"}, | ||
| 178 | {20, nullptr, "GetDeviceLocationNameOperationEventReadableHandle"}, | ||
| 179 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, | ||
| 180 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | ||
| 181 | {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, | ||
| 182 | {202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"}, | ||
| 183 | }; | ||
| 184 | // clang-format on | ||
| 185 | |||
| 186 | RegisterHandlers(functions); | ||
| 187 | } | ||
| 188 | 120 | ||
| 189 | private: | 121 | auto& time_manager{module->GetTimeManager()}; |
| 190 | LocationName location_name{"UTC"}; | ||
| 191 | TimeZoneRule my_time_zone_rule{}; | ||
| 192 | 122 | ||
| 193 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { | 123 | clock_snapshot.is_automatic_correction_enabled = |
| 194 | LOG_DEBUG(Service_Time, "called"); | 124 | time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled(); |
| 125 | clock_snapshot.user_context = user_context; | ||
| 126 | clock_snapshot.network_context = network_context; | ||
| 195 | 127 | ||
| 196 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; | 128 | if (const ResultCode result{ |
| 197 | rb.Push(RESULT_SUCCESS); | 129 | time_manager.GetTimeZoneContentManager().GetTimeZoneManager().GetDeviceLocationName( |
| 198 | rb.PushRaw(location_name); | 130 | clock_snapshot.location_name)}; |
| 131 | result != RESULT_SUCCESS) { | ||
| 132 | return result; | ||
| 199 | } | 133 | } |
| 200 | 134 | ||
| 201 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { | 135 | const auto current_time_point{ |
| 202 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 136 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(Core::System::GetInstance())}; |
| 203 | 137 | if (const ResultCode result{Clock::ClockSnapshot::GetCurrentTime( | |
| 204 | IPC::ResponseBuilder rb{ctx, 3}; | 138 | clock_snapshot.user_time, current_time_point, clock_snapshot.user_context)}; |
| 205 | rb.Push(RESULT_SUCCESS); | 139 | result != RESULT_SUCCESS) { |
| 206 | rb.Push<u32>(0); | 140 | return result; |
| 207 | } | 141 | } |
| 208 | 142 | ||
| 209 | void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) { | 143 | TimeZone::CalendarInfo userCalendarInfo{}; |
| 210 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 144 | if (const ResultCode result{ |
| 211 | 145 | time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules( | |
| 212 | ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule)); | 146 | clock_snapshot.user_time, userCalendarInfo)}; |
| 213 | 147 | result != RESULT_SUCCESS) { | |
| 214 | IPC::ResponseBuilder rb{ctx, 2}; | 148 | return result; |
| 215 | rb.Push(RESULT_SUCCESS); | ||
| 216 | } | 149 | } |
| 217 | 150 | ||
| 218 | void ToCalendarTime(Kernel::HLERequestContext& ctx) { | 151 | clock_snapshot.user_calendar_time = userCalendarInfo.time; |
| 219 | IPC::RequestParser rp{ctx}; | 152 | clock_snapshot.user_calendar_additional_time = userCalendarInfo.additiona_info; |
| 220 | const u64 posix_time = rp.Pop<u64>(); | ||
| 221 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | ||
| 222 | |||
| 223 | TimeZoneRule time_zone_rule{}; | ||
| 224 | auto buffer = ctx.ReadBuffer(); | ||
| 225 | std::memcpy(&time_zone_rule, buffer.data(), buffer.size()); | ||
| 226 | 153 | ||
| 227 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; | 154 | if (Clock::ClockSnapshot::GetCurrentTime(clock_snapshot.network_time, current_time_point, |
| 228 | CalendarAdditionalInfo additional_info{}; | 155 | clock_snapshot.network_context) != RESULT_SUCCESS) { |
| 229 | 156 | clock_snapshot.network_time = 0; | |
| 230 | PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule); | ||
| 231 | |||
| 232 | IPC::ResponseBuilder rb{ctx, 10}; | ||
| 233 | rb.Push(RESULT_SUCCESS); | ||
| 234 | rb.PushRaw(calendar_time); | ||
| 235 | rb.PushRaw(additional_info); | ||
| 236 | } | ||
| 237 | |||
| 238 | void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { | ||
| 239 | IPC::RequestParser rp{ctx}; | ||
| 240 | const u64 posix_time = rp.Pop<u64>(); | ||
| 241 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | ||
| 242 | |||
| 243 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; | ||
| 244 | CalendarAdditionalInfo additional_info{}; | ||
| 245 | |||
| 246 | PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule); | ||
| 247 | |||
| 248 | IPC::ResponseBuilder rb{ctx, 10}; | ||
| 249 | rb.Push(RESULT_SUCCESS); | ||
| 250 | rb.PushRaw(calendar_time); | ||
| 251 | rb.PushRaw(additional_info); | ||
| 252 | } | 157 | } |
| 253 | 158 | ||
| 254 | void ToPosixTime(Kernel::HLERequestContext& ctx) { | 159 | TimeZone::CalendarInfo networkCalendarInfo{}; |
| 255 | // TODO(ogniK): Figure out how to handle multiple times | 160 | if (const ResultCode result{ |
| 256 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 161 | time_manager.GetTimeZoneContentManager().GetTimeZoneManager().ToCalendarTimeWithMyRules( |
| 257 | 162 | clock_snapshot.network_time, networkCalendarInfo)}; | |
| 258 | IPC::RequestParser rp{ctx}; | 163 | result != RESULT_SUCCESS) { |
| 259 | auto calendar_time = rp.PopRaw<CalendarTime>(); | 164 | return result; |
| 260 | auto posix_time = CalendarToPosix(calendar_time, {}); | ||
| 261 | |||
| 262 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 263 | rb.Push(RESULT_SUCCESS); | ||
| 264 | rb.PushRaw<u32>(1); // Amount of times we're returning | ||
| 265 | ctx.WriteBuffer(&posix_time, sizeof(u64)); | ||
| 266 | } | 165 | } |
| 267 | 166 | ||
| 268 | void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { | 167 | clock_snapshot.network_calendar_time = networkCalendarInfo.time; |
| 269 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 168 | clock_snapshot.network_calendar_additional_time = networkCalendarInfo.additiona_info; |
| 270 | 169 | clock_snapshot.type = type; | |
| 271 | IPC::RequestParser rp{ctx}; | ||
| 272 | auto calendar_time = rp.PopRaw<CalendarTime>(); | ||
| 273 | auto posix_time = CalendarToPosix(calendar_time, {}); | ||
| 274 | 170 | ||
| 275 | IPC::ResponseBuilder rb{ctx, 3}; | 171 | return RESULT_SUCCESS; |
| 276 | rb.Push(RESULT_SUCCESS); | 172 | } |
| 277 | rb.PushRaw<u32>(1); // Amount of times we're returning | ||
| 278 | ctx.WriteBuffer(&posix_time, sizeof(u64)); | ||
| 279 | } | ||
| 280 | }; | ||
| 281 | 173 | ||
| 282 | void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { | 174 | void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { |
| 283 | LOG_DEBUG(Service_Time, "called"); | 175 | LOG_DEBUG(Service_Time, "called"); |
| 284 | |||
| 285 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 286 | rb.Push(RESULT_SUCCESS); | 177 | rb.Push(RESULT_SUCCESS); |
| 287 | rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardUserSystem); | 178 | rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore()); |
| 288 | } | 179 | } |
| 289 | 180 | ||
| 290 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { | 181 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { |
| 291 | LOG_DEBUG(Service_Time, "called"); | 182 | LOG_DEBUG(Service_Time, "called"); |
| 292 | |||
| 293 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 183 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 294 | rb.Push(RESULT_SUCCESS); | 184 | rb.Push(RESULT_SUCCESS); |
| 295 | rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardNetworkSystem); | 185 | rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore()); |
| 296 | } | 186 | } |
| 297 | 187 | ||
| 298 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { | 188 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { |
| 299 | LOG_DEBUG(Service_Time, "called"); | 189 | LOG_DEBUG(Service_Time, "called"); |
| 300 | |||
| 301 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 190 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 302 | rb.Push(RESULT_SUCCESS); | 191 | rb.Push(RESULT_SUCCESS); |
| 303 | rb.PushIpcInterface<ISteadyClock>(shared_memory, system); | 192 | rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore()); |
| 304 | } | 193 | } |
| 305 | 194 | ||
| 306 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | 195 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { |
| 307 | LOG_DEBUG(Service_Time, "called"); | 196 | LOG_DEBUG(Service_Time, "called"); |
| 308 | |||
| 309 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 197 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 310 | rb.Push(RESULT_SUCCESS); | 198 | rb.Push(RESULT_SUCCESS); |
| 311 | rb.PushIpcInterface<ITimeZoneService>(); | 199 | rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager()); |
| 312 | } | 200 | } |
| 313 | 201 | ||
| 314 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { | 202 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { |
| 315 | LOG_DEBUG(Service_Time, "called"); | 203 | LOG_DEBUG(Service_Time, "called"); |
| 316 | |||
| 317 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 204 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 318 | rb.Push(RESULT_SUCCESS); | 205 | rb.Push(RESULT_SUCCESS); |
| 319 | rb.PushIpcInterface<ISystemClock>(shared_memory, ClockContextType::StandardLocalSystem); | 206 | rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore()); |
| 320 | } | 207 | } |
| 321 | 208 | ||
| 322 | void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | 209 | void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient( |
| 210 | Kernel::HLERequestContext& ctx) { | ||
| 323 | LOG_DEBUG(Service_Time, "called"); | 211 | LOG_DEBUG(Service_Time, "called"); |
| 212 | auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()}; | ||
| 213 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 214 | rb.Push(RESULT_SUCCESS); | ||
| 215 | rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system)); | ||
| 216 | } | ||
| 324 | 217 | ||
| 325 | IPC::RequestParser rp{ctx}; | 218 | void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) { |
| 326 | const auto initial_type = rp.PopRaw<u8>(); | 219 | LOG_DEBUG(Service_Time, "called"); |
| 327 | 220 | ||
| 328 | const s64 time_since_epoch{GetSecondsSinceEpoch().count()}; | 221 | auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()}; |
| 329 | const std::time_t time(time_since_epoch); | 222 | if (!steady_clock_core.IsInitialized()) { |
| 330 | const std::tm* tm = std::localtime(&time); | ||
| 331 | if (tm == nullptr) { | ||
| 332 | LOG_ERROR(Service_Time, "tm is a nullptr"); | ||
| 333 | IPC::ResponseBuilder rb{ctx, 2}; | 223 | IPC::ResponseBuilder rb{ctx, 2}; |
| 334 | rb.Push(RESULT_UNKNOWN); // TODO(ogniK): Find appropriate error code | 224 | rb.Push(ERROR_UNINITIALIZED_CLOCK); |
| 335 | return; | 225 | return; |
| 336 | } | 226 | } |
| 337 | 227 | ||
| 338 | const auto& core_timing = system.CoreTiming(); | 228 | IPC::RequestParser rp{ctx}; |
| 339 | const auto ms = Core::Timing::CyclesToMs(core_timing.GetTicks()); | 229 | const auto context{rp.PopRaw<Clock::SystemClockContext>()}; |
| 340 | const SteadyClockTimePoint steady_clock_time_point{static_cast<u64_le>(ms.count() / 1000), {}}; | 230 | const auto current_time_point{ |
| 341 | 231 | steady_clock_core.GetCurrentTimePoint(Core::System::GetInstance())}; | |
| 342 | CalendarTime calendar_time{}; | 232 | |
| 343 | calendar_time.year = static_cast<u16_le>(tm->tm_year + 1900); | 233 | if (current_time_point.clock_source_id == context.steady_time_point.clock_source_id) { |
| 344 | calendar_time.month = static_cast<u8>(tm->tm_mon + 1); | 234 | const auto ticks{Clock::TimeSpanType::FromTicks( |
| 345 | calendar_time.day = static_cast<u8>(tm->tm_mday); | 235 | Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), |
| 346 | calendar_time.hour = static_cast<u8>(tm->tm_hour); | 236 | Core::Timing::CNTFREQ)}; |
| 347 | calendar_time.minute = static_cast<u8>(tm->tm_min); | 237 | const s64 base_time_point{context.offset + current_time_point.time_point - |
| 348 | calendar_time.second = static_cast<u8>(tm->tm_sec); | 238 | ticks.ToSeconds()}; |
| 239 | IPC::ResponseBuilder rb{ctx, (sizeof(s64) / 4) + 2}; | ||
| 240 | rb.Push(RESULT_SUCCESS); | ||
| 241 | rb.PushRaw(base_time_point); | ||
| 242 | return; | ||
| 243 | } | ||
| 349 | 244 | ||
| 350 | ClockSnapshot clock_snapshot{}; | 245 | IPC::ResponseBuilder rb{ctx, 2}; |
| 351 | clock_snapshot.system_posix_time = time_since_epoch; | 246 | rb.Push(ERROR_TIME_MISMATCH); |
| 352 | clock_snapshot.network_posix_time = time_since_epoch; | 247 | } |
| 353 | clock_snapshot.system_calendar_time = calendar_time; | ||
| 354 | clock_snapshot.network_calendar_time = calendar_time; | ||
| 355 | 248 | ||
| 356 | CalendarAdditionalInfo additional_info{}; | 249 | void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { |
| 357 | PosixToCalendar(time_since_epoch, calendar_time, additional_info, {}); | 250 | LOG_DEBUG(Service_Time, "called"); |
| 251 | IPC::RequestParser rp{ctx}; | ||
| 252 | const auto type{rp.PopRaw<u8>()}; | ||
| 358 | 253 | ||
| 359 | clock_snapshot.system_calendar_info = additional_info; | 254 | Clock::SystemClockContext user_context{}; |
| 360 | clock_snapshot.network_calendar_info = additional_info; | 255 | if (const ResultCode result{ |
| 256 | module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext( | ||
| 257 | Core::System::GetInstance(), user_context)}; | ||
| 258 | result != RESULT_SUCCESS) { | ||
| 259 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 260 | rb.Push(result); | ||
| 261 | return; | ||
| 262 | } | ||
| 263 | Clock::SystemClockContext network_context{}; | ||
| 264 | if (const ResultCode result{ | ||
| 265 | module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext( | ||
| 266 | Core::System::GetInstance(), network_context)}; | ||
| 267 | result != RESULT_SUCCESS) { | ||
| 268 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 269 | rb.Push(result); | ||
| 270 | return; | ||
| 271 | } | ||
| 361 | 272 | ||
| 362 | clock_snapshot.steady_clock_timepoint = steady_clock_time_point; | 273 | Clock::ClockSnapshot clock_snapshot{}; |
| 363 | clock_snapshot.location_name = LocationName{"UTC"}; | 274 | if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal( |
| 364 | clock_snapshot.clock_auto_adjustment_enabled = 1; | 275 | &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; |
| 365 | clock_snapshot.type = initial_type; | 276 | result != RESULT_SUCCESS) { |
| 277 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 278 | rb.Push(result); | ||
| 279 | return; | ||
| 280 | } | ||
| 366 | 281 | ||
| 367 | IPC::ResponseBuilder rb{ctx, 2}; | 282 | IPC::ResponseBuilder rb{ctx, 2}; |
| 368 | rb.Push(RESULT_SUCCESS); | 283 | rb.Push(RESULT_SUCCESS); |
| 369 | ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot)); | 284 | ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot)); |
| 370 | } | 285 | } |
| 371 | 286 | ||
| 372 | void Module::Interface::CalculateStandardUserSystemClockDifferenceByUser( | 287 | void Module::Interface::GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx) { |
| 373 | Kernel::HLERequestContext& ctx) { | ||
| 374 | LOG_DEBUG(Service_Time, "called"); | 288 | LOG_DEBUG(Service_Time, "called"); |
| 375 | |||
| 376 | IPC::RequestParser rp{ctx}; | 289 | IPC::RequestParser rp{ctx}; |
| 377 | const auto snapshot_a = rp.PopRaw<ClockSnapshot>(); | 290 | const auto type{rp.PopRaw<u8>()}; |
| 378 | const auto snapshot_b = rp.PopRaw<ClockSnapshot>(); | 291 | rp.AlignWithPadding(); |
| 379 | const u64 difference = | 292 | |
| 380 | snapshot_b.user_clock_context.offset - snapshot_a.user_clock_context.offset; | 293 | const Clock::SystemClockContext user_context{rp.PopRaw<Clock::SystemClockContext>()}; |
| 294 | const Clock::SystemClockContext network_context{rp.PopRaw<Clock::SystemClockContext>()}; | ||
| 381 | 295 | ||
| 382 | IPC::ResponseBuilder rb{ctx, 4}; | 296 | Clock::ClockSnapshot clock_snapshot{}; |
| 297 | if (const ResultCode result{GetClockSnapshotFromSystemClockContextInternal( | ||
| 298 | &ctx.GetThread(), user_context, network_context, type, clock_snapshot)}; | ||
| 299 | result != RESULT_SUCCESS) { | ||
| 300 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 301 | rb.Push(result); | ||
| 302 | return; | ||
| 303 | } | ||
| 304 | |||
| 305 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 383 | rb.Push(RESULT_SUCCESS); | 306 | rb.Push(RESULT_SUCCESS); |
| 384 | rb.PushRaw<u64>(difference); | 307 | ctx.WriteBuffer(&clock_snapshot, sizeof(Clock::ClockSnapshot)); |
| 385 | } | 308 | } |
| 386 | 309 | ||
| 387 | void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | 310 | void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { |
| 388 | LOG_DEBUG(Service_Time, "called"); | 311 | LOG_DEBUG(Service_Time, "called"); |
| 389 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 312 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 390 | rb.Push(RESULT_SUCCESS); | 313 | rb.Push(RESULT_SUCCESS); |
| 391 | rb.PushCopyObjects(shared_memory->GetSharedMemoryHolder()); | 314 | rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder()); |
| 392 | } | ||
| 393 | |||
| 394 | void Module::Interface::IsStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 395 | Kernel::HLERequestContext& ctx) { | ||
| 396 | // ogniK(TODO): When clock contexts are implemented, the value should be read from the context | ||
| 397 | // instead of our shared memory holder | ||
| 398 | LOG_DEBUG(Service_Time, "called"); | ||
| 399 | |||
| 400 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 401 | rb.Push(RESULT_SUCCESS); | ||
| 402 | rb.Push<u8>(shared_memory->GetStandardUserSystemClockAutomaticCorrectionEnabled()); | ||
| 403 | } | ||
| 404 | |||
| 405 | void Module::Interface::SetStandardUserSystemClockAutomaticCorrectionEnabled( | ||
| 406 | Kernel::HLERequestContext& ctx) { | ||
| 407 | IPC::RequestParser rp{ctx}; | ||
| 408 | const auto enabled = rp.Pop<u8>(); | ||
| 409 | |||
| 410 | LOG_WARNING(Service_Time, "(PARTIAL IMPLEMENTATION) called"); | ||
| 411 | |||
| 412 | // TODO(ogniK): Update clock contexts and correct timespans | ||
| 413 | |||
| 414 | shared_memory->SetStandardUserSystemClockAutomaticCorrectionEnabled(enabled > 0); | ||
| 415 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 416 | rb.Push(RESULT_SUCCESS); | ||
| 417 | } | 315 | } |
| 418 | 316 | ||
| 419 | Module::Interface::Interface(std::shared_ptr<Module> time, | 317 | Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name) |
| 420 | std::shared_ptr<SharedMemory> shared_memory, Core::System& system, | 318 | : ServiceFramework(name), module{std::move(module)}, system{system} {} |
| 421 | const char* name) | ||
| 422 | : ServiceFramework(name), time(std::move(time)), shared_memory(std::move(shared_memory)), | ||
| 423 | system(system) {} | ||
| 424 | 319 | ||
| 425 | Module::Interface::~Interface() = default; | 320 | Module::Interface::~Interface() = default; |
| 426 | 321 | ||
| 427 | void InstallInterfaces(Core::System& system) { | 322 | void InstallInterfaces(Core::System& system) { |
| 428 | auto time = std::make_shared<Module>(); | 323 | auto module{std::make_shared<Module>(system)}; |
| 429 | auto shared_mem = std::make_shared<SharedMemory>(system); | 324 | std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager()); |
| 430 | 325 | std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager()); | |
| 431 | std::make_shared<Time>(time, shared_mem, system, "time:a") | 326 | std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager()); |
| 432 | ->InstallAsService(system.ServiceManager()); | ||
| 433 | std::make_shared<Time>(time, shared_mem, system, "time:s") | ||
| 434 | ->InstallAsService(system.ServiceManager()); | ||
| 435 | std::make_shared<Time>(std::move(time), shared_mem, system, "time:u") | ||
| 436 | ->InstallAsService(system.ServiceManager()); | ||
| 437 | } | 327 | } |
| 438 | 328 | ||
| 439 | } // namespace Service::Time | 329 | } // namespace Service::Time |
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h index c32d32860..aadc2df60 100644 --- a/src/core/hle/service/time/time.h +++ b/src/core/hle/service/time/time.h | |||
| @@ -4,84 +4,23 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include "common/common_funcs.h" | ||
| 9 | #include "core/hle/service/service.h" | 7 | #include "core/hle/service/service.h" |
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | #include "core/hle/service/time/time_manager.h" | ||
| 10 | 10 | ||
| 11 | namespace Service::Time { | 11 | namespace Core { |
| 12 | 12 | class System; | |
| 13 | class SharedMemory; | 13 | } |
| 14 | |||
| 15 | struct LocationName { | ||
| 16 | std::array<u8, 0x24> name; | ||
| 17 | }; | ||
| 18 | static_assert(sizeof(LocationName) == 0x24, "LocationName is incorrect size"); | ||
| 19 | |||
| 20 | struct CalendarTime { | ||
| 21 | u16_le year; | ||
| 22 | u8 month; // Starts at 1 | ||
| 23 | u8 day; // Starts at 1 | ||
| 24 | u8 hour; | ||
| 25 | u8 minute; | ||
| 26 | u8 second; | ||
| 27 | }; | ||
| 28 | static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size"); | ||
| 29 | |||
| 30 | struct CalendarAdditionalInfo { | ||
| 31 | u32_le day_of_week; | ||
| 32 | u32_le day_of_year; | ||
| 33 | std::array<u8, 8> name; | ||
| 34 | u8 is_dst; | ||
| 35 | s32_le utc_offset; | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(CalendarAdditionalInfo) == 0x18, | ||
| 38 | "CalendarAdditionalInfo structure has incorrect size"); | ||
| 39 | |||
| 40 | // TODO(mailwl) RE this structure | ||
| 41 | struct TimeZoneRule { | ||
| 42 | INSERT_PADDING_BYTES(0x4000); | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct SteadyClockTimePoint { | ||
| 46 | using SourceID = std::array<u8, 16>; | ||
| 47 | 14 | ||
| 48 | u64_le value; | 15 | namespace Service::Time { |
| 49 | SourceID source_id; | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); | ||
| 52 | |||
| 53 | struct SystemClockContext { | ||
| 54 | u64_le offset; | ||
| 55 | SteadyClockTimePoint time_point; | ||
| 56 | }; | ||
| 57 | static_assert(sizeof(SystemClockContext) == 0x20, | ||
| 58 | "SystemClockContext structure has incorrect size"); | ||
| 59 | |||
| 60 | struct ClockSnapshot { | ||
| 61 | SystemClockContext user_clock_context; | ||
| 62 | SystemClockContext network_clock_context; | ||
| 63 | s64_le system_posix_time; | ||
| 64 | s64_le network_posix_time; | ||
| 65 | CalendarTime system_calendar_time; | ||
| 66 | CalendarTime network_calendar_time; | ||
| 67 | CalendarAdditionalInfo system_calendar_info; | ||
| 68 | CalendarAdditionalInfo network_calendar_info; | ||
| 69 | SteadyClockTimePoint steady_clock_timepoint; | ||
| 70 | LocationName location_name; | ||
| 71 | u8 clock_auto_adjustment_enabled; | ||
| 72 | u8 type; | ||
| 73 | u8 version; | ||
| 74 | INSERT_PADDING_BYTES(1); | ||
| 75 | }; | ||
| 76 | static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size"); | ||
| 77 | 16 | ||
| 78 | class Module final { | 17 | class Module final { |
| 79 | public: | 18 | public: |
| 19 | Module(Core::System& system) : time_manager{system} {} | ||
| 20 | |||
| 80 | class Interface : public ServiceFramework<Interface> { | 21 | class Interface : public ServiceFramework<Interface> { |
| 81 | public: | 22 | public: |
| 82 | explicit Interface(std::shared_ptr<Module> time, | 23 | explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name); |
| 83 | std::shared_ptr<SharedMemory> shared_memory, Core::System& system, | ||
| 84 | const char* name); | ||
| 85 | ~Interface() override; | 24 | ~Interface() override; |
| 86 | 25 | ||
| 87 | void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); | 26 | void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx); |
| @@ -89,17 +28,29 @@ public: | |||
| 89 | void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); | 28 | void GetStandardSteadyClock(Kernel::HLERequestContext& ctx); |
| 90 | void GetTimeZoneService(Kernel::HLERequestContext& ctx); | 29 | void GetTimeZoneService(Kernel::HLERequestContext& ctx); |
| 91 | void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); | 30 | void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx); |
| 31 | void IsStandardNetworkSystemClockAccuracySufficient(Kernel::HLERequestContext& ctx); | ||
| 32 | void CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx); | ||
| 92 | void GetClockSnapshot(Kernel::HLERequestContext& ctx); | 33 | void GetClockSnapshot(Kernel::HLERequestContext& ctx); |
| 93 | void CalculateStandardUserSystemClockDifferenceByUser(Kernel::HLERequestContext& ctx); | 34 | void GetClockSnapshotFromSystemClockContext(Kernel::HLERequestContext& ctx); |
| 94 | void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); | 35 | void GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx); |
| 95 | void IsStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx); | 36 | |
| 96 | void SetStandardUserSystemClockAutomaticCorrectionEnabled(Kernel::HLERequestContext& ctx); | 37 | private: |
| 38 | ResultCode GetClockSnapshotFromSystemClockContextInternal( | ||
| 39 | Kernel::Thread* thread, Clock::SystemClockContext user_context, | ||
| 40 | Clock::SystemClockContext network_context, u8 type, | ||
| 41 | Clock::ClockSnapshot& cloc_snapshot); | ||
| 97 | 42 | ||
| 98 | protected: | 43 | protected: |
| 99 | std::shared_ptr<Module> time; | 44 | std::shared_ptr<Module> module; |
| 100 | std::shared_ptr<SharedMemory> shared_memory; | ||
| 101 | Core::System& system; | 45 | Core::System& system; |
| 102 | }; | 46 | }; |
| 47 | |||
| 48 | TimeManager& GetTimeManager() { | ||
| 49 | return time_manager; | ||
| 50 | } | ||
| 51 | |||
| 52 | private: | ||
| 53 | TimeManager time_manager; | ||
| 103 | }; | 54 | }; |
| 104 | 55 | ||
| 105 | /// Registers all Time services with the specified service manager. | 56 | /// Registers all Time services with the specified service manager. |
diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp new file mode 100644 index 000000000..9d6c55865 --- /dev/null +++ b/src/core/hle/service/time/time_manager.cpp | |||
| @@ -0,0 +1,137 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <chrono> | ||
| 6 | #include <ctime> | ||
| 7 | |||
| 8 | #include "core/hle/service/time/ephemeral_network_system_clock_context_writer.h" | ||
| 9 | #include "core/hle/service/time/local_system_clock_context_writer.h" | ||
| 10 | #include "core/hle/service/time/network_system_clock_context_writer.h" | ||
| 11 | #include "core/hle/service/time/time_manager.h" | ||
| 12 | #include "core/settings.h" | ||
| 13 | |||
| 14 | namespace Service::Time { | ||
| 15 | |||
| 16 | constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL}; | ||
| 17 | |||
| 18 | static std::chrono::seconds GetSecondsSinceEpoch() { | ||
| 19 | return std::chrono::duration_cast<std::chrono::seconds>( | ||
| 20 | std::chrono::system_clock::now().time_since_epoch()) + | ||
| 21 | Settings::values.custom_rtc_differential; | ||
| 22 | } | ||
| 23 | |||
| 24 | static s64 GetExternalRtcValue() { | ||
| 25 | return GetSecondsSinceEpoch().count(); | ||
| 26 | } | ||
| 27 | |||
| 28 | TimeManager::TimeManager(Core::System& system) | ||
| 29 | : shared_memory{system}, standard_local_system_clock_core{standard_steady_clock_core}, | ||
| 30 | standard_network_system_clock_core{standard_steady_clock_core}, | ||
| 31 | standard_user_system_clock_core{standard_local_system_clock_core, | ||
| 32 | standard_network_system_clock_core, system}, | ||
| 33 | ephemeral_network_system_clock_core{tick_based_steady_clock_core}, | ||
| 34 | local_system_clock_context_writer{ | ||
| 35 | std::make_shared<Clock::LocalSystemClockContextWriter>(shared_memory)}, | ||
| 36 | network_system_clock_context_writer{ | ||
| 37 | std::make_shared<Clock::NetworkSystemClockContextWriter>(shared_memory)}, | ||
| 38 | ephemeral_network_system_clock_context_writer{ | ||
| 39 | std::make_shared<Clock::EphemeralNetworkSystemClockContextWriter>()}, | ||
| 40 | time_zone_content_manager{*this, system} { | ||
| 41 | |||
| 42 | const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; | ||
| 43 | SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {}); | ||
| 44 | SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); | ||
| 45 | SetupStandardNetworkSystemClock({}, standard_network_clock_accuracy); | ||
| 46 | SetupStandardUserSystemClock(system, {}, Clock::SteadyClockTimePoint::GetRandom()); | ||
| 47 | SetupEphemeralNetworkSystemClock(); | ||
| 48 | } | ||
| 49 | |||
| 50 | TimeManager::~TimeManager() = default; | ||
| 51 | |||
| 52 | void TimeManager::SetupTimeZoneManager(std::string location_name, | ||
| 53 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 54 | std::size_t total_location_name_count, | ||
| 55 | u128 time_zone_rule_version, | ||
| 56 | FileSys::VirtualFile& vfs_file) { | ||
| 57 | if (time_zone_content_manager.GetTimeZoneManager().SetDeviceLocationNameWithTimeZoneRule( | ||
| 58 | location_name, vfs_file) != RESULT_SUCCESS) { | ||
| 59 | UNREACHABLE(); | ||
| 60 | return; | ||
| 61 | } | ||
| 62 | |||
| 63 | time_zone_content_manager.GetTimeZoneManager().SetUpdatedTime(time_zone_updated_time_point); | ||
| 64 | time_zone_content_manager.GetTimeZoneManager().SetTotalLocationNameCount( | ||
| 65 | total_location_name_count); | ||
| 66 | time_zone_content_manager.GetTimeZoneManager().SetTimeZoneRuleVersion(time_zone_rule_version); | ||
| 67 | time_zone_content_manager.GetTimeZoneManager().MarkAsInitialized(); | ||
| 68 | } | ||
| 69 | |||
| 70 | void TimeManager::SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, | ||
| 71 | Clock::TimeSpanType setup_value, | ||
| 72 | Clock::TimeSpanType internal_offset, | ||
| 73 | bool is_rtc_reset_detected) { | ||
| 74 | standard_steady_clock_core.SetClockSourceId(clock_source_id); | ||
| 75 | standard_steady_clock_core.SetSetupValue(setup_value); | ||
| 76 | standard_steady_clock_core.SetInternalOffset(internal_offset); | ||
| 77 | standard_steady_clock_core.MarkAsInitialized(); | ||
| 78 | |||
| 79 | const auto current_time_point{standard_steady_clock_core.GetCurrentRawTimePoint(system)}; | ||
| 80 | shared_memory.SetupStandardSteadyClock(system, clock_source_id, current_time_point); | ||
| 81 | } | ||
| 82 | |||
| 83 | void TimeManager::SetupStandardLocalSystemClock(Core::System& system, | ||
| 84 | Clock::SystemClockContext clock_context, | ||
| 85 | s64 posix_time) { | ||
| 86 | standard_local_system_clock_core.SetUpdateCallbackInstance(local_system_clock_context_writer); | ||
| 87 | |||
| 88 | const auto current_time_point{ | ||
| 89 | standard_local_system_clock_core.GetSteadyClockCore().GetCurrentTimePoint(system)}; | ||
| 90 | if (current_time_point.clock_source_id == clock_context.steady_time_point.clock_source_id) { | ||
| 91 | standard_local_system_clock_core.SetSystemClockContext(clock_context); | ||
| 92 | } else { | ||
| 93 | if (standard_local_system_clock_core.SetCurrentTime(system, posix_time) != RESULT_SUCCESS) { | ||
| 94 | UNREACHABLE(); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | standard_local_system_clock_core.MarkAsInitialized(); | ||
| 100 | } | ||
| 101 | |||
| 102 | void TimeManager::SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, | ||
| 103 | Clock::TimeSpanType sufficient_accuracy) { | ||
| 104 | standard_network_system_clock_core.SetUpdateCallbackInstance( | ||
| 105 | network_system_clock_context_writer); | ||
| 106 | |||
| 107 | if (standard_network_system_clock_core.SetSystemClockContext(clock_context) != RESULT_SUCCESS) { | ||
| 108 | UNREACHABLE(); | ||
| 109 | return; | ||
| 110 | } | ||
| 111 | |||
| 112 | standard_network_system_clock_core.SetStandardNetworkClockSufficientAccuracy( | ||
| 113 | sufficient_accuracy); | ||
| 114 | standard_network_system_clock_core.MarkAsInitialized(); | ||
| 115 | } | ||
| 116 | |||
| 117 | void TimeManager::SetupStandardUserSystemClock( | ||
| 118 | Core::System& system, bool is_automatic_correction_enabled, | ||
| 119 | Clock::SteadyClockTimePoint steady_clock_time_point) { | ||
| 120 | if (standard_user_system_clock_core.SetAutomaticCorrectionEnabled( | ||
| 121 | system, is_automatic_correction_enabled) != RESULT_SUCCESS) { | ||
| 122 | UNREACHABLE(); | ||
| 123 | return; | ||
| 124 | } | ||
| 125 | |||
| 126 | standard_user_system_clock_core.SetAutomaticCorrectionUpdatedTime(steady_clock_time_point); | ||
| 127 | standard_user_system_clock_core.MarkAsInitialized(); | ||
| 128 | shared_memory.SetAutomaticCorrectionEnabled(is_automatic_correction_enabled); | ||
| 129 | } | ||
| 130 | |||
| 131 | void TimeManager::SetupEphemeralNetworkSystemClock() { | ||
| 132 | ephemeral_network_system_clock_core.SetUpdateCallbackInstance( | ||
| 133 | ephemeral_network_system_clock_context_writer); | ||
| 134 | ephemeral_network_system_clock_core.MarkAsInitialized(); | ||
| 135 | } | ||
| 136 | |||
| 137 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_manager.h b/src/core/hle/service/time/time_manager.h new file mode 100644 index 000000000..8e65f0d22 --- /dev/null +++ b/src/core/hle/service/time/time_manager.h | |||
| @@ -0,0 +1,117 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "core/file_sys/vfs_types.h" | ||
| 9 | #include "core/hle/service/time/clock_types.h" | ||
| 10 | #include "core/hle/service/time/ephemeral_network_system_clock_core.h" | ||
| 11 | #include "core/hle/service/time/standard_local_system_clock_core.h" | ||
| 12 | #include "core/hle/service/time/standard_network_system_clock_core.h" | ||
| 13 | #include "core/hle/service/time/standard_steady_clock_core.h" | ||
| 14 | #include "core/hle/service/time/standard_user_system_clock_core.h" | ||
| 15 | #include "core/hle/service/time/tick_based_steady_clock_core.h" | ||
| 16 | #include "core/hle/service/time/time_sharedmemory.h" | ||
| 17 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 18 | |||
| 19 | namespace Service::Time { | ||
| 20 | |||
| 21 | namespace Clock { | ||
| 22 | class EphemeralNetworkSystemClockContextWriter; | ||
| 23 | class LocalSystemClockContextWriter; | ||
| 24 | class NetworkSystemClockContextWriter; | ||
| 25 | } // namespace Clock | ||
| 26 | |||
| 27 | // Parts of this implementation were based on Ryujinx (https://github.com/Ryujinx/Ryujinx/pull/783). | ||
| 28 | // This code was released under public domain. | ||
| 29 | |||
| 30 | class TimeManager final { | ||
| 31 | public: | ||
| 32 | explicit TimeManager(Core::System& system); | ||
| 33 | ~TimeManager(); | ||
| 34 | |||
| 35 | Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() { | ||
| 36 | return standard_steady_clock_core; | ||
| 37 | } | ||
| 38 | |||
| 39 | const Clock::StandardSteadyClockCore& GetStandardSteadyClockCore() const { | ||
| 40 | return standard_steady_clock_core; | ||
| 41 | } | ||
| 42 | |||
| 43 | Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() { | ||
| 44 | return standard_local_system_clock_core; | ||
| 45 | } | ||
| 46 | |||
| 47 | const Clock::StandardLocalSystemClockCore& GetStandardLocalSystemClockCore() const { | ||
| 48 | return standard_local_system_clock_core; | ||
| 49 | } | ||
| 50 | |||
| 51 | Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() { | ||
| 52 | return standard_network_system_clock_core; | ||
| 53 | } | ||
| 54 | |||
| 55 | const Clock::StandardNetworkSystemClockCore& GetStandardNetworkSystemClockCore() const { | ||
| 56 | return standard_network_system_clock_core; | ||
| 57 | } | ||
| 58 | |||
| 59 | Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() { | ||
| 60 | return standard_user_system_clock_core; | ||
| 61 | } | ||
| 62 | |||
| 63 | const Clock::StandardUserSystemClockCore& GetStandardUserSystemClockCore() const { | ||
| 64 | return standard_user_system_clock_core; | ||
| 65 | } | ||
| 66 | |||
| 67 | TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() { | ||
| 68 | return time_zone_content_manager; | ||
| 69 | } | ||
| 70 | |||
| 71 | const TimeZone::TimeZoneContentManager& GetTimeZoneContentManager() const { | ||
| 72 | return time_zone_content_manager; | ||
| 73 | } | ||
| 74 | |||
| 75 | SharedMemory& GetSharedMemory() { | ||
| 76 | return shared_memory; | ||
| 77 | } | ||
| 78 | |||
| 79 | const SharedMemory& GetSharedMemory() const { | ||
| 80 | return shared_memory; | ||
| 81 | } | ||
| 82 | |||
| 83 | void SetupTimeZoneManager(std::string location_name, | ||
| 84 | Clock::SteadyClockTimePoint time_zone_updated_time_point, | ||
| 85 | std::size_t total_location_name_count, u128 time_zone_rule_version, | ||
| 86 | FileSys::VirtualFile& vfs_file); | ||
| 87 | |||
| 88 | private: | ||
| 89 | void SetupStandardSteadyClock(Core::System& system, Common::UUID clock_source_id, | ||
| 90 | Clock::TimeSpanType setup_value, | ||
| 91 | Clock::TimeSpanType internal_offset, bool is_rtc_reset_detected); | ||
| 92 | void SetupStandardLocalSystemClock(Core::System& system, | ||
| 93 | Clock::SystemClockContext clock_context, s64 posix_time); | ||
| 94 | void SetupStandardNetworkSystemClock(Clock::SystemClockContext clock_context, | ||
| 95 | Clock::TimeSpanType sufficient_accuracy); | ||
| 96 | void SetupStandardUserSystemClock(Core::System& system, bool is_automatic_correction_enabled, | ||
| 97 | Clock::SteadyClockTimePoint steady_clock_time_point); | ||
| 98 | void SetupEphemeralNetworkSystemClock(); | ||
| 99 | |||
| 100 | SharedMemory shared_memory; | ||
| 101 | |||
| 102 | Clock::StandardSteadyClockCore standard_steady_clock_core; | ||
| 103 | Clock::TickBasedSteadyClockCore tick_based_steady_clock_core; | ||
| 104 | Clock::StandardLocalSystemClockCore standard_local_system_clock_core; | ||
| 105 | Clock::StandardNetworkSystemClockCore standard_network_system_clock_core; | ||
| 106 | Clock::StandardUserSystemClockCore standard_user_system_clock_core; | ||
| 107 | Clock::EphemeralNetworkSystemClockCore ephemeral_network_system_clock_core; | ||
| 108 | |||
| 109 | std::shared_ptr<Clock::LocalSystemClockContextWriter> local_system_clock_context_writer; | ||
| 110 | std::shared_ptr<Clock::NetworkSystemClockContextWriter> network_system_clock_context_writer; | ||
| 111 | std::shared_ptr<Clock::EphemeralNetworkSystemClockContextWriter> | ||
| 112 | ephemeral_network_system_clock_context_writer; | ||
| 113 | |||
| 114 | TimeZone::TimeZoneContentManager time_zone_content_manager; | ||
| 115 | }; | ||
| 116 | |||
| 117 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_sharedmemory.cpp b/src/core/hle/service/time/time_sharedmemory.cpp index 4035f5072..9b03191bf 100644 --- a/src/core/hle/service/time/time_sharedmemory.cpp +++ b/src/core/hle/service/time/time_sharedmemory.cpp | |||
| @@ -3,20 +3,21 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/core.h" | 5 | #include "core/core.h" |
| 6 | #include "core/core_timing.h" | ||
| 7 | #include "core/core_timing_util.h" | ||
| 8 | #include "core/hle/service/time/clock_types.h" | ||
| 9 | #include "core/hle/service/time/steady_clock_core.h" | ||
| 6 | #include "core/hle/service/time/time_sharedmemory.h" | 10 | #include "core/hle/service/time/time_sharedmemory.h" |
| 7 | 11 | ||
| 8 | namespace Service::Time { | 12 | namespace Service::Time { |
| 9 | const std::size_t SHARED_MEMORY_SIZE = 0x1000; | 13 | |
| 14 | static constexpr std::size_t SHARED_MEMORY_SIZE{0x1000}; | ||
| 10 | 15 | ||
| 11 | SharedMemory::SharedMemory(Core::System& system) : system(system) { | 16 | SharedMemory::SharedMemory(Core::System& system) : system(system) { |
| 12 | shared_memory_holder = Kernel::SharedMemory::Create( | 17 | shared_memory_holder = Kernel::SharedMemory::Create( |
| 13 | system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, | 18 | system.Kernel(), nullptr, SHARED_MEMORY_SIZE, Kernel::MemoryPermission::ReadWrite, |
| 14 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory"); | 19 | Kernel::MemoryPermission::Read, 0, Kernel::MemoryRegion::BASE, "Time:SharedMemory"); |
| 15 | 20 | std::memset(shared_memory_holder->GetPointer(), 0, SHARED_MEMORY_SIZE); | |
| 16 | // Seems static from 1.0.0 -> 8.1.0. Specific games seem to check this value and crash | ||
| 17 | // if it's set to anything else | ||
| 18 | shared_memory_format.format_version = 14; | ||
| 19 | std::memcpy(shared_memory_holder->GetPointer(), &shared_memory_format, sizeof(Format)); | ||
| 20 | } | 21 | } |
| 21 | 22 | ||
| 22 | SharedMemory::~SharedMemory() = default; | 23 | SharedMemory::~SharedMemory() = default; |
| @@ -25,44 +26,32 @@ std::shared_ptr<Kernel::SharedMemory> SharedMemory::GetSharedMemoryHolder() cons | |||
| 25 | return shared_memory_holder; | 26 | return shared_memory_holder; |
| 26 | } | 27 | } |
| 27 | 28 | ||
| 28 | void SharedMemory::SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint) { | 29 | void SharedMemory::SetupStandardSteadyClock(Core::System& system, |
| 30 | const Common::UUID& clock_source_id, | ||
| 31 | Clock::TimeSpanType current_time_point) { | ||
| 32 | const Clock::TimeSpanType ticks_time_span{Clock::TimeSpanType::FromTicks( | ||
| 33 | Core::Timing::CpuCyclesToClockCycles(system.CoreTiming().GetTicks()), | ||
| 34 | Core::Timing::CNTFREQ)}; | ||
| 35 | const Clock::SteadyClockContext context{ | ||
| 36 | static_cast<u64>(current_time_point.nanoseconds - ticks_time_span.nanoseconds), | ||
| 37 | clock_source_id}; | ||
| 29 | shared_memory_format.standard_steady_clock_timepoint.StoreData( | 38 | shared_memory_format.standard_steady_clock_timepoint.StoreData( |
| 30 | shared_memory_holder->GetPointer(), timepoint); | 39 | shared_memory_holder->GetPointer(), context); |
| 31 | } | 40 | } |
| 32 | 41 | ||
| 33 | void SharedMemory::SetStandardLocalSystemClockContext(const SystemClockContext& context) { | 42 | void SharedMemory::UpdateLocalSystemClockContext(const Clock::SystemClockContext& context) { |
| 34 | shared_memory_format.standard_local_system_clock_context.StoreData( | 43 | shared_memory_format.standard_local_system_clock_context.StoreData( |
| 35 | shared_memory_holder->GetPointer(), context); | 44 | shared_memory_holder->GetPointer(), context); |
| 36 | } | 45 | } |
| 37 | 46 | ||
| 38 | void SharedMemory::SetStandardNetworkSystemClockContext(const SystemClockContext& context) { | 47 | void SharedMemory::UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context) { |
| 39 | shared_memory_format.standard_network_system_clock_context.StoreData( | 48 | shared_memory_format.standard_network_system_clock_context.StoreData( |
| 40 | shared_memory_holder->GetPointer(), context); | 49 | shared_memory_holder->GetPointer(), context); |
| 41 | } | 50 | } |
| 42 | 51 | ||
| 43 | void SharedMemory::SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled) { | 52 | void SharedMemory::SetAutomaticCorrectionEnabled(bool is_enabled) { |
| 44 | shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( | 53 | shared_memory_format.standard_user_system_clock_automatic_correction.StoreData( |
| 45 | shared_memory_holder->GetPointer(), enabled); | 54 | shared_memory_holder->GetPointer(), is_enabled); |
| 46 | } | ||
| 47 | |||
| 48 | SteadyClockTimePoint SharedMemory::GetStandardSteadyClockTimepoint() { | ||
| 49 | return shared_memory_format.standard_steady_clock_timepoint.ReadData( | ||
| 50 | shared_memory_holder->GetPointer()); | ||
| 51 | } | ||
| 52 | |||
| 53 | SystemClockContext SharedMemory::GetStandardLocalSystemClockContext() { | ||
| 54 | return shared_memory_format.standard_local_system_clock_context.ReadData( | ||
| 55 | shared_memory_holder->GetPointer()); | ||
| 56 | } | ||
| 57 | |||
| 58 | SystemClockContext SharedMemory::GetStandardNetworkSystemClockContext() { | ||
| 59 | return shared_memory_format.standard_network_system_clock_context.ReadData( | ||
| 60 | shared_memory_holder->GetPointer()); | ||
| 61 | } | ||
| 62 | |||
| 63 | bool SharedMemory::GetStandardUserSystemClockAutomaticCorrectionEnabled() { | ||
| 64 | return shared_memory_format.standard_user_system_clock_automatic_correction.ReadData( | ||
| 65 | shared_memory_holder->GetPointer()); | ||
| 66 | } | 55 | } |
| 67 | 56 | ||
| 68 | } // namespace Service::Time | 57 | } // namespace Service::Time |
diff --git a/src/core/hle/service/time/time_sharedmemory.h b/src/core/hle/service/time/time_sharedmemory.h index 904a96430..5976b2046 100644 --- a/src/core/hle/service/time/time_sharedmemory.h +++ b/src/core/hle/service/time/time_sharedmemory.h | |||
| @@ -5,11 +5,14 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/uuid.h" | ||
| 8 | #include "core/hle/kernel/shared_memory.h" | 9 | #include "core/hle/kernel/shared_memory.h" |
| 9 | #include "core/hle/service/time/time.h" | 10 | #include "core/hle/kernel/thread.h" |
| 11 | #include "core/hle/service/time/clock_types.h" | ||
| 10 | 12 | ||
| 11 | namespace Service::Time { | 13 | namespace Service::Time { |
| 12 | class SharedMemory { | 14 | |
| 15 | class SharedMemory final { | ||
| 13 | public: | 16 | public: |
| 14 | explicit SharedMemory(Core::System& system); | 17 | explicit SharedMemory(Core::System& system); |
| 15 | ~SharedMemory(); | 18 | ~SharedMemory(); |
| @@ -17,22 +20,10 @@ public: | |||
| 17 | // Return the shared memory handle | 20 | // Return the shared memory handle |
| 18 | std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const; | 21 | std::shared_ptr<Kernel::SharedMemory> GetSharedMemoryHolder() const; |
| 19 | 22 | ||
| 20 | // Set memory barriers in shared memory and update them | ||
| 21 | void SetStandardSteadyClockTimepoint(const SteadyClockTimePoint& timepoint); | ||
| 22 | void SetStandardLocalSystemClockContext(const SystemClockContext& context); | ||
| 23 | void SetStandardNetworkSystemClockContext(const SystemClockContext& context); | ||
| 24 | void SetStandardUserSystemClockAutomaticCorrectionEnabled(bool enabled); | ||
| 25 | |||
| 26 | // Pull from memory barriers in the shared memory | ||
| 27 | SteadyClockTimePoint GetStandardSteadyClockTimepoint(); | ||
| 28 | SystemClockContext GetStandardLocalSystemClockContext(); | ||
| 29 | SystemClockContext GetStandardNetworkSystemClockContext(); | ||
| 30 | bool GetStandardUserSystemClockAutomaticCorrectionEnabled(); | ||
| 31 | |||
| 32 | // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? | 23 | // TODO(ogniK): We have to properly simulate memory barriers, how are we going to do this? |
| 33 | template <typename T, std::size_t Offset> | 24 | template <typename T, std::size_t Offset> |
| 34 | struct MemoryBarrier { | 25 | struct MemoryBarrier { |
| 35 | static_assert(std::is_trivially_constructible_v<T>, "T must be trivially constructable"); | 26 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); |
| 36 | u32_le read_attempt{}; | 27 | u32_le read_attempt{}; |
| 37 | std::array<T, 2> data{}; | 28 | std::array<T, 2> data{}; |
| 38 | 29 | ||
| @@ -57,16 +48,22 @@ public: | |||
| 57 | 48 | ||
| 58 | // Shared memory format | 49 | // Shared memory format |
| 59 | struct Format { | 50 | struct Format { |
| 60 | MemoryBarrier<SteadyClockTimePoint, 0x0> standard_steady_clock_timepoint; | 51 | MemoryBarrier<Clock::SteadyClockContext, 0x0> standard_steady_clock_timepoint; |
| 61 | MemoryBarrier<SystemClockContext, 0x38> standard_local_system_clock_context; | 52 | MemoryBarrier<Clock::SystemClockContext, 0x38> standard_local_system_clock_context; |
| 62 | MemoryBarrier<SystemClockContext, 0x80> standard_network_system_clock_context; | 53 | MemoryBarrier<Clock::SystemClockContext, 0x80> standard_network_system_clock_context; |
| 63 | MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; | 54 | MemoryBarrier<bool, 0xc8> standard_user_system_clock_automatic_correction; |
| 64 | u32_le format_version; | 55 | u32_le format_version; |
| 65 | }; | 56 | }; |
| 66 | static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); | 57 | static_assert(sizeof(Format) == 0xd8, "Format is an invalid size"); |
| 67 | 58 | ||
| 59 | void SetupStandardSteadyClock(Core::System& system, const Common::UUID& clock_source_id, | ||
| 60 | Clock::TimeSpanType currentTimePoint); | ||
| 61 | void UpdateLocalSystemClockContext(const Clock::SystemClockContext& context); | ||
| 62 | void UpdateNetworkSystemClockContext(const Clock::SystemClockContext& context); | ||
| 63 | void SetAutomaticCorrectionEnabled(bool is_enabled); | ||
| 64 | |||
| 68 | private: | 65 | private: |
| 69 | std::shared_ptr<Kernel::SharedMemory> shared_memory_holder{}; | 66 | std::shared_ptr<Kernel::SharedMemory> shared_memory_holder; |
| 70 | Core::System& system; | 67 | Core::System& system; |
| 71 | Format shared_memory_format{}; | 68 | Format shared_memory_format{}; |
| 72 | }; | 69 | }; |
diff --git a/src/core/hle/service/time/time_zone_content_manager.cpp b/src/core/hle/service/time/time_zone_content_manager.cpp new file mode 100644 index 000000000..57b1a2bca --- /dev/null +++ b/src/core/hle/service/time/time_zone_content_manager.cpp | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <sstream> | ||
| 6 | |||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "core/core.h" | ||
| 9 | #include "core/file_sys/content_archive.h" | ||
| 10 | #include "core/file_sys/nca_metadata.h" | ||
| 11 | #include "core/file_sys/registered_cache.h" | ||
| 12 | #include "core/file_sys/romfs.h" | ||
| 13 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 14 | #include "core/hle/service/filesystem/filesystem.h" | ||
| 15 | #include "core/hle/service/time/time_manager.h" | ||
| 16 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 17 | |||
| 18 | namespace Service::Time::TimeZone { | ||
| 19 | |||
| 20 | constexpr u64 time_zone_binary_titleid{0x010000000000080E}; | ||
| 21 | |||
| 22 | static FileSys::VirtualDir GetTimeZoneBinary(Core::System& system) { | ||
| 23 | const auto* nand{system.GetFileSystemController().GetSystemNANDContents()}; | ||
| 24 | const auto nca{nand->GetEntry(time_zone_binary_titleid, FileSys::ContentRecordType::Data)}; | ||
| 25 | |||
| 26 | FileSys::VirtualFile romfs; | ||
| 27 | if (nca) { | ||
| 28 | romfs = nca->GetRomFS(); | ||
| 29 | } | ||
| 30 | |||
| 31 | if (!romfs) { | ||
| 32 | romfs = FileSys::SystemArchive::SynthesizeSystemArchive(time_zone_binary_titleid); | ||
| 33 | } | ||
| 34 | |||
| 35 | if (!romfs) { | ||
| 36 | LOG_ERROR(Service_Time, "Failed to find or synthesize {:016X!}", time_zone_binary_titleid); | ||
| 37 | return {}; | ||
| 38 | } | ||
| 39 | |||
| 40 | return FileSys::ExtractRomFS(romfs); | ||
| 41 | } | ||
| 42 | |||
| 43 | static std::vector<std::string> BuildLocationNameCache(Core::System& system) { | ||
| 44 | const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)}; | ||
| 45 | if (!extracted_romfs) { | ||
| 46 | LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid); | ||
| 47 | return {}; | ||
| 48 | } | ||
| 49 | |||
| 50 | const FileSys::VirtualFile binary_list{extracted_romfs->GetFile("binaryList.txt")}; | ||
| 51 | if (!binary_list) { | ||
| 52 | LOG_ERROR(Service_Time, "{:016X} has no file binaryList.txt!", time_zone_binary_titleid); | ||
| 53 | return {}; | ||
| 54 | } | ||
| 55 | |||
| 56 | std::vector<char> raw_data(binary_list->GetSize()); | ||
| 57 | binary_list->ReadBytes<char>(raw_data.data(), binary_list->GetSize()); | ||
| 58 | |||
| 59 | std::stringstream data_stream{raw_data.data()}; | ||
| 60 | std::string name; | ||
| 61 | std::vector<std::string> location_name_cache; | ||
| 62 | while (std::getline(data_stream, name)) { | ||
| 63 | name.pop_back(); // Remove carriage return | ||
| 64 | location_name_cache.emplace_back(std::move(name)); | ||
| 65 | } | ||
| 66 | return location_name_cache; | ||
| 67 | } | ||
| 68 | |||
| 69 | TimeZoneContentManager::TimeZoneContentManager(TimeManager& time_manager, Core::System& system) | ||
| 70 | : system{system}, location_name_cache{BuildLocationNameCache(system)} { | ||
| 71 | if (FileSys::VirtualFile vfs_file; GetTimeZoneInfoFile("GMT", vfs_file) == RESULT_SUCCESS) { | ||
| 72 | const auto time_point{ | ||
| 73 | time_manager.GetStandardSteadyClockCore().GetCurrentTimePoint(system)}; | ||
| 74 | time_manager.SetupTimeZoneManager("GMT", time_point, location_name_cache.size(), {}, | ||
| 75 | vfs_file); | ||
| 76 | } else { | ||
| 77 | time_zone_manager.MarkAsInitialized(); | ||
| 78 | } | ||
| 79 | } | ||
| 80 | |||
| 81 | ResultCode TimeZoneContentManager::LoadTimeZoneRule(TimeZoneRule& rules, | ||
| 82 | const std::string& location_name) const { | ||
| 83 | FileSys::VirtualFile vfs_file; | ||
| 84 | if (const ResultCode result{GetTimeZoneInfoFile(location_name, vfs_file)}; | ||
| 85 | result != RESULT_SUCCESS) { | ||
| 86 | return result; | ||
| 87 | } | ||
| 88 | |||
| 89 | return time_zone_manager.ParseTimeZoneRuleBinary(rules, vfs_file); | ||
| 90 | } | ||
| 91 | |||
| 92 | bool TimeZoneContentManager::IsLocationNameValid(const std::string& location_name) const { | ||
| 93 | return std::find(location_name_cache.begin(), location_name_cache.end(), location_name) != | ||
| 94 | location_name_cache.end(); | ||
| 95 | } | ||
| 96 | |||
| 97 | ResultCode TimeZoneContentManager::GetTimeZoneInfoFile(const std::string& location_name, | ||
| 98 | FileSys::VirtualFile& vfs_file) const { | ||
| 99 | if (!IsLocationNameValid(location_name)) { | ||
| 100 | return ERROR_TIME_NOT_FOUND; | ||
| 101 | } | ||
| 102 | |||
| 103 | const FileSys::VirtualDir extracted_romfs{GetTimeZoneBinary(system)}; | ||
| 104 | if (!extracted_romfs) { | ||
| 105 | LOG_ERROR(Service_Time, "Failed to extract RomFS for {:016X}!", time_zone_binary_titleid); | ||
| 106 | return ERROR_TIME_NOT_FOUND; | ||
| 107 | } | ||
| 108 | |||
| 109 | const FileSys::VirtualDir zoneinfo_dir{extracted_romfs->GetSubdirectory("zoneinfo")}; | ||
| 110 | if (!zoneinfo_dir) { | ||
| 111 | LOG_ERROR(Service_Time, "{:016X} has no directory zoneinfo!", time_zone_binary_titleid); | ||
| 112 | return ERROR_TIME_NOT_FOUND; | ||
| 113 | } | ||
| 114 | |||
| 115 | vfs_file = zoneinfo_dir->GetFile(location_name); | ||
| 116 | if (!vfs_file) { | ||
| 117 | LOG_ERROR(Service_Time, "{:016X} has no file \"{}\"!", time_zone_binary_titleid, | ||
| 118 | location_name); | ||
| 119 | return ERROR_TIME_NOT_FOUND; | ||
| 120 | } | ||
| 121 | |||
| 122 | return RESULT_SUCCESS; | ||
| 123 | } | ||
| 124 | |||
| 125 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_content_manager.h b/src/core/hle/service/time/time_zone_content_manager.h new file mode 100644 index 000000000..4f302c3b9 --- /dev/null +++ b/src/core/hle/service/time/time_zone_content_manager.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | #include <vector> | ||
| 9 | |||
| 10 | #include "core/hle/service/time/time_zone_manager.h" | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | class System; | ||
| 14 | } | ||
| 15 | |||
| 16 | namespace Service::Time { | ||
| 17 | class TimeManager; | ||
| 18 | } | ||
| 19 | |||
| 20 | namespace Service::Time::TimeZone { | ||
| 21 | |||
| 22 | class TimeZoneContentManager final { | ||
| 23 | public: | ||
| 24 | TimeZoneContentManager(TimeManager& time_manager, Core::System& system); | ||
| 25 | |||
| 26 | TimeZoneManager& GetTimeZoneManager() { | ||
| 27 | return time_zone_manager; | ||
| 28 | } | ||
| 29 | |||
| 30 | const TimeZoneManager& GetTimeZoneManager() const { | ||
| 31 | return time_zone_manager; | ||
| 32 | } | ||
| 33 | |||
| 34 | ResultCode LoadTimeZoneRule(TimeZoneRule& rules, const std::string& location_name) const; | ||
| 35 | |||
| 36 | private: | ||
| 37 | bool IsLocationNameValid(const std::string& location_name) const; | ||
| 38 | ResultCode GetTimeZoneInfoFile(const std::string& location_name, | ||
| 39 | FileSys::VirtualFile& vfs_file) const; | ||
| 40 | |||
| 41 | Core::System& system; | ||
| 42 | TimeZoneManager time_zone_manager; | ||
| 43 | const std::vector<std::string> location_name_cache; | ||
| 44 | }; | ||
| 45 | |||
| 46 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp new file mode 100644 index 000000000..717e81818 --- /dev/null +++ b/src/core/hle/service/time/time_zone_manager.cpp | |||
| @@ -0,0 +1,1030 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <climits> | ||
| 6 | |||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/file_sys/content_archive.h" | ||
| 10 | #include "core/file_sys/nca_metadata.h" | ||
| 11 | #include "core/file_sys/registered_cache.h" | ||
| 12 | #include "core/file_sys/romfs.h" | ||
| 13 | #include "core/file_sys/system_archive/system_archive.h" | ||
| 14 | #include "core/hle/service/time/time_zone_manager.h" | ||
| 15 | |||
| 16 | namespace Service::Time::TimeZone { | ||
| 17 | |||
| 18 | static constexpr s32 epoch_year{1970}; | ||
| 19 | static constexpr s32 year_base{1900}; | ||
| 20 | static constexpr s32 epoch_week_day{4}; | ||
| 21 | static constexpr s32 seconds_per_minute{60}; | ||
| 22 | static constexpr s32 minutes_per_hour{60}; | ||
| 23 | static constexpr s32 hours_per_day{24}; | ||
| 24 | static constexpr s32 days_per_week{7}; | ||
| 25 | static constexpr s32 days_per_normal_year{365}; | ||
| 26 | static constexpr s32 days_per_leap_year{366}; | ||
| 27 | static constexpr s32 months_per_year{12}; | ||
| 28 | static constexpr s32 seconds_per_hour{seconds_per_minute * minutes_per_hour}; | ||
| 29 | static constexpr s32 seconds_per_day{seconds_per_hour * hours_per_day}; | ||
| 30 | static constexpr s32 years_per_repeat{400}; | ||
| 31 | static constexpr s64 average_seconds_per_year{31556952}; | ||
| 32 | static constexpr s64 seconds_per_repeat{years_per_repeat * average_seconds_per_year}; | ||
| 33 | |||
| 34 | struct Rule { | ||
| 35 | enum class Type : u32 { JulianDay, DayOfYear, MonthNthDayOfWeek }; | ||
| 36 | Type rule_type{}; | ||
| 37 | s32 day{}; | ||
| 38 | s32 week{}; | ||
| 39 | s32 month{}; | ||
| 40 | s32 transition_time{}; | ||
| 41 | }; | ||
| 42 | |||
| 43 | struct CalendarTimeInternal { | ||
| 44 | s64 year{}; | ||
| 45 | s8 month{}; | ||
| 46 | s8 day{}; | ||
| 47 | s8 hour{}; | ||
| 48 | s8 minute{}; | ||
| 49 | s8 second{}; | ||
| 50 | int Compare(const CalendarTimeInternal& other) const { | ||
| 51 | if (year != other.year) { | ||
| 52 | if (year < other.year) { | ||
| 53 | return -1; | ||
| 54 | } | ||
| 55 | return 1; | ||
| 56 | } | ||
| 57 | if (month != other.month) { | ||
| 58 | return month - other.month; | ||
| 59 | } | ||
| 60 | if (day != other.day) { | ||
| 61 | return day - other.day; | ||
| 62 | } | ||
| 63 | if (hour != other.hour) { | ||
| 64 | return hour - other.hour; | ||
| 65 | } | ||
| 66 | if (minute != other.minute) { | ||
| 67 | return minute - other.minute; | ||
| 68 | } | ||
| 69 | if (second != other.second) { | ||
| 70 | return second - other.second; | ||
| 71 | } | ||
| 72 | return {}; | ||
| 73 | } | ||
| 74 | }; | ||
| 75 | |||
| 76 | template <typename TResult, typename TOperand> | ||
| 77 | static bool SafeAdd(TResult& result, TOperand op) { | ||
| 78 | result = result + op; | ||
| 79 | return true; | ||
| 80 | } | ||
| 81 | |||
| 82 | template <typename TResult, typename TUnit, typename TBase> | ||
| 83 | static bool SafeNormalize(TResult& result, TUnit& unit, TBase base) { | ||
| 84 | TUnit delta{}; | ||
| 85 | if (unit >= 0) { | ||
| 86 | delta = unit / base; | ||
| 87 | } else { | ||
| 88 | delta = -1 - (-1 - unit) / base; | ||
| 89 | } | ||
| 90 | unit -= delta * base; | ||
| 91 | return SafeAdd(result, delta); | ||
| 92 | } | ||
| 93 | |||
| 94 | template <typename T> | ||
| 95 | static constexpr bool IsLeapYear(T year) { | ||
| 96 | return ((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0); | ||
| 97 | } | ||
| 98 | |||
| 99 | template <typename T> | ||
| 100 | static constexpr T GetYearLengthInDays(T year) { | ||
| 101 | return IsLeapYear(year) ? days_per_leap_year : days_per_normal_year; | ||
| 102 | } | ||
| 103 | |||
| 104 | static constexpr s64 GetLeapDaysFromYearPositive(s64 year) { | ||
| 105 | return year / 4 - year / 100 + year / years_per_repeat; | ||
| 106 | } | ||
| 107 | |||
| 108 | static constexpr s64 GetLeapDaysFromYear(s64 year) { | ||
| 109 | if (year < 0) { | ||
| 110 | return -1 - GetLeapDaysFromYearPositive(-1 - year); | ||
| 111 | } else { | ||
| 112 | return GetLeapDaysFromYearPositive(year); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | static constexpr int GetMonthLength(bool is_leap_year, int month) { | ||
| 117 | constexpr std::array<int, 12> month_lengths{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | ||
| 118 | constexpr std::array<int, 12> month_lengths_leap{31, 29, 31, 30, 31, 30, | ||
| 119 | 31, 31, 30, 31, 30, 31}; | ||
| 120 | return is_leap_year ? month_lengths_leap[month] : month_lengths[month]; | ||
| 121 | } | ||
| 122 | |||
| 123 | static constexpr bool IsDigit(char value) { | ||
| 124 | return value >= '0' && value <= '9'; | ||
| 125 | } | ||
| 126 | |||
| 127 | static constexpr int GetQZName(const char* name, int offset, char delimiter) { | ||
| 128 | while (name[offset] != '\0' && name[offset] != delimiter) { | ||
| 129 | offset++; | ||
| 130 | } | ||
| 131 | return offset; | ||
| 132 | } | ||
| 133 | |||
| 134 | static constexpr int GetTZName(const char* name, int offset) { | ||
| 135 | for (char value{name[offset]}; | ||
| 136 | value != '\0' && !IsDigit(value) && value != ',' && value != '-' && value != '+'; | ||
| 137 | offset++) { | ||
| 138 | value = name[offset]; | ||
| 139 | } | ||
| 140 | return offset; | ||
| 141 | } | ||
| 142 | |||
| 143 | static constexpr bool GetInteger(const char* name, int& offset, int& value, int min, int max) { | ||
| 144 | value = 0; | ||
| 145 | char temp{name[offset]}; | ||
| 146 | if (!IsDigit(temp)) { | ||
| 147 | return {}; | ||
| 148 | } | ||
| 149 | do { | ||
| 150 | value = value * 10 + (temp - '0'); | ||
| 151 | if (value > max) { | ||
| 152 | return {}; | ||
| 153 | } | ||
| 154 | temp = name[offset]; | ||
| 155 | } while (IsDigit(temp)); | ||
| 156 | |||
| 157 | return value >= min; | ||
| 158 | } | ||
| 159 | |||
| 160 | static constexpr bool GetSeconds(const char* name, int& offset, int& seconds) { | ||
| 161 | seconds = 0; | ||
| 162 | int value{}; | ||
| 163 | if (!GetInteger(name, offset, value, 0, hours_per_day * days_per_week - 1)) { | ||
| 164 | return {}; | ||
| 165 | } | ||
| 166 | seconds = value * seconds_per_hour; | ||
| 167 | |||
| 168 | if (name[offset] == ':') { | ||
| 169 | offset++; | ||
| 170 | if (!GetInteger(name, offset, value, 0, minutes_per_hour - 1)) { | ||
| 171 | return {}; | ||
| 172 | } | ||
| 173 | seconds += value * seconds_per_minute; | ||
| 174 | if (name[offset] == ':') { | ||
| 175 | offset++; | ||
| 176 | if (!GetInteger(name, offset, value, 0, seconds_per_minute)) { | ||
| 177 | return {}; | ||
| 178 | } | ||
| 179 | seconds += value; | ||
| 180 | } | ||
| 181 | } | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | |||
| 185 | static constexpr bool GetOffset(const char* name, int& offset, int& value) { | ||
| 186 | bool is_negative{}; | ||
| 187 | if (name[offset] == '-') { | ||
| 188 | is_negative = true; | ||
| 189 | offset++; | ||
| 190 | } else if (name[offset] == '+') { | ||
| 191 | offset++; | ||
| 192 | } | ||
| 193 | if (!GetSeconds(name, offset, value)) { | ||
| 194 | return {}; | ||
| 195 | } | ||
| 196 | if (is_negative) { | ||
| 197 | value = -value; | ||
| 198 | } | ||
| 199 | return true; | ||
| 200 | } | ||
| 201 | |||
| 202 | static constexpr bool GetRule(const char* name, int& position, Rule& rule) { | ||
| 203 | bool is_valid{}; | ||
| 204 | if (name[position] == 'J') { | ||
| 205 | position++; | ||
| 206 | rule.rule_type = Rule::Type::JulianDay; | ||
| 207 | is_valid = GetInteger(name, position, rule.day, 1, days_per_normal_year); | ||
| 208 | } else if (name[position] == 'M') { | ||
| 209 | position++; | ||
| 210 | rule.rule_type = Rule::Type::MonthNthDayOfWeek; | ||
| 211 | is_valid = GetInteger(name, position, rule.month, 1, months_per_year); | ||
| 212 | if (!is_valid) { | ||
| 213 | return {}; | ||
| 214 | } | ||
| 215 | if (name[position++] != '.') { | ||
| 216 | return {}; | ||
| 217 | } | ||
| 218 | is_valid = GetInteger(name, position, rule.week, 1, 5); | ||
| 219 | if (!is_valid) { | ||
| 220 | return {}; | ||
| 221 | } | ||
| 222 | if (name[position++] != '.') { | ||
| 223 | return {}; | ||
| 224 | } | ||
| 225 | is_valid = GetInteger(name, position, rule.day, 0, days_per_week - 1); | ||
| 226 | } else if (isdigit(name[position])) { | ||
| 227 | rule.rule_type = Rule::Type::DayOfYear; | ||
| 228 | is_valid = GetInteger(name, position, rule.day, 0, days_per_leap_year - 1); | ||
| 229 | } else { | ||
| 230 | return {}; | ||
| 231 | } | ||
| 232 | if (!is_valid) { | ||
| 233 | return {}; | ||
| 234 | } | ||
| 235 | if (name[position] == '/') { | ||
| 236 | position++; | ||
| 237 | return GetOffset(name, position, rule.transition_time); | ||
| 238 | } else { | ||
| 239 | rule.transition_time = 2 * seconds_per_hour; | ||
| 240 | } | ||
| 241 | return true; | ||
| 242 | } | ||
| 243 | |||
| 244 | static constexpr int TransitionTime(int year, Rule rule, int offset) { | ||
| 245 | int value{}; | ||
| 246 | switch (rule.rule_type) { | ||
| 247 | case Rule::Type::JulianDay: | ||
| 248 | value = (rule.day - 1) * seconds_per_day; | ||
| 249 | if (IsLeapYear(year) && rule.day >= 60) { | ||
| 250 | value += seconds_per_day; | ||
| 251 | } | ||
| 252 | break; | ||
| 253 | case Rule::Type::DayOfYear: | ||
| 254 | value = rule.day * seconds_per_day; | ||
| 255 | break; | ||
| 256 | case Rule::Type::MonthNthDayOfWeek: { | ||
| 257 | // Use Zeller's Congruence (https://en.wikipedia.org/wiki/Zeller%27s_congruence) to | ||
| 258 | // calculate the day of the week for any Julian or Gregorian calendar date. | ||
| 259 | const int m1{(rule.month + 9) % 12 + 1}; | ||
| 260 | const int yy0{(rule.month <= 2) ? (year - 1) : year}; | ||
| 261 | const int yy1{yy0 / 100}; | ||
| 262 | const int yy2{yy0 % 100}; | ||
| 263 | int day_of_week{((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7}; | ||
| 264 | |||
| 265 | if (day_of_week < 0) { | ||
| 266 | day_of_week += days_per_week; | ||
| 267 | } | ||
| 268 | int day{rule.day - day_of_week}; | ||
| 269 | if (day < 0) { | ||
| 270 | day += days_per_week; | ||
| 271 | } | ||
| 272 | for (int i{1}; i < rule.week; i++) { | ||
| 273 | if (day + days_per_week >= GetMonthLength(IsLeapYear(year), rule.month - 1)) { | ||
| 274 | break; | ||
| 275 | } | ||
| 276 | day += days_per_week; | ||
| 277 | } | ||
| 278 | |||
| 279 | value = day * seconds_per_day; | ||
| 280 | for (int index{}; index < rule.month - 1; ++index) { | ||
| 281 | value += GetMonthLength(IsLeapYear(year), index) * seconds_per_day; | ||
| 282 | } | ||
| 283 | break; | ||
| 284 | } | ||
| 285 | default: | ||
| 286 | UNREACHABLE(); | ||
| 287 | } | ||
| 288 | return value + rule.transition_time + offset; | ||
| 289 | } | ||
| 290 | |||
| 291 | static bool ParsePosixName(const char* name, TimeZoneRule& rule) { | ||
| 292 | constexpr char default_rule[]{",M4.1.0,M10.5.0"}; | ||
| 293 | const char* std_name{name}; | ||
| 294 | int std_len{}; | ||
| 295 | int offset{}; | ||
| 296 | int std_offset{}; | ||
| 297 | |||
| 298 | if (name[offset] == '<') { | ||
| 299 | offset++; | ||
| 300 | std_name = name + offset; | ||
| 301 | const int std_name_offset{offset}; | ||
| 302 | offset = GetQZName(name, offset, '>'); | ||
| 303 | if (name[offset] != '>') { | ||
| 304 | return {}; | ||
| 305 | } | ||
| 306 | std_len = offset - std_name_offset; | ||
| 307 | offset++; | ||
| 308 | } else { | ||
| 309 | offset = GetTZName(name, offset); | ||
| 310 | std_len = offset; | ||
| 311 | } | ||
| 312 | if (!std_len) { | ||
| 313 | return {}; | ||
| 314 | } | ||
| 315 | if (!GetOffset(name, offset, std_offset)) { | ||
| 316 | return {}; | ||
| 317 | } | ||
| 318 | |||
| 319 | int char_count{std_len + 1}; | ||
| 320 | int dest_len{}; | ||
| 321 | int dest_offset{}; | ||
| 322 | const char* dest_name{name + offset}; | ||
| 323 | if (rule.chars.size() < char_count) { | ||
| 324 | return {}; | ||
| 325 | } | ||
| 326 | |||
| 327 | if (name[offset] != '\0') { | ||
| 328 | if (name[offset] == '<') { | ||
| 329 | dest_name = name + (++offset); | ||
| 330 | const int dest_name_offset{offset}; | ||
| 331 | offset = GetQZName(name, offset, '>'); | ||
| 332 | if (name[offset] != '>') { | ||
| 333 | return {}; | ||
| 334 | } | ||
| 335 | dest_len = offset - dest_name_offset; | ||
| 336 | offset++; | ||
| 337 | } else { | ||
| 338 | dest_name = name + (offset); | ||
| 339 | offset = GetTZName(name, offset); | ||
| 340 | dest_len = offset; | ||
| 341 | } | ||
| 342 | if (dest_len == 0) { | ||
| 343 | return {}; | ||
| 344 | } | ||
| 345 | char_count += dest_len + 1; | ||
| 346 | if (rule.chars.size() < char_count) { | ||
| 347 | return {}; | ||
| 348 | } | ||
| 349 | if (name[offset] != '\0' && name[offset] != ',' && name[offset] != ';') { | ||
| 350 | if (!GetOffset(name, offset, dest_offset)) { | ||
| 351 | return {}; | ||
| 352 | } | ||
| 353 | } else { | ||
| 354 | dest_offset = std_offset - seconds_per_hour; | ||
| 355 | } | ||
| 356 | if (name[offset] == '\0') { | ||
| 357 | name = default_rule; | ||
| 358 | offset = 0; | ||
| 359 | } | ||
| 360 | if (name[offset] == ',' || name[offset] == ';') { | ||
| 361 | offset++; | ||
| 362 | |||
| 363 | Rule start{}; | ||
| 364 | if (!GetRule(name, offset, start)) { | ||
| 365 | return {}; | ||
| 366 | } | ||
| 367 | if (name[offset++] != ',') { | ||
| 368 | return {}; | ||
| 369 | } | ||
| 370 | |||
| 371 | Rule end{}; | ||
| 372 | if (!GetRule(name, offset, end)) { | ||
| 373 | return {}; | ||
| 374 | } | ||
| 375 | if (name[offset] != '\0') { | ||
| 376 | return {}; | ||
| 377 | } | ||
| 378 | |||
| 379 | rule.type_count = 2; | ||
| 380 | rule.ttis[0].gmt_offset = -dest_offset; | ||
| 381 | rule.ttis[0].is_dst = true; | ||
| 382 | rule.ttis[0].abbreviation_list_index = std_len + 1; | ||
| 383 | rule.ttis[1].gmt_offset = -std_offset; | ||
| 384 | rule.ttis[1].is_dst = false; | ||
| 385 | rule.ttis[1].abbreviation_list_index = 0; | ||
| 386 | rule.default_type = 0; | ||
| 387 | |||
| 388 | s64 jan_first{}; | ||
| 389 | int time_count{}; | ||
| 390 | int jan_offset{}; | ||
| 391 | int year_beginning{epoch_year}; | ||
| 392 | do { | ||
| 393 | const int year_seconds{GetYearLengthInDays(year_beginning - 1) * seconds_per_day}; | ||
| 394 | year_beginning--; | ||
| 395 | if (!SafeAdd(jan_first, -year_seconds)) { | ||
| 396 | jan_offset = -year_seconds; | ||
| 397 | break; | ||
| 398 | } | ||
| 399 | } while (epoch_year - years_per_repeat / 2 < year_beginning); | ||
| 400 | |||
| 401 | int year_limit{year_beginning + years_per_repeat + 1}; | ||
| 402 | int year{}; | ||
| 403 | for (year = year_beginning; year < year_limit; year++) { | ||
| 404 | int start_time{TransitionTime(year, start, std_offset)}; | ||
| 405 | int end_time{TransitionTime(year, end, dest_offset)}; | ||
| 406 | const int year_seconds{GetYearLengthInDays(year) * seconds_per_day}; | ||
| 407 | const bool is_reversed{end_time < start_time}; | ||
| 408 | if (is_reversed) { | ||
| 409 | int swap{start_time}; | ||
| 410 | start_time = end_time; | ||
| 411 | end_time = swap; | ||
| 412 | } | ||
| 413 | |||
| 414 | if (is_reversed || | ||
| 415 | (start_time < end_time && | ||
| 416 | (end_time - start_time < (year_seconds + (std_offset - dest_offset))))) { | ||
| 417 | if (rule.ats.size() - 2 < time_count) { | ||
| 418 | break; | ||
| 419 | } | ||
| 420 | |||
| 421 | rule.ats[time_count] = jan_first; | ||
| 422 | if (SafeAdd(rule.ats[time_count], jan_offset + start_time)) { | ||
| 423 | rule.types[time_count++] = is_reversed ? 1 : 0; | ||
| 424 | } else if (jan_offset != 0) { | ||
| 425 | rule.default_type = is_reversed ? 1 : 0; | ||
| 426 | } | ||
| 427 | |||
| 428 | rule.ats[time_count] = jan_first; | ||
| 429 | if (SafeAdd(rule.ats[time_count], jan_offset + end_time)) { | ||
| 430 | rule.types[time_count++] = is_reversed ? 0 : 1; | ||
| 431 | year_limit = year + years_per_repeat + 1; | ||
| 432 | } else if (jan_offset != 0) { | ||
| 433 | rule.default_type = is_reversed ? 0 : 1; | ||
| 434 | } | ||
| 435 | } | ||
| 436 | if (!SafeAdd(jan_first, jan_offset + year_seconds)) { | ||
| 437 | break; | ||
| 438 | } | ||
| 439 | jan_offset = 0; | ||
| 440 | } | ||
| 441 | rule.time_count = time_count; | ||
| 442 | if (time_count == 0) { | ||
| 443 | rule.type_count = 1; | ||
| 444 | } else if (years_per_repeat < year - year_beginning) { | ||
| 445 | rule.go_back = true; | ||
| 446 | rule.go_ahead = true; | ||
| 447 | } | ||
| 448 | } else { | ||
| 449 | if (name[offset] == '\0') { | ||
| 450 | return {}; | ||
| 451 | } | ||
| 452 | |||
| 453 | s64 their_std_offset{}; | ||
| 454 | for (int index{}; index < rule.time_count; ++index) { | ||
| 455 | const s8 type{rule.types[index]}; | ||
| 456 | if (rule.ttis[type].is_standard_time_daylight) { | ||
| 457 | their_std_offset = -rule.ttis[type].gmt_offset; | ||
| 458 | } | ||
| 459 | } | ||
| 460 | |||
| 461 | s64 their_offset{their_std_offset}; | ||
| 462 | for (int index{}; index < rule.time_count; ++index) { | ||
| 463 | const s8 type{rule.types[index]}; | ||
| 464 | rule.types[index] = rule.ttis[type].is_dst ? 1 : 0; | ||
| 465 | if (!rule.ttis[type].is_gmt) { | ||
| 466 | if (!rule.ttis[type].is_standard_time_daylight) { | ||
| 467 | rule.ats[index] += dest_offset - their_std_offset; | ||
| 468 | } else { | ||
| 469 | rule.ats[index] += std_offset - their_std_offset; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | their_offset = -rule.ttis[type].gmt_offset; | ||
| 473 | if (!rule.ttis[type].is_dst) { | ||
| 474 | their_std_offset = their_offset; | ||
| 475 | } | ||
| 476 | } | ||
| 477 | rule.ttis[0].gmt_offset = -std_offset; | ||
| 478 | rule.ttis[0].is_dst = false; | ||
| 479 | rule.ttis[0].abbreviation_list_index = 0; | ||
| 480 | rule.ttis[1].gmt_offset = -dest_offset; | ||
| 481 | rule.ttis[1].is_dst = true; | ||
| 482 | rule.ttis[1].abbreviation_list_index = std_len + 1; | ||
| 483 | rule.type_count = 2; | ||
| 484 | rule.default_type = 0; | ||
| 485 | } | ||
| 486 | } else { | ||
| 487 | // Default is standard time | ||
| 488 | rule.type_count = 1; | ||
| 489 | rule.time_count = 0; | ||
| 490 | rule.default_type = 0; | ||
| 491 | rule.ttis[0].gmt_offset = -std_offset; | ||
| 492 | rule.ttis[0].is_dst = false; | ||
| 493 | rule.ttis[0].abbreviation_list_index = 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | rule.char_count = char_count; | ||
| 497 | for (int index{}; index < std_len; ++index) { | ||
| 498 | rule.chars[index] = std_name[index]; | ||
| 499 | } | ||
| 500 | |||
| 501 | rule.chars[std_len++] = '\0'; | ||
| 502 | if (dest_len != 0) { | ||
| 503 | for (int index{}; index < dest_len; ++index) { | ||
| 504 | rule.chars[std_len + index] = dest_name[index]; | ||
| 505 | } | ||
| 506 | rule.chars[std_len + dest_len] = '\0'; | ||
| 507 | } | ||
| 508 | |||
| 509 | return true; | ||
| 510 | } | ||
| 511 | |||
| 512 | static bool ParseTimeZoneBinary(TimeZoneRule& time_zone_rule, FileSys::VirtualFile& vfs_file) { | ||
| 513 | TzifHeader header{}; | ||
| 514 | if (vfs_file->ReadObject<TzifHeader>(&header) != sizeof(TzifHeader)) { | ||
| 515 | return {}; | ||
| 516 | } | ||
| 517 | |||
| 518 | constexpr s32 time_zone_max_leaps{50}; | ||
| 519 | constexpr s32 time_zone_max_chars{50}; | ||
| 520 | if (!(0 <= header.leap_count && header.leap_count < time_zone_max_leaps && | ||
| 521 | 0 < header.type_count && header.type_count < time_zone_rule.ttis.size() && | ||
| 522 | 0 <= header.time_count && header.time_count < time_zone_rule.ats.size() && | ||
| 523 | 0 <= header.char_count && header.char_count < time_zone_max_chars && | ||
| 524 | (header.ttis_std_count == header.type_count || header.ttis_std_count == 0) && | ||
| 525 | (header.ttis_gmt_count == header.type_count || header.ttis_gmt_count == 0))) { | ||
| 526 | return {}; | ||
| 527 | } | ||
| 528 | time_zone_rule.time_count = header.time_count; | ||
| 529 | time_zone_rule.type_count = header.type_count; | ||
| 530 | time_zone_rule.char_count = header.char_count; | ||
| 531 | |||
| 532 | int time_count{}; | ||
| 533 | u64 read_offset = sizeof(TzifHeader); | ||
| 534 | for (int index{}; index < time_zone_rule.time_count; ++index) { | ||
| 535 | s64_be at{}; | ||
| 536 | vfs_file->ReadObject<s64_be>(&at, read_offset); | ||
| 537 | time_zone_rule.types[index] = 1; | ||
| 538 | if (time_count != 0 && at <= time_zone_rule.ats[time_count - 1]) { | ||
| 539 | if (at < time_zone_rule.ats[time_count - 1]) { | ||
| 540 | return {}; | ||
| 541 | } | ||
| 542 | time_zone_rule.types[index - 1] = 0; | ||
| 543 | time_count--; | ||
| 544 | } | ||
| 545 | time_zone_rule.ats[time_count++] = at; | ||
| 546 | read_offset += sizeof(s64_be); | ||
| 547 | } | ||
| 548 | time_count = 0; | ||
| 549 | for (int index{}; index < time_zone_rule.time_count; ++index) { | ||
| 550 | const u8 type{*vfs_file->ReadByte(read_offset)}; | ||
| 551 | read_offset += sizeof(u8); | ||
| 552 | if (time_zone_rule.time_count <= type) { | ||
| 553 | return {}; | ||
| 554 | } | ||
| 555 | if (time_zone_rule.types[index] != 0) { | ||
| 556 | time_zone_rule.types[time_count++] = type; | ||
| 557 | } | ||
| 558 | } | ||
| 559 | time_zone_rule.time_count = time_count; | ||
| 560 | for (int index{}; index < time_zone_rule.type_count; ++index) { | ||
| 561 | TimeTypeInfo& ttis{time_zone_rule.ttis[index]}; | ||
| 562 | u32_be gmt_offset{}; | ||
| 563 | vfs_file->ReadObject<u32_be>(&gmt_offset, read_offset); | ||
| 564 | read_offset += sizeof(u32_be); | ||
| 565 | ttis.gmt_offset = gmt_offset; | ||
| 566 | |||
| 567 | const u8 dst{*vfs_file->ReadByte(read_offset)}; | ||
| 568 | read_offset += sizeof(u8); | ||
| 569 | if (dst >= 2) { | ||
| 570 | return {}; | ||
| 571 | } | ||
| 572 | ttis.is_dst = dst != 0; | ||
| 573 | |||
| 574 | const s32 abbreviation_list_index{*vfs_file->ReadByte(read_offset)}; | ||
| 575 | read_offset += sizeof(u8); | ||
| 576 | if (abbreviation_list_index >= time_zone_rule.char_count) { | ||
| 577 | return {}; | ||
| 578 | } | ||
| 579 | ttis.abbreviation_list_index = abbreviation_list_index; | ||
| 580 | } | ||
| 581 | |||
| 582 | vfs_file->ReadArray(time_zone_rule.chars.data(), time_zone_rule.char_count, read_offset); | ||
| 583 | time_zone_rule.chars[time_zone_rule.char_count] = '\0'; | ||
| 584 | read_offset += time_zone_rule.char_count; | ||
| 585 | for (int index{}; index < time_zone_rule.type_count; ++index) { | ||
| 586 | if (header.ttis_std_count == 0) { | ||
| 587 | time_zone_rule.ttis[index].is_standard_time_daylight = false; | ||
| 588 | } else { | ||
| 589 | const u8 dst{*vfs_file->ReadByte(read_offset)}; | ||
| 590 | read_offset += sizeof(u8); | ||
| 591 | if (dst >= 2) { | ||
| 592 | return {}; | ||
| 593 | } | ||
| 594 | time_zone_rule.ttis[index].is_standard_time_daylight = dst != 0; | ||
| 595 | } | ||
| 596 | } | ||
| 597 | |||
| 598 | for (int index{}; index < time_zone_rule.type_count; ++index) { | ||
| 599 | if (header.ttis_std_count == 0) { | ||
| 600 | time_zone_rule.ttis[index].is_gmt = false; | ||
| 601 | } else { | ||
| 602 | const u8 dst{*vfs_file->ReadByte(read_offset)}; | ||
| 603 | read_offset += sizeof(u8); | ||
| 604 | if (dst >= 2) { | ||
| 605 | return {}; | ||
| 606 | } | ||
| 607 | time_zone_rule.ttis[index].is_gmt = dst != 0; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | |||
| 611 | const u64 position{(read_offset - sizeof(TzifHeader))}; | ||
| 612 | const std::size_t bytes_read{vfs_file->GetSize() - sizeof(TzifHeader) - position}; | ||
| 613 | if (bytes_read < 0) { | ||
| 614 | return {}; | ||
| 615 | } | ||
| 616 | constexpr s32 time_zone_name_max{255}; | ||
| 617 | if (bytes_read > (time_zone_name_max + 1)) { | ||
| 618 | return {}; | ||
| 619 | } | ||
| 620 | |||
| 621 | std::array<char, time_zone_name_max + 1> temp_name{}; | ||
| 622 | vfs_file->ReadArray(temp_name.data(), bytes_read, read_offset); | ||
| 623 | if (bytes_read > 2 && temp_name[0] == '\n' && temp_name[bytes_read - 1] == '\n' && | ||
| 624 | time_zone_rule.type_count + 2 <= time_zone_rule.ttis.size()) { | ||
| 625 | temp_name[bytes_read - 1] = '\0'; | ||
| 626 | |||
| 627 | std::array<char, time_zone_name_max> name{}; | ||
| 628 | std::memcpy(name.data(), temp_name.data() + 1, bytes_read - 1); | ||
| 629 | |||
| 630 | TimeZoneRule temp_rule; | ||
| 631 | if (ParsePosixName(name.data(), temp_rule)) { | ||
| 632 | UNIMPLEMENTED(); | ||
| 633 | } | ||
| 634 | } | ||
| 635 | if (time_zone_rule.type_count == 0) { | ||
| 636 | return {}; | ||
| 637 | } | ||
| 638 | if (time_zone_rule.time_count > 1) { | ||
| 639 | UNIMPLEMENTED(); | ||
| 640 | } | ||
| 641 | |||
| 642 | s32 default_type{}; | ||
| 643 | |||
| 644 | for (default_type = 0; default_type < time_zone_rule.time_count; default_type++) { | ||
| 645 | if (time_zone_rule.types[default_type] == 0) { | ||
| 646 | break; | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 650 | default_type = default_type < time_zone_rule.time_count ? -1 : 0; | ||
| 651 | if (default_type < 0 && time_zone_rule.time_count > 0 && | ||
| 652 | time_zone_rule.ttis[time_zone_rule.types[0]].is_dst) { | ||
| 653 | default_type = time_zone_rule.types[0]; | ||
| 654 | while (--default_type >= 0) { | ||
| 655 | if (!time_zone_rule.ttis[default_type].is_dst) { | ||
| 656 | break; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | } | ||
| 660 | if (default_type < 0) { | ||
| 661 | default_type = 0; | ||
| 662 | while (time_zone_rule.ttis[default_type].is_dst) { | ||
| 663 | if (++default_type >= time_zone_rule.type_count) { | ||
| 664 | default_type = 0; | ||
| 665 | break; | ||
| 666 | } | ||
| 667 | } | ||
| 668 | } | ||
| 669 | time_zone_rule.default_type = default_type; | ||
| 670 | return true; | ||
| 671 | } | ||
| 672 | |||
| 673 | static ResultCode CreateCalendarTime(s64 time, int gmt_offset, CalendarTimeInternal& calendar_time, | ||
| 674 | CalendarAdditionalInfo& calendar_additional_info) { | ||
| 675 | s64 year{epoch_year}; | ||
| 676 | s64 time_days{time / seconds_per_day}; | ||
| 677 | s64 remaining_seconds{time % seconds_per_day}; | ||
| 678 | while (time_days < 0 || time_days >= GetYearLengthInDays(year)) { | ||
| 679 | s64 delta = time_days / days_per_leap_year; | ||
| 680 | if (!delta) { | ||
| 681 | delta = time_days < 0 ? -1 : 1; | ||
| 682 | } | ||
| 683 | s64 new_year{year}; | ||
| 684 | if (!SafeAdd(new_year, delta)) { | ||
| 685 | return ERROR_OUT_OF_RANGE; | ||
| 686 | } | ||
| 687 | time_days -= (new_year - year) * days_per_normal_year; | ||
| 688 | time_days -= GetLeapDaysFromYear(new_year - 1) - GetLeapDaysFromYear(year - 1); | ||
| 689 | year = new_year; | ||
| 690 | } | ||
| 691 | |||
| 692 | s64 day_of_year{time_days}; | ||
| 693 | remaining_seconds += gmt_offset; | ||
| 694 | while (remaining_seconds < 0) { | ||
| 695 | remaining_seconds += seconds_per_day; | ||
| 696 | day_of_year--; | ||
| 697 | } | ||
| 698 | |||
| 699 | while (remaining_seconds >= seconds_per_day) { | ||
| 700 | remaining_seconds -= seconds_per_day; | ||
| 701 | day_of_year++; | ||
| 702 | } | ||
| 703 | |||
| 704 | while (day_of_year < 0) { | ||
| 705 | if (!SafeAdd(year, -1)) { | ||
| 706 | return ERROR_OUT_OF_RANGE; | ||
| 707 | } | ||
| 708 | day_of_year += GetYearLengthInDays(year); | ||
| 709 | } | ||
| 710 | |||
| 711 | while (day_of_year >= GetYearLengthInDays(year)) { | ||
| 712 | day_of_year -= GetYearLengthInDays(year); | ||
| 713 | if (!SafeAdd(year, 1)) { | ||
| 714 | return ERROR_OUT_OF_RANGE; | ||
| 715 | } | ||
| 716 | } | ||
| 717 | |||
| 718 | calendar_time.year = year; | ||
| 719 | calendar_additional_info.day_of_year = static_cast<u32>(day_of_year); | ||
| 720 | s64 day_of_week{ | ||
| 721 | (epoch_week_day + | ||
| 722 | ((year - epoch_year) % days_per_week) * (days_per_normal_year % days_per_week) + | ||
| 723 | GetLeapDaysFromYear(year - 1) - GetLeapDaysFromYear(epoch_year - 1) + day_of_year) % | ||
| 724 | days_per_week}; | ||
| 725 | if (day_of_week < 0) { | ||
| 726 | day_of_week += days_per_week; | ||
| 727 | } | ||
| 728 | |||
| 729 | calendar_additional_info.day_of_week = static_cast<u32>(day_of_week); | ||
| 730 | calendar_time.hour = static_cast<s8>((remaining_seconds / seconds_per_hour) % seconds_per_hour); | ||
| 731 | remaining_seconds %= seconds_per_hour; | ||
| 732 | calendar_time.minute = static_cast<s8>(remaining_seconds / seconds_per_minute); | ||
| 733 | calendar_time.second = static_cast<s8>(remaining_seconds % seconds_per_minute); | ||
| 734 | |||
| 735 | for (calendar_time.month = 0; | ||
| 736 | day_of_year >= GetMonthLength(IsLeapYear(year), calendar_time.month); | ||
| 737 | ++calendar_time.month) { | ||
| 738 | day_of_year -= GetMonthLength(IsLeapYear(year), calendar_time.month); | ||
| 739 | } | ||
| 740 | |||
| 741 | calendar_time.day = static_cast<s8>(day_of_year + 1); | ||
| 742 | calendar_additional_info.is_dst = false; | ||
| 743 | calendar_additional_info.gmt_offset = gmt_offset; | ||
| 744 | |||
| 745 | return RESULT_SUCCESS; | ||
| 746 | } | ||
| 747 | |||
| 748 | static ResultCode ToCalendarTimeInternal(const TimeZoneRule& rules, s64 time, | ||
| 749 | CalendarTimeInternal& calendar_time, | ||
| 750 | CalendarAdditionalInfo& calendar_additional_info) { | ||
| 751 | if ((rules.go_ahead && time < rules.ats[0]) || | ||
| 752 | (rules.go_back && time > rules.ats[rules.time_count - 1])) { | ||
| 753 | s64 seconds{}; | ||
| 754 | if (time < rules.ats[0]) { | ||
| 755 | seconds = rules.ats[0] - time; | ||
| 756 | } else { | ||
| 757 | seconds = time - rules.ats[rules.time_count - 1]; | ||
| 758 | } | ||
| 759 | seconds--; | ||
| 760 | |||
| 761 | const s64 years{(seconds / seconds_per_repeat + 1) * years_per_repeat}; | ||
| 762 | seconds = years * average_seconds_per_year; | ||
| 763 | |||
| 764 | s64 new_time{time}; | ||
| 765 | if (time < rules.ats[0]) { | ||
| 766 | new_time += seconds; | ||
| 767 | } else { | ||
| 768 | new_time -= seconds; | ||
| 769 | } | ||
| 770 | if (new_time < rules.ats[0] && new_time > rules.ats[rules.time_count - 1]) { | ||
| 771 | return ERROR_TIME_NOT_FOUND; | ||
| 772 | } | ||
| 773 | if (const ResultCode result{ | ||
| 774 | ToCalendarTimeInternal(rules, new_time, calendar_time, calendar_additional_info)}; | ||
| 775 | result != RESULT_SUCCESS) { | ||
| 776 | return result; | ||
| 777 | } | ||
| 778 | if (time < rules.ats[0]) { | ||
| 779 | calendar_time.year -= years; | ||
| 780 | } else { | ||
| 781 | calendar_time.year += years; | ||
| 782 | } | ||
| 783 | |||
| 784 | return RESULT_SUCCESS; | ||
| 785 | } | ||
| 786 | |||
| 787 | s32 tti_index{}; | ||
| 788 | if (rules.time_count == 0 || time < rules.ats[0]) { | ||
| 789 | tti_index = rules.default_type; | ||
| 790 | } else { | ||
| 791 | s32 low{1}; | ||
| 792 | s32 high{rules.time_count}; | ||
| 793 | while (low < high) { | ||
| 794 | s32 mid{(low + high) >> 1}; | ||
| 795 | if (time < rules.ats[mid]) { | ||
| 796 | high = mid; | ||
| 797 | } else { | ||
| 798 | low = mid + 1; | ||
| 799 | } | ||
| 800 | } | ||
| 801 | tti_index = rules.types[low - 1]; | ||
| 802 | } | ||
| 803 | |||
| 804 | if (const ResultCode result{CreateCalendarTime(time, rules.ttis[tti_index].gmt_offset, | ||
| 805 | calendar_time, calendar_additional_info)}; | ||
| 806 | result != RESULT_SUCCESS) { | ||
| 807 | return result; | ||
| 808 | } | ||
| 809 | |||
| 810 | calendar_additional_info.is_dst = rules.ttis[tti_index].is_dst; | ||
| 811 | const char* time_zone{&rules.chars[rules.ttis[tti_index].abbreviation_list_index]}; | ||
| 812 | for (int index{}; time_zone[index] != '\0'; ++index) { | ||
| 813 | calendar_additional_info.timezone_name[index] = time_zone[index]; | ||
| 814 | } | ||
| 815 | return RESULT_SUCCESS; | ||
| 816 | } | ||
| 817 | |||
| 818 | static ResultCode ToCalendarTimeImpl(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) { | ||
| 819 | CalendarTimeInternal calendar_time{}; | ||
| 820 | const ResultCode result{ | ||
| 821 | ToCalendarTimeInternal(rules, time, calendar_time, calendar.additiona_info)}; | ||
| 822 | calendar.time.year = static_cast<s16>(calendar_time.year); | ||
| 823 | calendar.time.month = calendar_time.month + 1; // Internal impl. uses 0-indexed month | ||
| 824 | calendar.time.day = calendar_time.day; | ||
| 825 | calendar.time.hour = calendar_time.hour; | ||
| 826 | calendar.time.minute = calendar_time.minute; | ||
| 827 | calendar.time.second = calendar_time.second; | ||
| 828 | return result; | ||
| 829 | } | ||
| 830 | |||
| 831 | TimeZoneManager::TimeZoneManager() = default; | ||
| 832 | TimeZoneManager::~TimeZoneManager() = default; | ||
| 833 | |||
| 834 | ResultCode TimeZoneManager::ToCalendarTime(const TimeZoneRule& rules, s64 time, | ||
| 835 | CalendarInfo& calendar) const { | ||
| 836 | return ToCalendarTimeImpl(rules, time, calendar); | ||
| 837 | } | ||
| 838 | |||
| 839 | ResultCode TimeZoneManager::SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name, | ||
| 840 | FileSys::VirtualFile& vfs_file) { | ||
| 841 | TimeZoneRule rule{}; | ||
| 842 | if (ParseTimeZoneBinary(rule, vfs_file)) { | ||
| 843 | device_location_name = location_name; | ||
| 844 | time_zone_rule = rule; | ||
| 845 | return RESULT_SUCCESS; | ||
| 846 | } | ||
| 847 | return ERROR_TIME_ZONE_CONVERSION_FAILED; | ||
| 848 | } | ||
| 849 | |||
| 850 | ResultCode TimeZoneManager::SetUpdatedTime(const Clock::SteadyClockTimePoint& value) { | ||
| 851 | time_zone_update_time_point = value; | ||
| 852 | return RESULT_SUCCESS; | ||
| 853 | } | ||
| 854 | |||
| 855 | ResultCode TimeZoneManager::ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const { | ||
| 856 | if (is_initialized) { | ||
| 857 | return ToCalendarTime(time_zone_rule, time, calendar); | ||
| 858 | } else { | ||
| 859 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 863 | ResultCode TimeZoneManager::ParseTimeZoneRuleBinary(TimeZoneRule& rules, | ||
| 864 | FileSys::VirtualFile& vfs_file) const { | ||
| 865 | if (!ParseTimeZoneBinary(rules, vfs_file)) { | ||
| 866 | return ERROR_TIME_ZONE_CONVERSION_FAILED; | ||
| 867 | } | ||
| 868 | return RESULT_SUCCESS; | ||
| 869 | } | ||
| 870 | |||
| 871 | ResultCode TimeZoneManager::ToPosixTime(const TimeZoneRule& rules, | ||
| 872 | const CalendarTime& calendar_time, s64& posix_time) const { | ||
| 873 | posix_time = 0; | ||
| 874 | |||
| 875 | CalendarTimeInternal internal_time{}; | ||
| 876 | internal_time.year = calendar_time.year; | ||
| 877 | internal_time.month = calendar_time.month - 1; // Internal impl. uses 0-indexed month | ||
| 878 | internal_time.day = calendar_time.day; | ||
| 879 | internal_time.hour = calendar_time.hour; | ||
| 880 | internal_time.minute = calendar_time.minute; | ||
| 881 | internal_time.second = calendar_time.second; | ||
| 882 | |||
| 883 | s32 hour{internal_time.hour}; | ||
| 884 | s32 minute{internal_time.minute}; | ||
| 885 | if (!SafeNormalize(hour, minute, minutes_per_hour)) { | ||
| 886 | return ERROR_OVERFLOW; | ||
| 887 | } | ||
| 888 | internal_time.minute = static_cast<s8>(minute); | ||
| 889 | |||
| 890 | s32 day{internal_time.day}; | ||
| 891 | if (!SafeNormalize(day, hour, hours_per_day)) { | ||
| 892 | return ERROR_OVERFLOW; | ||
| 893 | } | ||
| 894 | internal_time.day = static_cast<s8>(day); | ||
| 895 | internal_time.hour = static_cast<s8>(hour); | ||
| 896 | |||
| 897 | s64 year{internal_time.year}; | ||
| 898 | s64 month{internal_time.month}; | ||
| 899 | if (!SafeNormalize(year, month, months_per_year)) { | ||
| 900 | return ERROR_OVERFLOW; | ||
| 901 | } | ||
| 902 | internal_time.month = static_cast<s8>(month); | ||
| 903 | |||
| 904 | if (!SafeAdd(year, year_base)) { | ||
| 905 | return ERROR_OVERFLOW; | ||
| 906 | } | ||
| 907 | |||
| 908 | while (day <= 0) { | ||
| 909 | if (!SafeAdd(year, -1)) { | ||
| 910 | return ERROR_OVERFLOW; | ||
| 911 | } | ||
| 912 | s64 temp_year{year}; | ||
| 913 | if (1 < internal_time.month) { | ||
| 914 | ++temp_year; | ||
| 915 | } | ||
| 916 | day += static_cast<s32>(GetYearLengthInDays(temp_year)); | ||
| 917 | } | ||
| 918 | |||
| 919 | while (day > days_per_leap_year) { | ||
| 920 | s64 temp_year{year}; | ||
| 921 | if (1 < internal_time.month) { | ||
| 922 | temp_year++; | ||
| 923 | } | ||
| 924 | day -= static_cast<s32>(GetYearLengthInDays(temp_year)); | ||
| 925 | if (!SafeAdd(year, 1)) { | ||
| 926 | return ERROR_OVERFLOW; | ||
| 927 | } | ||
| 928 | } | ||
| 929 | |||
| 930 | while (true) { | ||
| 931 | const s32 month_length{GetMonthLength(IsLeapYear(year), internal_time.month)}; | ||
| 932 | if (day <= month_length) { | ||
| 933 | break; | ||
| 934 | } | ||
| 935 | day -= month_length; | ||
| 936 | internal_time.month++; | ||
| 937 | if (internal_time.month >= months_per_year) { | ||
| 938 | internal_time.month = 0; | ||
| 939 | if (!SafeAdd(year, 1)) { | ||
| 940 | return ERROR_OVERFLOW; | ||
| 941 | } | ||
| 942 | } | ||
| 943 | } | ||
| 944 | internal_time.day = static_cast<s8>(day); | ||
| 945 | |||
| 946 | if (!SafeAdd(year, -year_base)) { | ||
| 947 | return ERROR_OVERFLOW; | ||
| 948 | } | ||
| 949 | internal_time.year = year; | ||
| 950 | |||
| 951 | s32 saved_seconds{}; | ||
| 952 | if (internal_time.second >= 0 && internal_time.second < seconds_per_minute) { | ||
| 953 | saved_seconds = 0; | ||
| 954 | } else if (year + year_base < epoch_year) { | ||
| 955 | s32 second{internal_time.second}; | ||
| 956 | if (!SafeAdd(second, 1 - seconds_per_minute)) { | ||
| 957 | return ERROR_OVERFLOW; | ||
| 958 | } | ||
| 959 | saved_seconds = second; | ||
| 960 | internal_time.second = 1 - seconds_per_minute; | ||
| 961 | } else { | ||
| 962 | saved_seconds = internal_time.second; | ||
| 963 | internal_time.second = 0; | ||
| 964 | } | ||
| 965 | |||
| 966 | s64 low{LLONG_MIN}; | ||
| 967 | s64 high{LLONG_MAX}; | ||
| 968 | while (true) { | ||
| 969 | s64 pivot{low / 2 + high / 2}; | ||
| 970 | if (pivot < low) { | ||
| 971 | pivot = low; | ||
| 972 | } else if (pivot > high) { | ||
| 973 | pivot = high; | ||
| 974 | } | ||
| 975 | s32 direction{}; | ||
| 976 | CalendarTimeInternal candidate_calendar_time{}; | ||
| 977 | CalendarAdditionalInfo unused{}; | ||
| 978 | if (ToCalendarTimeInternal(rules, pivot, candidate_calendar_time, unused) != | ||
| 979 | RESULT_SUCCESS) { | ||
| 980 | if (pivot > 0) { | ||
| 981 | direction = 1; | ||
| 982 | } else { | ||
| 983 | direction = -1; | ||
| 984 | } | ||
| 985 | } else { | ||
| 986 | direction = candidate_calendar_time.Compare(internal_time); | ||
| 987 | } | ||
| 988 | if (!direction) { | ||
| 989 | const s64 time_result{pivot + saved_seconds}; | ||
| 990 | if ((time_result < pivot) != (saved_seconds < 0)) { | ||
| 991 | return ERROR_OVERFLOW; | ||
| 992 | } | ||
| 993 | posix_time = time_result; | ||
| 994 | break; | ||
| 995 | } else { | ||
| 996 | if (pivot == low) { | ||
| 997 | if (pivot == LLONG_MAX) { | ||
| 998 | return ERROR_TIME_NOT_FOUND; | ||
| 999 | } | ||
| 1000 | pivot++; | ||
| 1001 | low++; | ||
| 1002 | } else if (pivot == high) { | ||
| 1003 | if (pivot == LLONG_MIN) { | ||
| 1004 | return ERROR_TIME_NOT_FOUND; | ||
| 1005 | } | ||
| 1006 | pivot--; | ||
| 1007 | high--; | ||
| 1008 | } | ||
| 1009 | if (low > high) { | ||
| 1010 | return ERROR_TIME_NOT_FOUND; | ||
| 1011 | } | ||
| 1012 | if (direction > 0) { | ||
| 1013 | high = pivot; | ||
| 1014 | } else { | ||
| 1015 | low = pivot; | ||
| 1016 | } | ||
| 1017 | } | ||
| 1018 | } | ||
| 1019 | return RESULT_SUCCESS; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | ResultCode TimeZoneManager::GetDeviceLocationName(LocationName& value) const { | ||
| 1023 | if (!is_initialized) { | ||
| 1024 | return ERROR_UNINITIALIZED_CLOCK; | ||
| 1025 | } | ||
| 1026 | std::memcpy(value.data(), device_location_name.c_str(), device_location_name.size()); | ||
| 1027 | return RESULT_SUCCESS; | ||
| 1028 | } | ||
| 1029 | |||
| 1030 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_manager.h b/src/core/hle/service/time/time_zone_manager.h new file mode 100644 index 000000000..7c6f975ae --- /dev/null +++ b/src/core/hle/service/time/time_zone_manager.h | |||
| @@ -0,0 +1,53 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <string> | ||
| 8 | |||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "core/file_sys/vfs_types.h" | ||
| 11 | #include "core/hle/service/time/clock_types.h" | ||
| 12 | #include "core/hle/service/time/time_zone_types.h" | ||
| 13 | |||
| 14 | namespace Service::Time::TimeZone { | ||
| 15 | |||
| 16 | class TimeZoneManager final { | ||
| 17 | public: | ||
| 18 | TimeZoneManager(); | ||
| 19 | ~TimeZoneManager(); | ||
| 20 | |||
| 21 | void SetTotalLocationNameCount(std::size_t value) { | ||
| 22 | total_location_name_count = value; | ||
| 23 | } | ||
| 24 | |||
| 25 | void SetTimeZoneRuleVersion(const u128& value) { | ||
| 26 | time_zone_rule_version = value; | ||
| 27 | } | ||
| 28 | |||
| 29 | void MarkAsInitialized() { | ||
| 30 | is_initialized = true; | ||
| 31 | } | ||
| 32 | |||
| 33 | ResultCode SetDeviceLocationNameWithTimeZoneRule(const std::string& location_name, | ||
| 34 | FileSys::VirtualFile& vfs_file); | ||
| 35 | ResultCode SetUpdatedTime(const Clock::SteadyClockTimePoint& value); | ||
| 36 | ResultCode GetDeviceLocationName(TimeZone::LocationName& value) const; | ||
| 37 | ResultCode ToCalendarTime(const TimeZoneRule& rules, s64 time, CalendarInfo& calendar) const; | ||
| 38 | ResultCode ToCalendarTimeWithMyRules(s64 time, CalendarInfo& calendar) const; | ||
| 39 | ResultCode ParseTimeZoneRuleBinary(TimeZoneRule& rules, FileSys::VirtualFile& vfs_file) const; | ||
| 40 | ResultCode ToPosixTime(const TimeZoneRule& rules, const CalendarTime& calendar_time, | ||
| 41 | s64& posix_time) const; | ||
| 42 | |||
| 43 | private: | ||
| 44 | bool is_initialized{}; | ||
| 45 | TimeZoneRule time_zone_rule{}; | ||
| 46 | std::string device_location_name{"GMT"}; | ||
| 47 | u128 time_zone_rule_version{}; | ||
| 48 | std::size_t total_location_name_count{}; | ||
| 49 | Clock::SteadyClockTimePoint time_zone_update_time_point{ | ||
| 50 | Clock::SteadyClockTimePoint::GetRandom()}; | ||
| 51 | }; | ||
| 52 | |||
| 53 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/core/hle/service/time/time_zone_service.cpp b/src/core/hle/service/time/time_zone_service.cpp new file mode 100644 index 000000000..1566e778e --- /dev/null +++ b/src/core/hle/service/time/time_zone_service.cpp | |||
| @@ -0,0 +1,148 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "core/hle/ipc_helpers.h" | ||
| 7 | #include "core/hle/service/time/time_zone_content_manager.h" | ||
| 8 | #include "core/hle/service/time/time_zone_service.h" | ||
| 9 | #include "core/hle/service/time/time_zone_types.h" | ||
| 10 | |||
| 11 | namespace Service::Time { | ||
| 12 | |||
| 13 | ITimeZoneService ::ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_content_manager) | ||
| 14 | : ServiceFramework("ITimeZoneService"), time_zone_content_manager{time_zone_content_manager} { | ||
| 15 | static const FunctionInfo functions[] = { | ||
| 16 | {0, &ITimeZoneService::GetDeviceLocationName, "GetDeviceLocationName"}, | ||
| 17 | {1, nullptr, "SetDeviceLocationName"}, | ||
| 18 | {2, nullptr, "GetTotalLocationNameCount"}, | ||
| 19 | {3, nullptr, "LoadLocationNameList"}, | ||
| 20 | {4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"}, | ||
| 21 | {5, nullptr, "GetTimeZoneRuleVersion"}, | ||
| 22 | {100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"}, | ||
| 23 | {101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"}, | ||
| 24 | {201, &ITimeZoneService::ToPosixTime, "ToPosixTime"}, | ||
| 25 | {202, nullptr, "ToPosixTimeWithMyRule"}, | ||
| 26 | }; | ||
| 27 | RegisterHandlers(functions); | ||
| 28 | } | ||
| 29 | |||
| 30 | void ITimeZoneService::GetDeviceLocationName(Kernel::HLERequestContext& ctx) { | ||
| 31 | LOG_DEBUG(Service_Time, "called"); | ||
| 32 | |||
| 33 | TimeZone::LocationName location_name{}; | ||
| 34 | if (const ResultCode result{ | ||
| 35 | time_zone_content_manager.GetTimeZoneManager().GetDeviceLocationName(location_name)}; | ||
| 36 | result != RESULT_SUCCESS) { | ||
| 37 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 38 | rb.Push(result); | ||
| 39 | return; | ||
| 40 | } | ||
| 41 | |||
| 42 | IPC::ResponseBuilder rb{ctx, (sizeof(location_name) / 4) + 2}; | ||
| 43 | rb.Push(RESULT_SUCCESS); | ||
| 44 | rb.PushRaw(location_name); | ||
| 45 | } | ||
| 46 | |||
| 47 | void ITimeZoneService::LoadTimeZoneRule(Kernel::HLERequestContext& ctx) { | ||
| 48 | IPC::RequestParser rp{ctx}; | ||
| 49 | const auto raw_location_name{rp.PopRaw<std::array<u8, 0x24>>()}; | ||
| 50 | |||
| 51 | std::string location_name; | ||
| 52 | for (const auto& byte : raw_location_name) { | ||
| 53 | // Strip extra bytes | ||
| 54 | if (byte == '\0') { | ||
| 55 | break; | ||
| 56 | } | ||
| 57 | location_name.push_back(byte); | ||
| 58 | } | ||
| 59 | |||
| 60 | LOG_DEBUG(Service_Time, "called, location_name={}", location_name); | ||
| 61 | |||
| 62 | TimeZone::TimeZoneRule time_zone_rule{}; | ||
| 63 | if (const ResultCode result{ | ||
| 64 | time_zone_content_manager.LoadTimeZoneRule(time_zone_rule, location_name)}; | ||
| 65 | result != RESULT_SUCCESS) { | ||
| 66 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 67 | rb.Push(result); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | |||
| 71 | std::vector<u8> time_zone_rule_outbuffer(sizeof(TimeZone::TimeZoneRule)); | ||
| 72 | std::memcpy(time_zone_rule_outbuffer.data(), &time_zone_rule, sizeof(TimeZone::TimeZoneRule)); | ||
| 73 | ctx.WriteBuffer(time_zone_rule_outbuffer); | ||
| 74 | |||
| 75 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 76 | rb.Push(RESULT_SUCCESS); | ||
| 77 | } | ||
| 78 | |||
| 79 | void ITimeZoneService::ToCalendarTime(Kernel::HLERequestContext& ctx) { | ||
| 80 | IPC::RequestParser rp{ctx}; | ||
| 81 | const auto posix_time{rp.Pop<s64>()}; | ||
| 82 | |||
| 83 | LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time); | ||
| 84 | |||
| 85 | TimeZone::TimeZoneRule time_zone_rule{}; | ||
| 86 | const auto buffer{ctx.ReadBuffer()}; | ||
| 87 | std::memcpy(&time_zone_rule, buffer.data(), buffer.size()); | ||
| 88 | |||
| 89 | TimeZone::CalendarInfo calendar_info{}; | ||
| 90 | if (const ResultCode result{time_zone_content_manager.GetTimeZoneManager().ToCalendarTime( | ||
| 91 | time_zone_rule, posix_time, calendar_info)}; | ||
| 92 | result != RESULT_SUCCESS) { | ||
| 93 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 94 | rb.Push(result); | ||
| 95 | return; | ||
| 96 | } | ||
| 97 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)}; | ||
| 99 | rb.Push(RESULT_SUCCESS); | ||
| 100 | rb.PushRaw(calendar_info); | ||
| 101 | } | ||
| 102 | |||
| 103 | void ITimeZoneService::ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { | ||
| 104 | IPC::RequestParser rp{ctx}; | ||
| 105 | const auto posix_time{rp.Pop<s64>()}; | ||
| 106 | |||
| 107 | LOG_DEBUG(Service_Time, "called, posix_time=0x{:016X}", posix_time); | ||
| 108 | |||
| 109 | TimeZone::CalendarInfo calendar_info{}; | ||
| 110 | if (const ResultCode result{ | ||
| 111 | time_zone_content_manager.GetTimeZoneManager().ToCalendarTimeWithMyRules( | ||
| 112 | posix_time, calendar_info)}; | ||
| 113 | result != RESULT_SUCCESS) { | ||
| 114 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 115 | rb.Push(result); | ||
| 116 | return; | ||
| 117 | } | ||
| 118 | |||
| 119 | IPC::ResponseBuilder rb{ctx, 2 + (sizeof(TimeZone::CalendarInfo) / 4)}; | ||
| 120 | rb.Push(RESULT_SUCCESS); | ||
| 121 | rb.PushRaw(calendar_info); | ||
| 122 | } | ||
| 123 | |||
| 124 | void ITimeZoneService::ToPosixTime(Kernel::HLERequestContext& ctx) { | ||
| 125 | LOG_DEBUG(Service_Time, "called"); | ||
| 126 | |||
| 127 | IPC::RequestParser rp{ctx}; | ||
| 128 | const auto calendar_time{rp.PopRaw<TimeZone::CalendarTime>()}; | ||
| 129 | TimeZone::TimeZoneRule time_zone_rule{}; | ||
| 130 | std::memcpy(&time_zone_rule, ctx.ReadBuffer().data(), sizeof(TimeZone::TimeZoneRule)); | ||
| 131 | |||
| 132 | s64 posix_time{}; | ||
| 133 | if (const ResultCode result{time_zone_content_manager.GetTimeZoneManager().ToPosixTime( | ||
| 134 | time_zone_rule, calendar_time, posix_time)}; | ||
| 135 | result != RESULT_SUCCESS) { | ||
| 136 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 137 | rb.Push(result); | ||
| 138 | return; | ||
| 139 | } | ||
| 140 | |||
| 141 | // TODO(bunnei): Handle multiple times | ||
| 142 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 143 | rb.Push(RESULT_SUCCESS); | ||
| 144 | rb.PushRaw<u32>(1); // Number of times we're returning | ||
| 145 | ctx.WriteBuffer(&posix_time, sizeof(s64)); | ||
| 146 | } | ||
| 147 | |||
| 148 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_zone_service.h b/src/core/hle/service/time/time_zone_service.h new file mode 100644 index 000000000..a92b4312b --- /dev/null +++ b/src/core/hle/service/time/time_zone_service.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/service.h" | ||
| 8 | |||
| 9 | namespace Service::Time { | ||
| 10 | |||
| 11 | namespace TimeZone { | ||
| 12 | class TimeZoneContentManager; | ||
| 13 | } | ||
| 14 | |||
| 15 | class ITimeZoneService final : public ServiceFramework<ITimeZoneService> { | ||
| 16 | public: | ||
| 17 | explicit ITimeZoneService(TimeZone::TimeZoneContentManager& time_zone_manager); | ||
| 18 | |||
| 19 | private: | ||
| 20 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx); | ||
| 21 | void LoadTimeZoneRule(Kernel::HLERequestContext& ctx); | ||
| 22 | void ToCalendarTime(Kernel::HLERequestContext& ctx); | ||
| 23 | void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx); | ||
| 24 | void ToPosixTime(Kernel::HLERequestContext& ctx); | ||
| 25 | |||
| 26 | private: | ||
| 27 | TimeZone::TimeZoneContentManager& time_zone_content_manager; | ||
| 28 | }; | ||
| 29 | |||
| 30 | } // namespace Service::Time | ||
diff --git a/src/core/hle/service/time/time_zone_types.h b/src/core/hle/service/time/time_zone_types.h new file mode 100644 index 000000000..9be15b53e --- /dev/null +++ b/src/core/hle/service/time/time_zone_types.h | |||
| @@ -0,0 +1,87 @@ | |||
| 1 | // Copyright 2019 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | |||
| 9 | #include "common/common_funcs.h" | ||
| 10 | #include "common/common_types.h" | ||
| 11 | #include "common/swap.h" | ||
| 12 | |||
| 13 | namespace Service::Time::TimeZone { | ||
| 14 | |||
| 15 | using LocationName = std::array<char, 0x24>; | ||
| 16 | |||
| 17 | /// https://switchbrew.org/wiki/Glue_services#ttinfo | ||
| 18 | struct TimeTypeInfo { | ||
| 19 | s32 gmt_offset{}; | ||
| 20 | u8 is_dst{}; | ||
| 21 | INSERT_PADDING_BYTES(3); | ||
| 22 | s32 abbreviation_list_index{}; | ||
| 23 | u8 is_standard_time_daylight{}; | ||
| 24 | u8 is_gmt{}; | ||
| 25 | INSERT_PADDING_BYTES(2); | ||
| 26 | }; | ||
| 27 | static_assert(sizeof(TimeTypeInfo) == 0x10, "TimeTypeInfo is incorrect size"); | ||
| 28 | |||
| 29 | /// https://switchbrew.org/wiki/Glue_services#TimeZoneRule | ||
| 30 | struct TimeZoneRule { | ||
| 31 | s32 time_count{}; | ||
| 32 | s32 type_count{}; | ||
| 33 | s32 char_count{}; | ||
| 34 | u8 go_back{}; | ||
| 35 | u8 go_ahead{}; | ||
| 36 | INSERT_PADDING_BYTES(2); | ||
| 37 | std::array<s64, 1000> ats{}; | ||
| 38 | std::array<s8, 1000> types{}; | ||
| 39 | std::array<TimeTypeInfo, 128> ttis{}; | ||
| 40 | std::array<char, 512> chars{}; | ||
| 41 | s32 default_type{}; | ||
| 42 | INSERT_PADDING_BYTES(0x12C4); | ||
| 43 | }; | ||
| 44 | static_assert(sizeof(TimeZoneRule) == 0x4000, "TimeZoneRule is incorrect size"); | ||
| 45 | |||
| 46 | /// https://switchbrew.org/wiki/Glue_services#CalendarAdditionalInfo | ||
| 47 | struct CalendarAdditionalInfo { | ||
| 48 | u32 day_of_week{}; | ||
| 49 | u32 day_of_year{}; | ||
| 50 | std::array<char, 8> timezone_name; | ||
| 51 | u32 is_dst{}; | ||
| 52 | s32 gmt_offset{}; | ||
| 53 | }; | ||
| 54 | static_assert(sizeof(CalendarAdditionalInfo) == 0x18, "CalendarAdditionalInfo is incorrect size"); | ||
| 55 | |||
| 56 | /// https://switchbrew.org/wiki/Glue_services#CalendarTime | ||
| 57 | struct CalendarTime { | ||
| 58 | s16 year{}; | ||
| 59 | s8 month{}; | ||
| 60 | s8 day{}; | ||
| 61 | s8 hour{}; | ||
| 62 | s8 minute{}; | ||
| 63 | s8 second{}; | ||
| 64 | INSERT_PADDING_BYTES(1); | ||
| 65 | }; | ||
| 66 | static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime is incorrect size"); | ||
| 67 | |||
| 68 | struct CalendarInfo { | ||
| 69 | CalendarTime time{}; | ||
| 70 | CalendarAdditionalInfo additiona_info{}; | ||
| 71 | }; | ||
| 72 | static_assert(sizeof(CalendarInfo) == 0x20, "CalendarInfo is incorrect size"); | ||
| 73 | |||
| 74 | struct TzifHeader { | ||
| 75 | u32_be magic{}; | ||
| 76 | u8 version{}; | ||
| 77 | INSERT_PADDING_BYTES(15); | ||
| 78 | s32_be ttis_gmt_count{}; | ||
| 79 | s32_be ttis_std_count{}; | ||
| 80 | s32_be leap_count{}; | ||
| 81 | s32_be time_count{}; | ||
| 82 | s32_be type_count{}; | ||
| 83 | s32_be char_count{}; | ||
| 84 | }; | ||
| 85 | static_assert(sizeof(TzifHeader) == 0x2C, "TzifHeader is incorrect size"); | ||
| 86 | |||
| 87 | } // namespace Service::Time::TimeZone | ||
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 1d1f780e7..58dfa8033 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -91,6 +91,7 @@ void Maxwell3D::InitializeRegisterDefaults() { | |||
| 91 | regs.rasterize_enable = 1; | 91 | regs.rasterize_enable = 1; |
| 92 | regs.rt_separate_frag_data = 1; | 92 | regs.rt_separate_frag_data = 1; |
| 93 | regs.framebuffer_srgb = 1; | 93 | regs.framebuffer_srgb = 1; |
| 94 | regs.cull.front_face = Maxwell3D::Regs::Cull::FrontFace::ClockWise; | ||
| 94 | 95 | ||
| 95 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true; | 96 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_end_gl)] = true; |
| 96 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true; | 97 | mme_inline[MAXWELL3D_REG_INDEX(draw.vertex_begin_gl)] = true; |
diff --git a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp index 2e0536bf6..b155dfb49 100644 --- a/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp | |||
| @@ -191,8 +191,7 @@ UniquePipeline VKGraphicsPipeline::CreatePipeline(const RenderPassParams& render | |||
| 191 | const vk::PipelineRasterizationStateCreateInfo rasterizer_ci( | 191 | const vk::PipelineRasterizationStateCreateInfo rasterizer_ci( |
| 192 | {}, rs.depth_clamp_enable, false, vk::PolygonMode::eFill, | 192 | {}, rs.depth_clamp_enable, false, vk::PolygonMode::eFill, |
| 193 | rs.cull_enable ? MaxwellToVK::CullFace(rs.cull_face) : vk::CullModeFlagBits::eNone, | 193 | rs.cull_enable ? MaxwellToVK::CullFace(rs.cull_face) : vk::CullModeFlagBits::eNone, |
| 194 | rs.cull_enable ? MaxwellToVK::FrontFace(rs.front_face) : vk::FrontFace::eCounterClockwise, | 194 | MaxwellToVK::FrontFace(rs.front_face), rs.depth_bias_enable, 0.0f, 0.0f, 0.0f, 1.0f); |
| 195 | rs.depth_bias_enable, 0.0f, 0.0f, 0.0f, 1.0f); | ||
| 196 | 195 | ||
| 197 | const vk::PipelineMultisampleStateCreateInfo multisampling_ci( | 196 | const vk::PipelineMultisampleStateCreateInfo multisampling_ci( |
| 198 | {}, vk::SampleCountFlagBits::e1, false, 0.0f, nullptr, false, false); | 197 | {}, vk::SampleCountFlagBits::e1, false, 0.0f, nullptr, false, false); |
diff --git a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp index 0cf97cafa..dd6d2ef03 100644 --- a/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp +++ b/src/video_core/renderer_vulkan/vk_shader_decompiler.cpp | |||
| @@ -1796,9 +1796,17 @@ private: | |||
| 1796 | return {}; | 1796 | return {}; |
| 1797 | } | 1797 | } |
| 1798 | 1798 | ||
| 1799 | Expression UAtomicAdd(Operation) { | 1799 | Expression UAtomicAdd(Operation operation) { |
| 1800 | UNIMPLEMENTED(); | 1800 | const auto& smem = std::get<SmemNode>(*operation[0]); |
| 1801 | return {}; | 1801 | Id address = AsUint(Visit(smem.GetAddress())); |
| 1802 | address = OpShiftRightLogical(t_uint, address, Constant(t_uint, 2U)); | ||
| 1803 | const Id pointer = OpAccessChain(t_smem_uint, shared_memory, address); | ||
| 1804 | |||
| 1805 | const Id scope = Constant(t_uint, static_cast<u32>(spv::Scope::Device)); | ||
| 1806 | const Id semantics = Constant(t_uint, 0U); | ||
| 1807 | |||
| 1808 | const Id value = AsUint(Visit(operation[1])); | ||
| 1809 | return {OpAtomicIAdd(t_uint, pointer, scope, semantics, value), Type::Uint}; | ||
| 1802 | } | 1810 | } |
| 1803 | 1811 | ||
| 1804 | Expression Branch(Operation operation) { | 1812 | Expression Branch(Operation operation) { |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 25b2e1b05..8497eaa14 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -73,11 +73,11 @@ void ConfigureDialog::RetranslateUI() { | |||
| 73 | Q_DECLARE_METATYPE(QList<QWidget*>); | 73 | Q_DECLARE_METATYPE(QList<QWidget*>); |
| 74 | 74 | ||
| 75 | void ConfigureDialog::PopulateSelectionList() { | 75 | void ConfigureDialog::PopulateSelectionList() { |
| 76 | const std::array<std::pair<QString, QList<QWidget*>>, 4> items{ | 76 | const std::array<std::pair<QString, QList<QWidget*>>, 5> items{ |
| 77 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, | 77 | {{tr("General"), {ui->generalTab, ui->webTab, ui->debugTab, ui->gameListTab}}, |
| 78 | {tr("System"), | 78 | {tr("System"), {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab}}, |
| 79 | {ui->systemTab, ui->profileManagerTab, ui->serviceTab, ui->filesystemTab, ui->audioTab}}, | ||
| 80 | {tr("Graphics"), {ui->graphicsTab}}, | 79 | {tr("Graphics"), {ui->graphicsTab}}, |
| 80 | {tr("Audio"), {ui->audioTab}}, | ||
| 81 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, | 81 | {tr("Controls"), {ui->inputTab, ui->hotkeysTab}}}, |
| 82 | }; | 82 | }; |
| 83 | 83 | ||