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