Compare commits

..

2 Commits

Author SHA1 Message Date
bunnei
365f00cce8 Update src/core/hle/service/service.h
Co-authored-by: LC <mathew1800@gmail.com>
2020-11-24 14:31:35 -08:00
bunnei
62cf4f4ed9 hle: services: Fix a crash with improper NVFlinger lifetime management.
- This crash would happen when attempting to shutdown yuzu early on in boot.
2020-11-23 17:23:06 -08:00
722 changed files with 17172 additions and 21817 deletions

View File

@@ -5,7 +5,7 @@ cd /yuzu
ccache -s
mkdir build || true && cd build
cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON
cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DYUZU_USE_BUNDLED_UNICORN=ON -DYUZU_USE_QT_WEB_ENGINE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON
ninja

View File

@@ -5,7 +5,7 @@ cd /yuzu
ccache -s
mkdir build || true && cd build
cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON
cmake .. -G Ninja -DDISPLAY_VERSION=$1 -DCMAKE_TOOLCHAIN_FILE="$(pwd)/../CMakeModules/MinGWCross.cmake" -DUSE_CCACHE=ON -DYUZU_USE_BUNDLED_UNICORN=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON
ninja
ccache -s

View File

@@ -8,7 +8,7 @@ steps:
displayName: 'Install vulkan-sdk'
- script: python -m pip install --upgrade pip conan
displayName: 'Install conan'
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 --config Release -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_UNICORN=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DUSE_DISCORD_PRESENCE=ON -DDISPLAY_VERSION=${{ parameters['version'] }} .. && cd ..
displayName: 'Configure CMake'
- task: MSBuild@1
displayName: 'Build'

View File

@@ -1,4 +1,4 @@
#!/bin/bash -ex
mkdir -p "$HOME/.ccache"
docker run -e ENABLE_COMPATIBILITY_REPORTING --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/home/yuzu/.ccache yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.travis/linux/docker.sh
docker run -e ENABLE_COMPATIBILITY_REPORTING --env-file .travis/common/travis-ci.env -v $(pwd):/yuzu -v "$HOME/.ccache":/root/.ccache yuzuemu/build-environments:linux-fresh /bin/bash /yuzu/.travis/linux/docker.sh

View File

@@ -24,6 +24,8 @@ option(YUZU_ENABLE_BOXCAT "Enable the Boxcat service, a yuzu high-level implemen
option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
option(ENABLE_VULKAN "Enables Vulkan backend" ON)
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
# Default to a Release build
@@ -111,9 +113,6 @@ if (NOT DEFINED ARCHITECTURE)
endif()
message(STATUS "Target architecture: ${ARCHITECTURE}")
if (UNIX)
add_definitions(-DYUZU_UNIX=1)
endif()
# Configure C++ standard
# ===========================
@@ -158,6 +157,7 @@ macro(yuzu_find_packages)
# Capitalization matters here. We need the naming to match the generated paths from Conan
set(REQUIRED_LIBS
# Cmake Pkg Prefix Version Conan Pkg
"Boost 1.73 boost/1.73.0"
"Catch2 2.13 catch2/2.13.0"
"fmt 7.1 fmt/7.1.2"
# can't use until https://github.com/bincrafters/community/issues/1173
@@ -192,22 +192,6 @@ macro(yuzu_find_packages)
unset(FN_FORCE_REQUIRED)
endmacro()
find_package(Boost 1.73.0 COMPONENTS context headers QUIET)
if (Boost_FOUND)
set(Boost_LIBRARIES Boost::boost)
# Conditionally add Boost::context only if the active version of the Conan or system Boost package provides it
# The old version is missing Boost::context, so we want to avoid adding in that case
# The new version requires adding Boost::context to prevent linking issues
#
# This one is used by Conan on subsequent CMake configures, not the first configure.
if (TARGET Boost::context)
list(APPEND Boost_LIBRARIES Boost::context)
endif()
else()
message(STATUS "Boost 1.73.0 or newer not found, falling back to Conan")
list(APPEND CONAN_REQUIRED_LIBS "boost/1.73.0")
endif()
# Attempt to locate any packages that are required and report the missing ones in CONAN_REQUIRED_LIBS
yuzu_find_packages()
@@ -312,17 +296,6 @@ if (CONAN_REQUIRED_LIBS)
# this time with required, so we bail if its not found.
yuzu_find_packages(FORCE_REQUIRED)
if (NOT Boost_FOUND)
find_package(Boost 1.73.0 REQUIRED COMPONENTS context headers)
set(Boost_LIBRARIES Boost::boost)
# Conditionally add Boost::context only if the active version of the Conan Boost package provides it
# The old version is missing Boost::context, so we want to avoid adding in that case
# The new version requires adding Boost::context to prevent linking issues
if (TARGET Boost::context)
list(APPEND Boost_LIBRARIES Boost::context)
endif()
endif()
# Due to issues with variable scopes in functions, we need to also find_package(qt5) outside of the function
if(ENABLE_QT)
list(APPEND CMAKE_MODULE_PATH "${CONAN_QT_ROOT_RELEASE}")

View File

@@ -61,7 +61,9 @@ if (USE_DISCORD_PRESENCE)
endif()
# Sirit
add_subdirectory(sirit)
if (ENABLE_VULKAN)
add_subdirectory(sirit)
endif()
# libzip
find_package(Libzip 1.5)

View File

@@ -66,7 +66,6 @@ else()
-Wextra
-Wmissing-declarations
-Wno-attributes
-Wno-invalid-offsetof
-Wno-unused-parameter
)

View File

@@ -51,8 +51,6 @@ if (NOT MSVC)
-Werror=implicit-fallthrough
-Werror=reorder
-Werror=sign-compare
-Werror=shadow
-Werror=unused-parameter
-Werror=unused-variable
$<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter>

View File

@@ -31,8 +31,8 @@ Filter Filter::LowPass(double cutoff, double Q) {
Filter::Filter() : Filter(1.0, 0.0, 0.0, 1.0, 0.0, 0.0) {}
Filter::Filter(double a0_, double a1_, double a2_, double b0_, double b1_, double b2_)
: a1(a1_ / a0_), a2(a2_ / a0_), b0(b0_ / a0_), b1(b1_ / a0_), b2(b2_ / a0_) {}
Filter::Filter(double a0, double a1, double a2, double b0, double b1, double b2)
: a1(a1 / a0), a2(a2 / a0), b0(b0 / a0), b1(b1 / a0), b2(b2 / a0) {}
void Filter::Process(std::vector<s16>& signal) {
const std::size_t num_frames = signal.size() / 2;
@@ -69,7 +69,7 @@ CascadingFilter CascadingFilter::LowPass(double cutoff, std::size_t cascade_size
}
CascadingFilter::CascadingFilter() = default;
CascadingFilter::CascadingFilter(std::vector<Filter> filters_) : filters(std::move(filters_)) {}
CascadingFilter::CascadingFilter(std::vector<Filter> filters) : filters(std::move(filters)) {}
void CascadingFilter::Process(std::vector<s16>& signal) {
for (auto& filter : filters) {

View File

@@ -25,7 +25,7 @@ public:
/// Passthrough filter.
Filter();
Filter(double a0_, double a1_, double a2_, double b0_, double b1_, double b2_);
Filter(double a0, double a1, double a2, double b0, double b1, double b2);
void Process(std::vector<s16>& signal);
@@ -51,7 +51,7 @@ public:
/// Passthrough.
CascadingFilter();
explicit CascadingFilter(std::vector<Filter> filters_);
explicit CascadingFilter(std::vector<Filter> filters);
void Process(std::vector<s16>& signal);

View File

@@ -43,10 +43,6 @@ std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream,
return stream->GetTagsAndReleaseBuffers(max_count);
}
std::vector<Buffer::Tag> AudioOut::GetTagsAndReleaseBuffers(StreamPtr stream) {
return stream->GetTagsAndReleaseBuffers();
}
void AudioOut::StartStream(StreamPtr stream) {
stream->Play();
}

View File

@@ -31,9 +31,6 @@ public:
/// Returns a vector of recently released buffers specified by tag for the specified stream
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream, std::size_t max_count);
/// Returns a vector of all recently released buffers specified by tag for the specified stream
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(StreamPtr stream);
/// Starts an audio stream for playback
void StartStream(StreamPtr stream);

View File

@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <limits>
#include <vector>
#include "audio_core/audio_out.h"
@@ -15,71 +14,19 @@
#include "core/memory.h"
#include "core/settings.h"
namespace {
[[nodiscard]] static constexpr s16 ClampToS16(s32 value) {
return static_cast<s16>(std::clamp(value, s32{std::numeric_limits<s16>::min()},
s32{std::numeric_limits<s16>::max()}));
}
[[nodiscard]] static constexpr s16 Mix2To1(s16 l_channel, s16 r_channel) {
// Mix 50% from left and 50% from right channel
constexpr float l_mix_amount = 50.0f / 100.0f;
constexpr float r_mix_amount = 50.0f / 100.0f;
return ClampToS16(static_cast<s32>((static_cast<float>(l_channel) * l_mix_amount) +
(static_cast<float>(r_channel) * r_mix_amount)));
}
[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2(s16 fl_channel, s16 fr_channel,
s16 fc_channel,
[[maybe_unused]] s16 lf_channel,
s16 bl_channel, s16 br_channel) {
// Front channels are mixed 36.94%, Center channels are mixed to be 26.12% & the back channels
// are mixed to be 36.94%
constexpr float front_mix_amount = 36.94f / 100.0f;
constexpr float center_mix_amount = 26.12f / 100.0f;
constexpr float back_mix_amount = 36.94f / 100.0f;
// Mix 50% from left and 50% from right channel
const auto left = front_mix_amount * static_cast<float>(fl_channel) +
center_mix_amount * static_cast<float>(fc_channel) +
back_mix_amount * static_cast<float>(bl_channel);
const auto right = front_mix_amount * static_cast<float>(fr_channel) +
center_mix_amount * static_cast<float>(fc_channel) +
back_mix_amount * static_cast<float>(br_channel);
return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
}
[[nodiscard]] static constexpr std::tuple<s16, s16> Mix6To2WithCoefficients(
s16 fl_channel, s16 fr_channel, s16 fc_channel, s16 lf_channel, s16 bl_channel, s16 br_channel,
const std::array<float_le, 4>& coeff) {
const auto left =
static_cast<float>(fl_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(bl_channel) * coeff[0];
const auto right =
static_cast<float>(fr_channel) * coeff[0] + static_cast<float>(fc_channel) * coeff[1] +
static_cast<float>(lf_channel) * coeff[2] + static_cast<float>(br_channel) * coeff[0];
return {ClampToS16(static_cast<s32>(left)), ClampToS16(static_cast<s32>(right))};
}
} // namespace
namespace AudioCore {
AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
AudioCommon::AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
std::shared_ptr<Kernel::WritableEvent> buffer_event,
std::size_t instance_number)
: worker_params{params}, buffer_event{buffer_event_},
: worker_params{params}, buffer_event{buffer_event},
memory_pool_info(params.effect_count + params.voice_count * 4),
voice_context(params.voice_count), effect_context(params.effect_count), mix_context(),
sink_context(params.sink_count), splitter_context(),
voices(params.voice_count), memory{memory_},
command_generator(worker_params, voice_context, mix_context, splitter_context, effect_context,
memory) {
memory),
temp_mix_buffer(AudioCommon::TOTAL_TEMP_MIX_SIZE) {
behavior_info.SetUserRevision(params.revision);
splitter_context.Initialize(behavior_info, params.splitter_count,
params.num_splitter_send_channels);
@@ -88,7 +35,7 @@ AudioRenderer::AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory
stream =
audio_out->OpenStream(core_timing, params.sample_rate, AudioCommon::STREAM_NUM_CHANNELS,
fmt::format("AudioRenderer-Instance{}", instance_number),
[=]() { buffer_event_->Signal(); });
[=]() { buffer_event->Signal(); });
audio_out->StartStream(stream);
QueueMixedBuffer(0);
@@ -115,6 +62,10 @@ Stream::State AudioRenderer::GetStreamState() const {
return stream->GetState();
}
static constexpr s16 ClampToS16(s32 value) {
return static_cast<s16>(std::clamp(value, -32768, 32767));
}
ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params) {
@@ -153,8 +104,8 @@ ResultCode AudioRenderer::UpdateAudioRenderer(const std::vector<u8>& input_param
}
}
const auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
splitter_context, effect_context);
auto mix_result = info_updater.UpdateMixes(mix_context, worker_params.mix_buffer_count,
splitter_context, effect_context);
if (mix_result.IsError()) {
LOG_ERROR(Audio, "Failed to update mix parameters");
@@ -243,22 +194,20 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
for (std::size_t i = 0; i < BUFFER_SIZE; i++) {
if (channel_count == 1) {
const auto sample = ClampToS16(mix_buffers[0][i]);
// Place sample in all channels
for (u32 channel = 0; channel < stream_channel_count; channel++) {
buffer[i * stream_channel_count + channel] = sample;
buffer[i * stream_channel_count + 0] = sample;
if (stream_channel_count > 1) {
buffer[i * stream_channel_count + 1] = sample;
}
if (stream_channel_count == 6) {
// Output stream has a LF channel, mute it!
buffer[i * stream_channel_count + 3] = 0;
buffer[i * stream_channel_count + 2] = sample;
buffer[i * stream_channel_count + 4] = sample;
buffer[i * stream_channel_count + 5] = sample;
}
} else if (channel_count == 2) {
const auto l_sample = ClampToS16(mix_buffers[0][i]);
const auto r_sample = ClampToS16(mix_buffers[1][i]);
if (stream_channel_count == 1) {
buffer[i * stream_channel_count + 0] = Mix2To1(l_sample, r_sample);
buffer[i * stream_channel_count + 0] = l_sample;
} else if (stream_channel_count == 2) {
buffer[i * stream_channel_count + 0] = l_sample;
buffer[i * stream_channel_count + 1] = r_sample;
@@ -266,8 +215,8 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
buffer[i * stream_channel_count + 0] = l_sample;
buffer[i * stream_channel_count + 1] = r_sample;
// Combine both left and right channels to the center channel
buffer[i * stream_channel_count + 2] = Mix2To1(l_sample, r_sample);
buffer[i * stream_channel_count + 2] =
ClampToS16((static_cast<s32>(l_sample) + static_cast<s32>(r_sample)) / 2);
buffer[i * stream_channel_count + 4] = l_sample;
buffer[i * stream_channel_count + 5] = r_sample;
@@ -282,25 +231,17 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
const auto br_sample = ClampToS16(mix_buffers[5][i]);
if (stream_channel_count == 1) {
// Games seem to ignore the center channel half the time, we use the front left
// and right channel for mixing as that's where majority of the audio goes
buffer[i * stream_channel_count + 0] = Mix2To1(fl_sample, fr_sample);
buffer[i * stream_channel_count + 0] = fc_sample;
} else if (stream_channel_count == 2) {
// Mix all channels into 2 channels
if (sink_context.HasDownMixingCoefficients()) {
const auto [left, right] = Mix6To2WithCoefficients(
fl_sample, fr_sample, fc_sample, lf_sample, bl_sample, br_sample,
sink_context.GetDownmixCoefficients());
buffer[i * stream_channel_count + 0] = left;
buffer[i * stream_channel_count + 1] = right;
} else {
const auto [left, right] = Mix6To2(fl_sample, fr_sample, fc_sample,
lf_sample, bl_sample, br_sample);
buffer[i * stream_channel_count + 0] = left;
buffer[i * stream_channel_count + 1] = right;
}
buffer[i * stream_channel_count + 0] =
static_cast<s16>(0.3694f * static_cast<float>(fl_sample) +
0.2612f * static_cast<float>(fc_sample) +
0.3694f * static_cast<float>(bl_sample));
buffer[i * stream_channel_count + 1] =
static_cast<s16>(0.3694f * static_cast<float>(fr_sample) +
0.2612f * static_cast<float>(fc_sample) +
0.3694f * static_cast<float>(br_sample));
} else if (stream_channel_count == 6) {
// Pass through
buffer[i * stream_channel_count + 0] = fl_sample;
buffer[i * stream_channel_count + 1] = fr_sample;
buffer[i * stream_channel_count + 2] = fc_sample;
@@ -318,7 +259,7 @@ void AudioRenderer::QueueMixedBuffer(Buffer::Tag tag) {
}
void AudioRenderer::ReleaseAndQueueBuffers() {
const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream)};
const auto released_buffers{audio_out->GetTagsAndReleaseBuffers(stream, 2)};
for (const auto& tag : released_buffers) {
QueueMixedBuffer(tag);
}

View File

@@ -36,26 +36,31 @@ class Memory;
}
namespace AudioCore {
using DSPStateHolder = std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT>;
using DSPStateHolder = std::array<VoiceState*, 6>;
class AudioOut;
struct RendererInfo {
u64_le elasped_frame_count{};
INSERT_PADDING_WORDS(2);
};
static_assert(sizeof(RendererInfo) == 0x10, "RendererInfo is an invalid size");
class AudioRenderer {
public:
AudioRenderer(Core::Timing::CoreTiming& core_timing, Core::Memory::Memory& memory_,
AudioCommon::AudioRendererParameter params,
std::shared_ptr<Kernel::WritableEvent> buffer_event_,
std::size_t instance_number);
std::shared_ptr<Kernel::WritableEvent> buffer_event, std::size_t instance_number);
~AudioRenderer();
[[nodiscard]] ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params);
ResultCode UpdateAudioRenderer(const std::vector<u8>& input_params,
std::vector<u8>& output_params);
void QueueMixedBuffer(Buffer::Tag tag);
void ReleaseAndQueueBuffers();
[[nodiscard]] u32 GetSampleRate() const;
[[nodiscard]] u32 GetSampleCount() const;
[[nodiscard]] u32 GetMixBufferCount() const;
[[nodiscard]] Stream::State GetStreamState() const;
u32 GetSampleRate() const;
u32 GetSampleCount() const;
u32 GetMixBufferCount() const;
Stream::State GetStreamState() const;
private:
BehaviorInfo behavior_info{};
@@ -74,6 +79,7 @@ private:
Core::Memory::Memory& memory;
CommandGenerator command_generator;
std::size_t elapsed_frame_count{};
std::vector<s32> temp_mix_buffer{};
};
} // namespace AudioCore

View File

@@ -43,22 +43,22 @@ public:
void ClearError();
void UpdateFlags(u64_le dest_flags);
void SetUserRevision(u32_le revision);
[[nodiscard]] u32_le GetUserRevision() const;
[[nodiscard]] u32_le GetProcessRevision() const;
u32_le GetUserRevision() const;
u32_le GetProcessRevision() const;
[[nodiscard]] bool IsAdpcmLoopContextBugFixed() const;
[[nodiscard]] bool IsSplitterSupported() const;
[[nodiscard]] bool IsLongSizePreDelaySupported() const;
[[nodiscard]] bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
[[nodiscard]] bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
[[nodiscard]] bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
[[nodiscard]] bool IsElapsedFrameCountSupported() const;
[[nodiscard]] bool IsMemoryPoolForceMappingEnabled() const;
[[nodiscard]] bool IsFlushVoiceWaveBuffersSupported() const;
[[nodiscard]] bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const;
[[nodiscard]] bool IsVoicePitchAndSrcSkippedSupported() const;
[[nodiscard]] bool IsMixInParameterDirtyOnlyUpdateSupported() const;
[[nodiscard]] bool IsSplitterBugFixed() const;
bool IsAdpcmLoopContextBugFixed() const;
bool IsSplitterSupported() const;
bool IsLongSizePreDelaySupported() const;
bool IsAudioRendererProcessingTimeLimit80PercentSupported() const;
bool IsAudioRendererProcessingTimeLimit75PercentSupported() const;
bool IsAudioRendererProcessingTimeLimit70PercentSupported() const;
bool IsElapsedFrameCountSupported() const;
bool IsMemoryPoolForceMappingEnabled() const;
bool IsFlushVoiceWaveBuffersSupported() const;
bool IsVoicePlayedSampleCountResetAtLoopPointSupported() const;
bool IsVoicePitchAndSrcSkippedSupported() const;
bool IsMixInParameterDirtyOnlyUpdateSupported() const;
bool IsSplitterBugFixed() const;
void CopyErrorInfo(OutParams& dst);
private:

View File

@@ -18,7 +18,7 @@ class Buffer {
public:
using Tag = u64;
Buffer(Tag tag_, std::vector<s16>&& samples_) : tag{tag_}, samples{std::move(samples_)} {}
Buffer(Tag tag, std::vector<s16>&& samples) : tag{tag}, samples{std::move(samples)} {}
/// Returns the raw audio data for the buffer
std::vector<s16>& GetSamples() {

View File

@@ -67,12 +67,12 @@ s32 ApplyMixDepop(s32* output, s32 first_sample, s32 delta, s32 sample_count) {
} // namespace
CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_,
VoiceContext& voice_context_, MixContext& mix_context_,
SplitterContext& splitter_context_,
EffectContext& effect_context_, Core::Memory::Memory& memory_)
: worker_params(worker_params_), voice_context(voice_context_), mix_context(mix_context_),
splitter_context(splitter_context_), effect_context(effect_context_), memory(memory_),
CommandGenerator::CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
VoiceContext& voice_context, MixContext& mix_context,
SplitterContext& splitter_context, EffectContext& effect_context,
Core::Memory::Memory& memory)
: worker_params(worker_params), voice_context(voice_context), mix_context(mix_context),
splitter_context(splitter_context), effect_context(effect_context), memory(memory),
mix_buffer((worker_params.mix_buffer_count + AudioCommon::MAX_CHANNEL_COUNT) *
worker_params.sample_count),
sample_buffer(MIX_BUFFER_SIZE),
@@ -255,8 +255,7 @@ void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, Vo
void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voice_info,
VoiceState& dsp_state,
[[maybe_unused]] s32 mix_buffer_count,
[[maybe_unused]] s32 channel) {
s32 mix_buffer_count, s32 channel) {
for (std::size_t i = 0; i < AudioCommon::MAX_BIQUAD_FILTERS; i++) {
const auto& in_params = voice_info.GetInParams();
auto& biquad_filter = in_params.biquad_filter[i];
@@ -279,12 +278,9 @@ void CommandGenerator::GenerateBiquadFilterCommandForVoice(ServerVoiceInfo& voic
}
}
void CommandGenerator::GenerateBiquadFilterCommand([[maybe_unused]] s32 mix_buffer_id,
const BiquadFilterParameter& params,
std::array<s64, 2>& state,
std::size_t input_offset,
std::size_t output_offset, s32 sample_count,
s32 node_id) {
void AudioCore::CommandGenerator::GenerateBiquadFilterCommand(
s32 mix_buffer, const BiquadFilterParameter& params, std::array<s64, 2>& state,
std::size_t input_offset, std::size_t output_offset, s32 sample_count, s32 node_id) {
if (dumping_frame) {
LOG_DEBUG(Audio,
"(DSP_TRACE) GenerateBiquadFilterCommand node_id={}, "
@@ -718,8 +714,7 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
}
s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
s32 sample_count, [[maybe_unused]] s32 channel,
std::size_t mix_offset) {
s32 sample_count, s32 channel, std::size_t mix_offset) {
const auto& in_params = voice_info.GetInParams();
const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
if (wave_buffer.buffer_address == 0) {

View File

@@ -25,10 +25,10 @@ using MixVolumeBuffer = std::array<float, AudioCommon::MAX_MIX_BUFFERS>;
class CommandGenerator {
public:
explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params_,
VoiceContext& voice_context_, MixContext& mix_context_,
SplitterContext& splitter_context_, EffectContext& effect_context_,
Core::Memory::Memory& memory_);
explicit CommandGenerator(AudioCommon::AudioRendererParameter& worker_params,
VoiceContext& voice_context, MixContext& mix_context,
SplitterContext& splitter_context, EffectContext& effect_context,
Core::Memory::Memory& memory);
~CommandGenerator();
void ClearMixBuffers();
@@ -39,13 +39,13 @@ public:
void PreCommand();
void PostCommand();
[[nodiscard]] s32* GetChannelMixBuffer(s32 channel);
[[nodiscard]] const s32* GetChannelMixBuffer(s32 channel) const;
[[nodiscard]] s32* GetMixBuffer(std::size_t index);
[[nodiscard]] const s32* GetMixBuffer(std::size_t index) const;
[[nodiscard]] std::size_t GetMixChannelBufferOffset(s32 channel) const;
s32* GetChannelMixBuffer(s32 channel);
const s32* GetChannelMixBuffer(s32 channel) const;
s32* GetMixBuffer(std::size_t index);
const s32* GetMixBuffer(std::size_t index) const;
std::size_t GetMixChannelBufferOffset(s32 channel) const;
[[nodiscard]] std::size_t GetTotalMixBufferCount() const;
std::size_t GetTotalMixBufferCount() const;
private:
void GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state, s32 channel);
@@ -73,7 +73,7 @@ private:
void GenerateI3dl2ReverbEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
void GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
void GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled);
[[nodiscard]] ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
ServerSplitterDestinationData* GetDestinationData(s32 splitter_id, s32 index);
s32 WriteAuxBuffer(AuxInfoDSP& dsp_info, VAddr send_buffer, u32 max_samples, const s32* data,
u32 sample_count, u32 write_offset, u32 write_count);

View File

@@ -22,7 +22,7 @@ constexpr std::size_t MAX_CHANNEL_COUNT = 6;
constexpr std::size_t MAX_WAVE_BUFFERS = 4;
constexpr std::size_t MAX_SAMPLE_HISTORY = 4;
constexpr u32 STREAM_SAMPLE_RATE = 48000;
constexpr u32 STREAM_NUM_CHANNELS = 2;
constexpr u32 STREAM_NUM_CHANNELS = 6;
constexpr s32 NO_SPLITTER = -1;
constexpr s32 NO_MIX = 0x7fffffff;
constexpr s32 NO_FINAL_MIX = std::numeric_limits<s32>::min();

View File

@@ -21,16 +21,15 @@ namespace AudioCore {
class CubebSinkStream final : public SinkStream {
public:
CubebSinkStream(cubeb* ctx_, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
CubebSinkStream(cubeb* ctx, u32 sample_rate, u32 num_channels_, cubeb_devid output_device,
const std::string& name)
: ctx{ctx_}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate,
num_channels} {
: ctx{ctx}, num_channels{std::min(num_channels_, 6u)}, time_stretch{sample_rate,
num_channels} {
cubeb_stream_params params{};
params.rate = sample_rate;
params.channels = num_channels;
params.format = CUBEB_SAMPLE_S16NE;
params.prefs = CUBEB_STREAM_PREF_PERSIST;
switch (num_channels) {
case 1:
params.layout = CUBEB_LAYOUT_MONO;
@@ -193,9 +192,8 @@ SinkStream& CubebSink::AcquireSinkStream(u32 sample_rate, u32 num_channels,
return *sink_streams.back();
}
long CubebSinkStream::DataCallback([[maybe_unused]] cubeb_stream* stream, void* user_data,
[[maybe_unused]] const void* input_buffer, void* output_buffer,
long num_frames) {
long CubebSinkStream::DataCallback(cubeb_stream* stream, void* user_data, const void* input_buffer,
void* output_buffer, long num_frames) {
auto* impl = static_cast<CubebSinkStream*>(user_data);
auto* buffer = static_cast<u8*>(output_buffer);
@@ -238,9 +236,7 @@ long CubebSinkStream::DataCallback([[maybe_unused]] cubeb_stream* stream, void*
return num_frames;
}
void CubebSinkStream::StateCallback([[maybe_unused]] cubeb_stream* stream,
[[maybe_unused]] void* user_data,
[[maybe_unused]] cubeb_state state) {}
void CubebSinkStream::StateCallback(cubeb_stream* stream, void* user_data, cubeb_state state) {}
std::vector<std::string> ListCubebSinkDevices() {
std::vector<std::string> device_list;

View File

@@ -12,7 +12,7 @@ bool ValidChannelCountForEffect(s32 channel_count) {
}
} // namespace
EffectContext::EffectContext(std::size_t effect_count_) : effect_count(effect_count_) {
EffectContext::EffectContext(std::size_t effect_count) : effect_count(effect_count) {
effects.reserve(effect_count);
std::generate_n(std::back_inserter(effects), effect_count,
[] { return std::make_unique<EffectStubbed>(); });
@@ -61,13 +61,13 @@ const EffectBase* EffectContext::GetInfo(std::size_t i) const {
return effects.at(i).get();
}
EffectStubbed::EffectStubbed() : EffectBase(EffectType::Invalid) {}
EffectStubbed::EffectStubbed() : EffectBase::EffectBase(EffectType::Invalid) {}
EffectStubbed::~EffectStubbed() = default;
void EffectStubbed::Update([[maybe_unused]] EffectInfo::InParams& in_params) {}
void EffectStubbed::Update(EffectInfo::InParams& in_params) {}
void EffectStubbed::UpdateForCommandGeneration() {}
EffectBase::EffectBase(EffectType effect_type_) : effect_type(effect_type_) {}
EffectBase::EffectBase(EffectType effect_type) : effect_type(effect_type) {}
EffectBase::~EffectBase() = default;
UsageState EffectBase::GetUsage() const {
@@ -90,32 +90,32 @@ s32 EffectBase::GetProcessingOrder() const {
return processing_order;
}
EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric(EffectType::I3dl2Reverb) {}
EffectI3dl2Reverb::EffectI3dl2Reverb() : EffectGeneric::EffectGeneric(EffectType::I3dl2Reverb) {}
EffectI3dl2Reverb::~EffectI3dl2Reverb() = default;
void EffectI3dl2Reverb::Update(EffectInfo::InParams& in_params) {
auto& params = GetParams();
auto& internal_params = GetParams();
const auto* reverb_params = reinterpret_cast<I3dl2ReverbParams*>(in_params.raw.data());
if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
UNREACHABLE_MSG("Invalid reverb max channel count {}", reverb_params->max_channels);
return;
}
const auto last_status = params.status;
const auto last_status = internal_params.status;
mix_id = in_params.mix_id;
processing_order = in_params.processing_order;
params = *reverb_params;
internal_params = *reverb_params;
if (!ValidChannelCountForEffect(reverb_params->channel_count)) {
params.channel_count = params.max_channels;
internal_params.channel_count = internal_params.max_channels;
}
enabled = in_params.is_enabled;
if (last_status != ParameterStatus::Updated) {
params.status = last_status;
internal_params.status = last_status;
}
if (in_params.is_new || skipped) {
usage = UsageState::Initialized;
params.status = ParameterStatus::Initialized;
internal_params.status = ParameterStatus::Initialized;
skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
}
}
@@ -129,15 +129,15 @@ void EffectI3dl2Reverb::UpdateForCommandGeneration() {
GetParams().status = ParameterStatus::Updated;
}
EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric(EffectType::BiquadFilter) {}
EffectBiquadFilter::EffectBiquadFilter() : EffectGeneric::EffectGeneric(EffectType::BiquadFilter) {}
EffectBiquadFilter::~EffectBiquadFilter() = default;
void EffectBiquadFilter::Update(EffectInfo::InParams& in_params) {
auto& params = GetParams();
auto& internal_params = GetParams();
const auto* biquad_params = reinterpret_cast<BiquadFilterParams*>(in_params.raw.data());
mix_id = in_params.mix_id;
processing_order = in_params.processing_order;
params = *biquad_params;
internal_params = *biquad_params;
enabled = in_params.is_enabled;
}
@@ -150,7 +150,7 @@ void EffectBiquadFilter::UpdateForCommandGeneration() {
GetParams().status = ParameterStatus::Updated;
}
EffectAuxInfo::EffectAuxInfo() : EffectGeneric(EffectType::Aux) {}
EffectAuxInfo::EffectAuxInfo() : EffectGeneric::EffectGeneric(EffectType::Aux) {}
EffectAuxInfo::~EffectAuxInfo() = default;
void EffectAuxInfo::Update(EffectInfo::InParams& in_params) {
@@ -200,32 +200,32 @@ VAddr EffectAuxInfo::GetRecvBuffer() const {
return recv_buffer;
}
EffectDelay::EffectDelay() : EffectGeneric(EffectType::Delay) {}
EffectDelay::EffectDelay() : EffectGeneric::EffectGeneric(EffectType::Delay) {}
EffectDelay::~EffectDelay() = default;
void EffectDelay::Update(EffectInfo::InParams& in_params) {
const auto* delay_params = reinterpret_cast<DelayParams*>(in_params.raw.data());
auto& params = GetParams();
auto& internal_params = GetParams();
if (!ValidChannelCountForEffect(delay_params->max_channels)) {
return;
}
const auto last_status = params.status;
const auto last_status = internal_params.status;
mix_id = in_params.mix_id;
processing_order = in_params.processing_order;
params = *delay_params;
internal_params = *delay_params;
if (!ValidChannelCountForEffect(delay_params->channels)) {
params.channels = params.max_channels;
internal_params.channels = internal_params.max_channels;
}
enabled = in_params.is_enabled;
if (last_status != ParameterStatus::Updated) {
params.status = last_status;
internal_params.status = last_status;
}
if (in_params.is_new || skipped) {
usage = UsageState::Initialized;
params.status = ParameterStatus::Initialized;
internal_params.status = ParameterStatus::Initialized;
skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
}
}
@@ -239,7 +239,7 @@ void EffectDelay::UpdateForCommandGeneration() {
GetParams().status = ParameterStatus::Updated;
}
EffectBufferMixer::EffectBufferMixer() : EffectGeneric(EffectType::BufferMixer) {}
EffectBufferMixer::EffectBufferMixer() : EffectGeneric::EffectGeneric(EffectType::BufferMixer) {}
EffectBufferMixer::~EffectBufferMixer() = default;
void EffectBufferMixer::Update(EffectInfo::InParams& in_params) {
@@ -257,32 +257,32 @@ void EffectBufferMixer::UpdateForCommandGeneration() {
}
}
EffectReverb::EffectReverb() : EffectGeneric(EffectType::Reverb) {}
EffectReverb::EffectReverb() : EffectGeneric::EffectGeneric(EffectType::Reverb) {}
EffectReverb::~EffectReverb() = default;
void EffectReverb::Update(EffectInfo::InParams& in_params) {
const auto* reverb_params = reinterpret_cast<ReverbParams*>(in_params.raw.data());
auto& params = GetParams();
auto& internal_params = GetParams();
if (!ValidChannelCountForEffect(reverb_params->max_channels)) {
return;
}
const auto last_status = params.status;
const auto last_status = internal_params.status;
mix_id = in_params.mix_id;
processing_order = in_params.processing_order;
params = *reverb_params;
internal_params = *reverb_params;
if (!ValidChannelCountForEffect(reverb_params->channels)) {
params.channels = params.max_channels;
internal_params.channels = internal_params.max_channels;
}
enabled = in_params.is_enabled;
if (last_status != ParameterStatus::Updated) {
params.status = last_status;
internal_params.status = last_status;
}
if (in_params.is_new || skipped) {
usage = UsageState::Initialized;
params.status = ParameterStatus::Initialized;
internal_params.status = ParameterStatus::Initialized;
skipped = in_params.buffer_address == 0 || in_params.buffer_size == 0;
}
}

View File

@@ -184,16 +184,16 @@ struct AuxAddress {
class EffectBase {
public:
explicit EffectBase(EffectType effect_type_);
explicit EffectBase(EffectType effect_type);
virtual ~EffectBase();
virtual void Update(EffectInfo::InParams& in_params) = 0;
virtual void UpdateForCommandGeneration() = 0;
[[nodiscard]] UsageState GetUsage() const;
[[nodiscard]] EffectType GetType() const;
[[nodiscard]] bool IsEnabled() const;
[[nodiscard]] s32 GetMixID() const;
[[nodiscard]] s32 GetProcessingOrder() const;
UsageState GetUsage() const;
EffectType GetType() const;
bool IsEnabled() const;
s32 GetMixID() const;
s32 GetProcessingOrder() const;
protected:
UsageState usage{UsageState::Invalid};
@@ -206,7 +206,7 @@ protected:
template <typename T>
class EffectGeneric : public EffectBase {
public:
explicit EffectGeneric(EffectType effect_type_) : EffectBase(effect_type_) {}
explicit EffectGeneric(EffectType effect_type) : EffectBase(effect_type) {}
T& GetParams() {
return internal_params;
@@ -257,10 +257,10 @@ public:
void Update(EffectInfo::InParams& in_params) override;
void UpdateForCommandGeneration() override;
[[nodiscard]] VAddr GetSendInfo() const;
[[nodiscard]] VAddr GetSendBuffer() const;
[[nodiscard]] VAddr GetRecvInfo() const;
[[nodiscard]] VAddr GetRecvBuffer() const;
VAddr GetSendInfo() const;
VAddr GetSendBuffer() const;
VAddr GetRecvInfo() const;
VAddr GetRecvBuffer() const;
private:
VAddr send_info{};
@@ -306,13 +306,13 @@ private:
class EffectContext {
public:
explicit EffectContext(std::size_t effect_count_);
explicit EffectContext(std::size_t effect_count);
~EffectContext();
[[nodiscard]] std::size_t GetCount() const;
[[nodiscard]] EffectBase* GetInfo(std::size_t i);
[[nodiscard]] EffectBase* RetargetEffect(std::size_t i, EffectType effect);
[[nodiscard]] const EffectBase* GetInfo(std::size_t i) const;
std::size_t GetCount() const;
EffectBase* GetInfo(std::size_t i);
EffectBase* RetargetEffect(std::size_t i, EffectType effect);
const EffectBase* GetInfo(std::size_t i) const;
private:
std::size_t effect_count{};

View File

@@ -14,9 +14,9 @@
namespace AudioCore {
InfoUpdater::InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_,
BehaviorInfo& behavior_info_)
: in_params(in_params_), out_params(out_params_), behavior_info(behavior_info_) {
InfoUpdater::InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params,
BehaviorInfo& behavior_info)
: in_params(in_params), out_params(out_params), behavior_info(behavior_info) {
ASSERT(
AudioCommon::CanConsumeBuffer(in_params.size(), 0, sizeof(AudioCommon::UpdateDataHeader)));
std::memcpy(&input_header, in_params.data(), sizeof(AudioCommon::UpdateDataHeader));
@@ -135,8 +135,8 @@ bool InfoUpdater::UpdateVoiceChannelResources(VoiceContext& voice_context) {
}
bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
[[maybe_unused]] std::vector<ServerMemoryPoolInfo>& memory_pool_info,
[[maybe_unused]] VAddr audio_codec_dsp_addr) {
std::vector<ServerMemoryPoolInfo>& memory_pool_info,
VAddr audio_codec_dsp_addr) {
const auto voice_count = voice_context.GetVoiceCount();
std::vector<VoiceInfo::InParams> voice_in(voice_count);
std::vector<VoiceInfo::OutParams> voice_out(voice_count);
@@ -165,28 +165,28 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
// Update our voices
for (std::size_t i = 0; i < voice_count; i++) {
auto& voice_in_params = voice_in[i];
const auto channel_count = static_cast<std::size_t>(voice_in_params.channel_count);
auto& in_params = voice_in[i];
const auto channel_count = static_cast<std::size_t>(in_params.channel_count);
// Skip if it's not currently in use
if (!voice_in_params.is_in_use) {
if (!in_params.is_in_use) {
continue;
}
// Voice states for each channel
std::array<VoiceState*, AudioCommon::MAX_CHANNEL_COUNT> voice_states{};
ASSERT(static_cast<std::size_t>(voice_in_params.id) < voice_count);
ASSERT(static_cast<std::size_t>(in_params.id) < voice_count);
// Grab our current voice info
auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(voice_in_params.id));
auto& voice_info = voice_context.GetInfo(static_cast<std::size_t>(in_params.id));
ASSERT(channel_count <= AudioCommon::MAX_CHANNEL_COUNT);
// Get all our channel voice states
for (std::size_t channel = 0; channel < channel_count; channel++) {
voice_states[channel] =
&voice_context.GetState(voice_in_params.voice_channel_resource_ids[channel]);
&voice_context.GetState(in_params.voice_channel_resource_ids[channel]);
}
if (voice_in_params.is_new) {
if (in_params.is_new) {
// Default our values for our voice
voice_info.Initialize();
if (channel_count == 0 || channel_count > AudioCommon::MAX_CHANNEL_COUNT) {
@@ -200,12 +200,12 @@ bool InfoUpdater::UpdateVoices(VoiceContext& voice_context,
}
// Update our voice
voice_info.UpdateParameters(voice_in_params, behavior_info);
voice_info.UpdateParameters(in_params, behavior_info);
// TODO(ogniK): Handle mapping errors with behavior info based on in params response
// Update our wave buffers
voice_info.UpdateWaveBuffers(voice_in_params, voice_states, behavior_info);
voice_info.WriteOutStatus(voice_out[i], voice_in_params, voice_states);
voice_info.UpdateWaveBuffers(in_params, voice_states, behavior_info);
voice_info.WriteOutStatus(voice_out[i], in_params, voice_states);
}
if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, voice_out_size)) {
@@ -445,7 +445,7 @@ bool InfoUpdater::UpdatePerformanceBuffer() {
return true;
}
bool InfoUpdater::UpdateErrorInfo([[maybe_unused]] BehaviorInfo& in_behavior_info) {
bool InfoUpdater::UpdateErrorInfo(BehaviorInfo& in_behavior_info) {
const auto total_beahvior_info_out = sizeof(BehaviorInfo::OutParams);
if (!AudioCommon::CanConsumeBuffer(out_params.size(), output_offset, total_beahvior_info_out)) {

View File

@@ -21,8 +21,8 @@ class SplitterContext;
class InfoUpdater {
public:
// TODO(ogniK): Pass process handle when we support it
InfoUpdater(const std::vector<u8>& in_params_, std::vector<u8>& out_params_,
BehaviorInfo& behavior_info_);
InfoUpdater(const std::vector<u8>& in_params, std::vector<u8>& out_params,
BehaviorInfo& behavior_info);
~InfoUpdater();
bool UpdateBehaviorInfo(BehaviorInfo& in_behavior_info);

View File

@@ -10,10 +10,11 @@ namespace AudioCore {
ServerMemoryPoolInfo::ServerMemoryPoolInfo() = default;
ServerMemoryPoolInfo::~ServerMemoryPoolInfo() = default;
bool ServerMemoryPoolInfo::Update(const InParams& in_params, OutParams& out_params) {
bool ServerMemoryPoolInfo::Update(const ServerMemoryPoolInfo::InParams& in_params,
ServerMemoryPoolInfo::OutParams& out_params) {
// Our state does not need to be changed
if (in_params.state != State::RequestAttach && in_params.state != State::RequestDetach) {
if (in_params.state != ServerMemoryPoolInfo::State::RequestAttach &&
in_params.state != ServerMemoryPoolInfo::State::RequestDetach) {
return true;
}
@@ -31,11 +32,11 @@ bool ServerMemoryPoolInfo::Update(const InParams& in_params, OutParams& out_para
return false;
}
if (in_params.state == State::RequestAttach) {
if (in_params.state == ServerMemoryPoolInfo::State::RequestAttach) {
cpu_address = in_params.address;
size = in_params.size;
used = true;
out_params.state = State::Attached;
out_params.state = ServerMemoryPoolInfo::State::Attached;
} else {
// Unexpected address
if (cpu_address != in_params.address) {
@@ -53,7 +54,7 @@ bool ServerMemoryPoolInfo::Update(const InParams& in_params, OutParams& out_para
cpu_address = 0;
size = 0;
used = false;
out_params.state = State::Detached;
out_params.state = ServerMemoryPoolInfo::State::Detached;
}
return true;
}

View File

@@ -28,18 +28,19 @@ public:
struct InParams {
u64_le address{};
u64_le size{};
State state{};
ServerMemoryPoolInfo::State state{};
INSERT_PADDING_WORDS(3);
};
static_assert(sizeof(InParams) == 0x20, "InParams are an invalid size");
static_assert(sizeof(ServerMemoryPoolInfo::InParams) == 0x20, "InParams are an invalid size");
struct OutParams {
State state{};
ServerMemoryPoolInfo::State state{};
INSERT_PADDING_WORDS(3);
};
static_assert(sizeof(OutParams) == 0x10, "OutParams are an invalid size");
static_assert(sizeof(ServerMemoryPoolInfo::OutParams) == 0x10, "OutParams are an invalid size");
bool Update(const InParams& in_params, OutParams& out_params);
bool Update(const ServerMemoryPoolInfo::InParams& in_params,
ServerMemoryPoolInfo::OutParams& out_params);
private:
// There's another entry here which is the DSP address, however since we're not talking to the

View File

@@ -62,17 +62,17 @@ public:
ServerMixInfo();
~ServerMixInfo();
[[nodiscard]] const ServerMixInfo::InParams& GetInParams() const;
[[nodiscard]] ServerMixInfo::InParams& GetInParams();
const ServerMixInfo::InParams& GetInParams() const;
ServerMixInfo::InParams& GetInParams();
bool Update(EdgeMatrix& edge_matrix, const MixInfo::InParams& mix_in,
BehaviorInfo& behavior_info, SplitterContext& splitter_context,
EffectContext& effect_context);
[[nodiscard]] bool HasAnyConnection() const;
bool HasAnyConnection() const;
void Cleanup();
void SetEffectCount(std::size_t count);
void ResetEffectProcessingOrder();
[[nodiscard]] s32 GetEffectOrder(std::size_t i) const;
s32 GetEffectOrder(std::size_t i) const;
private:
std::vector<s32> effect_processing_order;
@@ -91,15 +91,15 @@ public:
void SortInfo();
bool TsortInfo(SplitterContext& splitter_context);
[[nodiscard]] std::size_t GetCount() const;
[[nodiscard]] ServerMixInfo& GetInfo(std::size_t i);
[[nodiscard]] const ServerMixInfo& GetInfo(std::size_t i) const;
[[nodiscard]] ServerMixInfo& GetSortedInfo(std::size_t i);
[[nodiscard]] const ServerMixInfo& GetSortedInfo(std::size_t i) const;
[[nodiscard]] ServerMixInfo& GetFinalMixInfo();
[[nodiscard]] const ServerMixInfo& GetFinalMixInfo() const;
[[nodiscard]] EdgeMatrix& GetEdgeMatrix();
[[nodiscard]] const EdgeMatrix& GetEdgeMatrix() const;
std::size_t GetCount() const;
ServerMixInfo& GetInfo(std::size_t i);
const ServerMixInfo& GetInfo(std::size_t i) const;
ServerMixInfo& GetSortedInfo(std::size_t i);
const ServerMixInfo& GetSortedInfo(std::size_t i) const;
ServerMixInfo& GetFinalMixInfo();
const ServerMixInfo& GetFinalMixInfo() const;
EdgeMatrix& GetEdgeMatrix();
const EdgeMatrix& GetEdgeMatrix() const;
private:
void CalcMixBufferOffset();

View File

@@ -5,23 +5,17 @@
#include "audio_core/sink_context.h"
namespace AudioCore {
SinkContext::SinkContext(std::size_t sink_count_) : sink_count{sink_count_} {}
SinkContext::SinkContext(std::size_t sink_count) : sink_count(sink_count) {}
SinkContext::~SinkContext() = default;
std::size_t SinkContext::GetCount() const {
return sink_count;
}
void SinkContext::UpdateMainSink(const SinkInfo::InParams& in) {
ASSERT(in.type == SinkTypes::Device);
has_downmix_coefs = in.device.down_matrix_enabled;
if (has_downmix_coefs) {
downmix_coefficients = in.device.down_matrix_coef;
}
void SinkContext::UpdateMainSink(SinkInfo::InParams& in) {
in_use = in.in_use;
use_count = in.device.input_count;
buffers = in.device.input;
std::memcpy(buffers.data(), in.device.input.data(), AudioCommon::MAX_CHANNEL_COUNT);
}
bool SinkContext::InUse() const {
@@ -34,12 +28,4 @@ std::vector<u8> SinkContext::OutputBuffers() const {
return buffer_ret;
}
bool SinkContext::HasDownMixingCoefficients() const {
return has_downmix_coefs;
}
const DownmixCoefficients& SinkContext::GetDownmixCoefficients() const {
return downmix_coefficients;
}
} // namespace AudioCore

View File

@@ -11,8 +11,6 @@
namespace AudioCore {
using DownmixCoefficients = std::array<float_le, 4>;
enum class SinkTypes : u8 {
Invalid = 0,
Device = 1,
@@ -42,7 +40,7 @@ public:
bool in_use;
INSERT_UNION_PADDING_BYTES(5);
};
static_assert(sizeof(CircularBufferIn) == 0x28,
static_assert(sizeof(SinkInfo::CircularBufferIn) == 0x28,
"SinkInfo::CircularBufferIn is in invalid size");
struct DeviceIn {
@@ -52,9 +50,9 @@ public:
std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input;
INSERT_UNION_PADDING_BYTES(1);
bool down_matrix_enabled;
DownmixCoefficients down_matrix_coef;
std::array<float_le, 4> down_matrix_coef;
};
static_assert(sizeof(DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size");
static_assert(sizeof(SinkInfo::DeviceIn) == 0x11c, "SinkInfo::DeviceIn is an invalid size");
struct InParams {
SinkTypes type{};
@@ -64,33 +62,28 @@ public:
INSERT_PADDING_WORDS(6);
union {
// std::array<u8, 0x120> raw{};
DeviceIn device;
CircularBufferIn circular_buffer;
SinkInfo::DeviceIn device;
SinkInfo::CircularBufferIn circular_buffer;
};
};
static_assert(sizeof(InParams) == 0x140, "SinkInfo::InParams are an invalid size!");
static_assert(sizeof(SinkInfo::InParams) == 0x140, "SinkInfo::InParams are an invalid size!");
};
class SinkContext {
public:
explicit SinkContext(std::size_t sink_count_);
explicit SinkContext(std::size_t sink_count);
~SinkContext();
[[nodiscard]] std::size_t GetCount() const;
std::size_t GetCount() const;
void UpdateMainSink(const SinkInfo::InParams& in);
[[nodiscard]] bool InUse() const;
[[nodiscard]] std::vector<u8> OutputBuffers() const;
[[nodiscard]] bool HasDownMixingCoefficients() const;
[[nodiscard]] const DownmixCoefficients& GetDownmixCoefficients() const;
void UpdateMainSink(SinkInfo::InParams& in);
bool InUse() const;
std::vector<u8> OutputBuffers() const;
private:
bool in_use{false};
s32 use_count{};
std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> buffers{};
std::size_t sink_count{};
bool has_downmix_coefs{false};
DownmixCoefficients downmix_coefficients{};
};
} // namespace AudioCore

View File

@@ -10,7 +10,7 @@
namespace AudioCore {
ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id_) : id{id_} {}
ServerSplitterDestinationData::ServerSplitterDestinationData(s32 id) : id(id) {}
ServerSplitterDestinationData::~ServerSplitterDestinationData() = default;
void ServerSplitterDestinationData::Update(SplitterInfo::InDestinationParams& header) {
@@ -87,7 +87,7 @@ void ServerSplitterDestinationData::UpdateInternalState() {
needs_update = false;
}
ServerSplitterInfo::ServerSplitterInfo(s32 id_) : id(id_) {}
ServerSplitterInfo::ServerSplitterInfo(s32 id) : id(id) {}
ServerSplitterInfo::~ServerSplitterInfo() = default;
void ServerSplitterInfo::InitializeInfos() {
@@ -121,7 +121,7 @@ const ServerSplitterDestinationData* ServerSplitterInfo::GetHead() const {
}
ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) {
auto* current_head = head;
auto current_head = head;
for (std::size_t i = 0; i < depth; i++) {
if (current_head == nullptr) {
return nullptr;
@@ -132,7 +132,7 @@ ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) {
}
const ServerSplitterDestinationData* ServerSplitterInfo::GetData(std::size_t depth) const {
auto* current_head = head;
auto current_head = head;
for (std::size_t i = 0; i < depth; i++) {
if (current_head == nullptr) {
return nullptr;
@@ -245,7 +245,7 @@ ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t i
const ServerSplitterDestinationData* SplitterContext::GetDestinationData(std::size_t info,
std::size_t data) const {
ASSERT(info < info_count);
const auto& cur_info = GetInfo(info);
auto& cur_info = GetInfo(info);
return cur_info.GetData(data);
}
@@ -267,11 +267,11 @@ std::size_t SplitterContext::GetDataCount() const {
return data_count;
}
void SplitterContext::Setup(std::size_t info_count_, std::size_t data_count_,
void SplitterContext::Setup(std::size_t _info_count, std::size_t _data_count,
bool is_splitter_bug_fixed) {
info_count = info_count_;
data_count = data_count_;
info_count = _info_count;
data_count = _data_count;
for (std::size_t i = 0; i < info_count; i++) {
auto& splitter = infos.emplace_back(static_cast<s32>(i));
@@ -364,7 +364,7 @@ bool SplitterContext::RecomposeDestination(ServerSplitterInfo& info,
// Clear our current destinations
auto* current_head = info.GetHead();
while (current_head != nullptr) {
auto* next_head = current_head->GetNextDestination();
auto next_head = current_head->GetNextDestination();
current_head->SetNextDestination(nullptr);
current_head = next_head;
}
@@ -471,8 +471,8 @@ bool NodeStates::DepthFirstSearch(EdgeMatrix& edge_matrix) {
continue;
}
const auto edge_node_count = edge_matrix.GetNodeCount();
for (s32 j = 0; j < static_cast<s32>(edge_node_count); j++) {
const auto node_count = edge_matrix.GetNodeCount();
for (s32 j = 0; j < static_cast<s32>(node_count); j++) {
// Check if our node is connected to our edge matrix
if (!edge_matrix.Connected(current_stack_index, j)) {
continue;

View File

@@ -63,7 +63,7 @@ public:
NodeStates();
~NodeStates();
void Initialize(std::size_t node_count_);
void Initialize(std::size_t _node_count);
bool Tsort(EdgeMatrix& edge_matrix);
std::size_t GetIndexPos() const;
const std::vector<s32>& GetIndexList() const;
@@ -72,15 +72,15 @@ private:
void PushTsortResult(s32 index);
bool DepthFirstSearch(EdgeMatrix& edge_matrix);
void ResetState();
void UpdateState(State state, std::size_t i);
State GetState(std::size_t i);
void UpdateState(NodeStates::State state, std::size_t i);
NodeStates::State GetState(std::size_t i);
std::size_t node_count{};
std::vector<bool> was_node_found{};
std::vector<bool> was_node_completed{};
std::size_t index_pos{};
std::vector<s32> index_list{};
Stack index_stack{};
NodeStates::Stack index_stack{};
};
enum class SplitterMagic : u32_le {
@@ -97,7 +97,8 @@ public:
s32_le data_count{};
INSERT_PADDING_WORDS(5);
};
static_assert(sizeof(InHeader) == 0x20, "SplitterInfo::InHeader is an invalid size");
static_assert(sizeof(SplitterInfo::InHeader) == 0x20,
"SplitterInfo::InHeader is an invalid size");
struct InInfoPrams {
SplitterMagic magic{};
@@ -106,7 +107,8 @@ public:
s32_le length{};
s32_le resource_id_base{};
};
static_assert(sizeof(InInfoPrams) == 0x14, "SplitterInfo::InInfoPrams is an invalid size");
static_assert(sizeof(SplitterInfo::InInfoPrams) == 0x14,
"SplitterInfo::InInfoPrams is an invalid size");
struct InDestinationParams {
SplitterMagic magic{};
@@ -116,13 +118,13 @@ public:
bool in_use{};
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(InDestinationParams) == 0x70,
static_assert(sizeof(SplitterInfo::InDestinationParams) == 0x70,
"SplitterInfo::InDestinationParams is an invalid size");
};
class ServerSplitterDestinationData {
public:
explicit ServerSplitterDestinationData(s32 id_);
explicit ServerSplitterDestinationData(s32 id);
~ServerSplitterDestinationData();
void Update(SplitterInfo::InDestinationParams& header);
@@ -151,7 +153,7 @@ private:
class ServerSplitterInfo {
public:
explicit ServerSplitterInfo(s32 id_);
explicit ServerSplitterInfo(s32 id);
~ServerSplitterInfo();
void InitializeInfos();

View File

@@ -31,10 +31,10 @@ u32 Stream::GetNumChannels() const {
return {};
}
Stream::Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format format_,
ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_)
: sample_rate{sample_rate_}, format{format_}, release_callback{std::move(release_callback_)},
sink_stream{sink_stream_}, core_timing{core_timing_}, name{std::move(name_)} {
Stream::Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format,
ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_)
: sample_rate{sample_rate}, format{format}, release_callback{std::move(release_callback)},
sink_stream{sink_stream}, core_timing{core_timing}, name{std::move(name_)} {
release_event =
Core::Timing::CreateEvent(name, [this](std::uintptr_t, std::chrono::nanoseconds ns_late) {
ReleaseActiveBuffer(ns_late);
@@ -122,7 +122,7 @@ bool Stream::QueueBuffer(BufferPtr&& buffer) {
return false;
}
bool Stream::ContainsBuffer([[maybe_unused]] Buffer::Tag tag) const {
bool Stream::ContainsBuffer(Buffer::Tag tag) const {
UNIMPLEMENTED();
return {};
}
@@ -136,14 +136,4 @@ std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers(std::size_t max_count)
return tags;
}
std::vector<Buffer::Tag> Stream::GetTagsAndReleaseBuffers() {
std::vector<Buffer::Tag> tags;
tags.reserve(released_buffers.size());
while (!released_buffers.empty()) {
tags.push_back(released_buffers.front()->GetTag());
released_buffers.pop();
}
return tags;
}
} // namespace AudioCore

View File

@@ -44,8 +44,8 @@ public:
/// Callback function type, used to change guest state on a buffer being released
using ReleaseCallback = std::function<void()>;
Stream(Core::Timing::CoreTiming& core_timing_, u32 sample_rate_, Format format_,
ReleaseCallback&& release_callback_, SinkStream& sink_stream_, std::string&& name_);
Stream(Core::Timing::CoreTiming& core_timing, u32 sample_rate, Format format,
ReleaseCallback&& release_callback, SinkStream& sink_stream, std::string&& name_);
/// Plays the audio stream
void Play();
@@ -57,40 +57,37 @@ public:
bool QueueBuffer(BufferPtr&& buffer);
/// Returns true if the audio stream contains a buffer with the specified tag
[[nodiscard]] bool ContainsBuffer(Buffer::Tag tag) const;
bool ContainsBuffer(Buffer::Tag tag) const;
/// Returns a vector of recently released buffers specified by tag
[[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
/// Returns a vector of all recently released buffers specified by tag
[[nodiscard]] std::vector<Buffer::Tag> GetTagsAndReleaseBuffers();
std::vector<Buffer::Tag> GetTagsAndReleaseBuffers(std::size_t max_count);
void SetVolume(float volume);
[[nodiscard]] float GetVolume() const {
float GetVolume() const {
return game_volume;
}
/// Returns true if the stream is currently playing
[[nodiscard]] bool IsPlaying() const {
bool IsPlaying() const {
return state == State::Playing;
}
/// Returns the number of queued buffers
[[nodiscard]] std::size_t GetQueueSize() const {
std::size_t GetQueueSize() const {
return queued_buffers.size();
}
/// Gets the sample rate
[[nodiscard]] u32 GetSampleRate() const {
u32 GetSampleRate() const {
return sample_rate;
}
/// Gets the number of channels
[[nodiscard]] u32 GetNumChannels() const;
u32 GetNumChannels() const;
/// Get the state
[[nodiscard]] State GetState() const;
State GetState() const;
private:
/// Plays the next queued buffer in the audio stream, starting playback if necessary
@@ -100,7 +97,7 @@ private:
void ReleaseActiveBuffer(std::chrono::nanoseconds ns_late = {});
/// Gets the number of core cycles when the specified buffer will be released
[[nodiscard]] std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
std::chrono::nanoseconds GetBufferReleaseNS(const Buffer& buffer) const;
u32 sample_rate; ///< Sample rate of the stream
Format format; ///< Format of the stream

View File

@@ -8,7 +8,7 @@
namespace AudioCore {
ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id_) : id(id_) {}
ServerVoiceChannelResource::ServerVoiceChannelResource(s32 id) : id(id) {}
ServerVoiceChannelResource::~ServerVoiceChannelResource() = default;
bool ServerVoiceChannelResource::InUse() const {
@@ -209,8 +209,7 @@ void ServerVoiceInfo::UpdateWaveBuffers(
void ServerVoiceInfo::UpdateWaveBuffer(ServerWaveBuffer& out_wavebuffer,
const WaveBuffer& in_wave_buffer, SampleFormat sample_format,
bool is_buffer_valid,
[[maybe_unused]] BehaviorInfo& behavior_info) {
bool is_buffer_valid, BehaviorInfo& behavior_info) {
if (!is_buffer_valid && out_wavebuffer.sent_to_dsp) {
out_wavebuffer.buffer_address = 0;
out_wavebuffer.buffer_size = 0;
@@ -401,7 +400,7 @@ bool ServerVoiceInfo::HasValidWaveBuffer(const VoiceState* state) const {
return std::find(valid_wb.begin(), valid_wb.end(), true) != valid_wb.end();
}
VoiceContext::VoiceContext(std::size_t voice_count_) : voice_count{voice_count_} {
VoiceContext::VoiceContext(std::size_t voice_count) : voice_count(voice_count) {
for (std::size_t i = 0; i < voice_count; i++) {
voice_channel_resources.emplace_back(static_cast<s32>(i));
sorted_voice_info.push_back(&voice_info.emplace_back());

View File

@@ -118,12 +118,12 @@ public:
bool in_use{};
INSERT_PADDING_BYTES(11);
};
static_assert(sizeof(InParams) == 0x70, "InParams is an invalid size");
static_assert(sizeof(VoiceChannelResource::InParams) == 0x70, "InParams is an invalid size");
};
class ServerVoiceChannelResource {
public:
explicit ServerVoiceChannelResource(s32 id_);
explicit ServerVoiceChannelResource(s32 id);
~ServerVoiceChannelResource();
bool InUse() const;
@@ -174,7 +174,7 @@ public:
BehaviorFlags behavior_flags{};
INSERT_PADDING_BYTES(16);
};
static_assert(sizeof(InParams) == 0x170, "InParams is an invalid size");
static_assert(sizeof(VoiceInfo::InParams) == 0x170, "InParams is an invalid size");
struct OutParams {
u64_le played_sample_count{};
@@ -182,7 +182,7 @@ public:
u8 voice_dropped{};
INSERT_PADDING_BYTES(3);
};
static_assert(sizeof(OutParams) == 0x10, "OutParams is an invalid size");
static_assert(sizeof(VoiceInfo::OutParams) == 0x10, "OutParams is an invalid size");
};
class ServerVoiceInfo {
@@ -263,7 +263,7 @@ private:
class VoiceContext {
public:
explicit VoiceContext(std::size_t voice_count_);
VoiceContext(std::size_t voice_count);
~VoiceContext();
std::size_t GetVoiceCount() const;

View File

@@ -104,7 +104,6 @@ add_library(common STATIC
detached_tasks.h
bit_cast.h
bit_field.h
bit_set.h
bit_util.h
cityhash.cpp
cityhash.h
@@ -113,7 +112,6 @@ add_library(common STATIC
common_paths.h
common_types.h
concepts.h
div_ceil.h
dynamic_library.cpp
dynamic_library.h
fiber.cpp
@@ -141,6 +139,7 @@ add_library(common STATIC
microprofile.h
microprofileui.h
misc.cpp
multi_level_queue.h
page_table.cpp
page_table.h
param_package.cpp
@@ -209,6 +208,7 @@ else()
endif()
create_target_directory_groups(common)
find_package(Boost 1.71 COMPONENTS context headers REQUIRED)
target_link_libraries(common PUBLIC ${Boost_LIBRARIES} fmt::fmt microprofile)
target_link_libraries(common PRIVATE lz4::lz4 xbyak)

View File

@@ -1,99 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <array>
#include <bit>
#include "common/alignment.h"
#include "common/bit_util.h"
#include "common/common_types.h"
namespace Common {
namespace impl {
template <typename Storage, size_t N>
class BitSet {
public:
constexpr BitSet() = default;
constexpr void SetBit(size_t i) {
this->words[i / FlagsPerWord] |= GetBitMask(i % FlagsPerWord);
}
constexpr void ClearBit(size_t i) {
this->words[i / FlagsPerWord] &= ~GetBitMask(i % FlagsPerWord);
}
constexpr size_t CountLeadingZero() const {
for (size_t i = 0; i < NumWords; i++) {
if (this->words[i]) {
return FlagsPerWord * i + CountLeadingZeroImpl(this->words[i]);
}
}
return FlagsPerWord * NumWords;
}
constexpr size_t GetNextSet(size_t n) const {
for (size_t i = (n + 1) / FlagsPerWord; i < NumWords; i++) {
Storage word = this->words[i];
if (!IsAligned(n + 1, FlagsPerWord)) {
word &= GetBitMask(n % FlagsPerWord) - 1;
}
if (word) {
return FlagsPerWord * i + CountLeadingZeroImpl(word);
}
}
return FlagsPerWord * NumWords;
}
private:
static_assert(std::is_unsigned_v<Storage>);
static_assert(sizeof(Storage) <= sizeof(u64));
static constexpr size_t FlagsPerWord = BitSize<Storage>();
static constexpr size_t NumWords = AlignUp(N, FlagsPerWord) / FlagsPerWord;
static constexpr auto CountLeadingZeroImpl(Storage word) {
return std::countl_zero(static_cast<unsigned long long>(word)) -
(BitSize<unsigned long long>() - FlagsPerWord);
}
static constexpr Storage GetBitMask(size_t bit) {
return Storage(1) << (FlagsPerWord - 1 - bit);
}
std::array<Storage, NumWords> words{};
};
} // namespace impl
template <size_t N>
using BitSet8 = impl::BitSet<u8, N>;
template <size_t N>
using BitSet16 = impl::BitSet<u16, N>;
template <size_t N>
using BitSet32 = impl::BitSet<u32, N>;
template <size_t N>
using BitSet64 = impl::BitSet<u64, N>;
} // namespace Common

View File

@@ -31,8 +31,4 @@ concept DerivedFrom = requires {
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
};
// TODO: Replace with std::convertible_to when libc++ implements it.
template <typename From, typename To>
concept ConvertibleTo = std::is_convertible_v<From, To>;
} // namespace Common

View File

@@ -1,26 +0,0 @@
// Copyright 2020 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <cstddef>
#include <type_traits>
namespace Common {
/// Ceiled integer division.
template <typename N, typename D>
requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeil(
N number, D divisor) {
return (static_cast<D>(number) + divisor - 1) / divisor;
}
/// Ceiled integer division with logarithmic divisor in base 2
template <typename N, typename D>
requires std::is_integral_v<N>&& std::is_unsigned_v<D>[[nodiscard]] constexpr auto DivCeilLog2(
N value, D alignment_log2) {
return (static_cast<D>(value) + (D(1) << alignment_log2) - 1) >> alignment_log2;
}
} // namespace Common

View File

@@ -5,20 +5,18 @@
#include "common/assert.h"
#include "common/fiber.h"
#include "common/spin_lock.h"
#include "common/virtual_buffer.h"
#if defined(_WIN32) || defined(WIN32)
#include <windows.h>
#else
#include <boost/context/detail/fcontext.hpp>
#endif
namespace Common {
constexpr std::size_t default_stack_size = 256 * 1024;
constexpr std::size_t default_stack_size = 256 * 1024; // 256kb
struct Fiber::FiberImpl {
FiberImpl() : stack{default_stack_size}, rewind_stack{default_stack_size} {}
VirtualBuffer<u8> stack;
VirtualBuffer<u8> rewind_stack;
SpinLock guard{};
std::function<void(void*)> entry_point;
std::function<void(void*)> rewind_point;
@@ -28,10 +26,17 @@ struct Fiber::FiberImpl {
bool is_thread_fiber{};
bool released{};
u8* stack_limit{};
u8* rewind_stack_limit{};
boost::context::detail::fcontext_t context{};
boost::context::detail::fcontext_t rewind_context{};
#if defined(_WIN32) || defined(WIN32)
LPVOID handle = nullptr;
LPVOID rewind_handle = nullptr;
#else
alignas(64) std::array<u8, default_stack_size> stack;
alignas(64) std::array<u8, default_stack_size> rewind_stack;
u8* stack_limit;
u8* rewind_stack_limit;
boost::context::detail::fcontext_t context;
boost::context::detail::fcontext_t rewind_context;
#endif
};
void Fiber::SetStartParameter(void* new_parameter) {
@@ -43,6 +48,95 @@ void Fiber::SetRewindPoint(std::function<void(void*)>&& rewind_func, void* rewin
impl->rewind_parameter = rewind_param;
}
#if defined(_WIN32) || defined(WIN32)
void Fiber::Start() {
ASSERT(impl->previous_fiber != nullptr);
impl->previous_fiber->impl->guard.unlock();
impl->previous_fiber.reset();
impl->entry_point(impl->start_parameter);
UNREACHABLE();
}
void Fiber::OnRewind() {
ASSERT(impl->handle != nullptr);
DeleteFiber(impl->handle);
impl->handle = impl->rewind_handle;
impl->rewind_handle = nullptr;
impl->rewind_point(impl->rewind_parameter);
UNREACHABLE();
}
void Fiber::FiberStartFunc(void* fiber_parameter) {
auto* fiber = static_cast<Fiber*>(fiber_parameter);
fiber->Start();
}
void Fiber::RewindStartFunc(void* fiber_parameter) {
auto* fiber = static_cast<Fiber*>(fiber_parameter);
fiber->OnRewind();
}
Fiber::Fiber(std::function<void(void*)>&& entry_point_func, void* start_parameter)
: impl{std::make_unique<FiberImpl>()} {
impl->entry_point = std::move(entry_point_func);
impl->start_parameter = start_parameter;
impl->handle = CreateFiber(default_stack_size, &FiberStartFunc, this);
}
Fiber::Fiber() : impl{std::make_unique<FiberImpl>()} {}
Fiber::~Fiber() {
if (impl->released) {
return;
}
// Make sure the Fiber is not being used
const bool locked = impl->guard.try_lock();
ASSERT_MSG(locked, "Destroying a fiber that's still running");
if (locked) {
impl->guard.unlock();
}
DeleteFiber(impl->handle);
}
void Fiber::Exit() {
ASSERT_MSG(impl->is_thread_fiber, "Exitting non main thread fiber");
if (!impl->is_thread_fiber) {
return;
}
ConvertFiberToThread();
impl->guard.unlock();
impl->released = true;
}
void Fiber::Rewind() {
ASSERT(impl->rewind_point);
ASSERT(impl->rewind_handle == nullptr);
impl->rewind_handle = CreateFiber(default_stack_size, &RewindStartFunc, this);
SwitchToFiber(impl->rewind_handle);
}
void Fiber::YieldTo(std::shared_ptr<Fiber> from, std::shared_ptr<Fiber> to) {
ASSERT_MSG(from != nullptr, "Yielding fiber is null!");
ASSERT_MSG(to != nullptr, "Next fiber is null!");
to->impl->guard.lock();
to->impl->previous_fiber = from;
SwitchToFiber(to->impl->handle);
ASSERT(from->impl->previous_fiber != nullptr);
from->impl->previous_fiber->impl->guard.unlock();
from->impl->previous_fiber.reset();
}
std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
std::shared_ptr<Fiber> fiber = std::shared_ptr<Fiber>{new Fiber()};
fiber->impl->guard.lock();
fiber->impl->handle = ConvertThreadToFiber(nullptr);
fiber->impl->is_thread_fiber = true;
return fiber;
}
#else
void Fiber::Start(boost::context::detail::transfer_t& transfer) {
ASSERT(impl->previous_fiber != nullptr);
impl->previous_fiber->impl->context = transfer.fctx;
@@ -135,4 +229,5 @@ std::shared_ptr<Fiber> Fiber::ThreadToFiber() {
return fiber;
}
#endif
} // namespace Common

View File

@@ -7,9 +7,11 @@
#include <functional>
#include <memory>
#if !defined(_WIN32) && !defined(WIN32)
namespace boost::context::detail {
struct transfer_t;
}
#endif
namespace Common {
@@ -57,10 +59,17 @@ public:
private:
Fiber();
#if defined(_WIN32) || defined(WIN32)
void OnRewind();
void Start();
static void FiberStartFunc(void* fiber_parameter);
static void RewindStartFunc(void* fiber_parameter);
#else
void OnRewind(boost::context::detail::transfer_t& transfer);
void Start(boost::context::detail::transfer_t& transfer);
static void FiberStartFunc(boost::context::detail::transfer_t transfer);
static void RewindStartFunc(boost::context::detail::transfer_t transfer);
#endif
struct FiberImpl;
std::unique_ptr<FiberImpl> impl;

View File

@@ -0,0 +1,345 @@
// Copyright 2019 TuxSH
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <array>
#include <iterator>
#include <list>
#include <utility>
#include "common/bit_util.h"
#include "common/common_types.h"
namespace Common {
/**
* A MultiLevelQueue is a type of priority queue which has the following characteristics:
* - iteratable through each of its elements.
* - back can be obtained.
* - O(1) add, lookup (both front and back)
* - discrete priorities and a max of 64 priorities (limited domain)
* This type of priority queue is normaly used for managing threads within an scheduler
*/
template <typename T, std::size_t Depth>
class MultiLevelQueue {
public:
using value_type = T;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
using size_type = std::size_t;
template <bool is_constant>
class iterator_impl {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = T;
using pointer = std::conditional_t<is_constant, T*, const T*>;
using reference = std::conditional_t<is_constant, const T&, T&>;
using difference_type = typename std::pointer_traits<pointer>::difference_type;
friend bool operator==(const iterator_impl& lhs, const iterator_impl& rhs) {
if (lhs.IsEnd() && rhs.IsEnd())
return true;
return std::tie(lhs.current_priority, lhs.it) == std::tie(rhs.current_priority, rhs.it);
}
friend bool operator!=(const iterator_impl& lhs, const iterator_impl& rhs) {
return !operator==(lhs, rhs);
}
reference operator*() const {
return *it;
}
pointer operator->() const {
return it.operator->();
}
iterator_impl& operator++() {
if (IsEnd()) {
return *this;
}
++it;
if (it == GetEndItForPrio()) {
u64 prios = mlq.used_priorities;
prios &= ~((1ULL << (current_priority + 1)) - 1);
if (prios == 0) {
current_priority = static_cast<u32>(mlq.depth());
} else {
current_priority = CountTrailingZeroes64(prios);
it = GetBeginItForPrio();
}
}
return *this;
}
iterator_impl& operator--() {
if (IsEnd()) {
if (mlq.used_priorities != 0) {
current_priority = 63 - CountLeadingZeroes64(mlq.used_priorities);
it = GetEndItForPrio();
--it;
}
} else if (it == GetBeginItForPrio()) {
u64 prios = mlq.used_priorities;
prios &= (1ULL << current_priority) - 1;
if (prios != 0) {
current_priority = CountTrailingZeroes64(prios);
it = GetEndItForPrio();
--it;
}
} else {
--it;
}
return *this;
}
iterator_impl operator++(int) {
const iterator_impl v{*this};
++(*this);
return v;
}
iterator_impl operator--(int) {
const iterator_impl v{*this};
--(*this);
return v;
}
// allow implicit const->non-const
iterator_impl(const iterator_impl<false>& other)
: mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
iterator_impl(const iterator_impl<true>& other)
: mlq(other.mlq), it(other.it), current_priority(other.current_priority) {}
iterator_impl& operator=(const iterator_impl<false>& other) {
mlq = other.mlq;
it = other.it;
current_priority = other.current_priority;
return *this;
}
friend class iterator_impl<true>;
iterator_impl() = default;
private:
friend class MultiLevelQueue;
using container_ref =
std::conditional_t<is_constant, const MultiLevelQueue&, MultiLevelQueue&>;
using list_iterator = std::conditional_t<is_constant, typename std::list<T>::const_iterator,
typename std::list<T>::iterator>;
explicit iterator_impl(container_ref mlq, list_iterator it, u32 current_priority)
: mlq(mlq), it(it), current_priority(current_priority) {}
explicit iterator_impl(container_ref mlq, u32 current_priority)
: mlq(mlq), it(), current_priority(current_priority) {}
bool IsEnd() const {
return current_priority == mlq.depth();
}
list_iterator GetBeginItForPrio() const {
return mlq.levels[current_priority].begin();
}
list_iterator GetEndItForPrio() const {
return mlq.levels[current_priority].end();
}
container_ref mlq;
list_iterator it;
u32 current_priority;
};
using iterator = iterator_impl<false>;
using const_iterator = iterator_impl<true>;
void add(const T& element, u32 priority, bool send_back = true) {
if (send_back)
levels[priority].push_back(element);
else
levels[priority].push_front(element);
used_priorities |= 1ULL << priority;
}
void remove(const T& element, u32 priority) {
auto it = ListIterateTo(levels[priority], element);
if (it == levels[priority].end())
return;
levels[priority].erase(it);
if (levels[priority].empty()) {
used_priorities &= ~(1ULL << priority);
}
}
void adjust(const T& element, u32 old_priority, u32 new_priority, bool adjust_front = false) {
remove(element, old_priority);
add(element, new_priority, !adjust_front);
}
void adjust(const_iterator it, u32 old_priority, u32 new_priority, bool adjust_front = false) {
adjust(*it, old_priority, new_priority, adjust_front);
}
void transfer_to_front(const T& element, u32 priority, MultiLevelQueue& other) {
ListSplice(other.levels[priority], other.levels[priority].begin(), levels[priority],
ListIterateTo(levels[priority], element));
other.used_priorities |= 1ULL << priority;
if (levels[priority].empty()) {
used_priorities &= ~(1ULL << priority);
}
}
void transfer_to_front(const_iterator it, u32 priority, MultiLevelQueue& other) {
transfer_to_front(*it, priority, other);
}
void transfer_to_back(const T& element, u32 priority, MultiLevelQueue& other) {
ListSplice(other.levels[priority], other.levels[priority].end(), levels[priority],
ListIterateTo(levels[priority], element));
other.used_priorities |= 1ULL << priority;
if (levels[priority].empty()) {
used_priorities &= ~(1ULL << priority);
}
}
void transfer_to_back(const_iterator it, u32 priority, MultiLevelQueue& other) {
transfer_to_back(*it, priority, other);
}
void yield(u32 priority, std::size_t n = 1) {
ListShiftForward(levels[priority], n);
}
[[nodiscard]] std::size_t depth() const {
return Depth;
}
[[nodiscard]] std::size_t size(u32 priority) const {
return levels[priority].size();
}
[[nodiscard]] std::size_t size() const {
u64 priorities = used_priorities;
std::size_t size = 0;
while (priorities != 0) {
const u64 current_priority = CountTrailingZeroes64(priorities);
size += levels[current_priority].size();
priorities &= ~(1ULL << current_priority);
}
return size;
}
[[nodiscard]] bool empty() const {
return used_priorities == 0;
}
[[nodiscard]] bool empty(u32 priority) const {
return (used_priorities & (1ULL << priority)) == 0;
}
[[nodiscard]] u32 highest_priority_set(u32 max_priority = 0) const {
const u64 priorities =
max_priority == 0 ? used_priorities : (used_priorities & ~((1ULL << max_priority) - 1));
return priorities == 0 ? Depth : static_cast<u32>(CountTrailingZeroes64(priorities));
}
[[nodiscard]] u32 lowest_priority_set(u32 min_priority = Depth - 1) const {
const u64 priorities = min_priority >= Depth - 1
? used_priorities
: (used_priorities & ((1ULL << (min_priority + 1)) - 1));
return priorities == 0 ? Depth : 63 - CountLeadingZeroes64(priorities);
}
[[nodiscard]] const_iterator cbegin(u32 max_prio = 0) const {
const u32 priority = highest_priority_set(max_prio);
return priority == Depth ? cend()
: const_iterator{*this, levels[priority].cbegin(), priority};
}
[[nodiscard]] const_iterator begin(u32 max_prio = 0) const {
return cbegin(max_prio);
}
[[nodiscard]] iterator begin(u32 max_prio = 0) {
const u32 priority = highest_priority_set(max_prio);
return priority == Depth ? end() : iterator{*this, levels[priority].begin(), priority};
}
[[nodiscard]] const_iterator cend(u32 min_prio = Depth - 1) const {
return min_prio == Depth - 1 ? const_iterator{*this, Depth} : cbegin(min_prio + 1);
}
[[nodiscard]] const_iterator end(u32 min_prio = Depth - 1) const {
return cend(min_prio);
}
[[nodiscard]] iterator end(u32 min_prio = Depth - 1) {
return min_prio == Depth - 1 ? iterator{*this, Depth} : begin(min_prio + 1);
}
[[nodiscard]] T& front(u32 max_priority = 0) {
const u32 priority = highest_priority_set(max_priority);
return levels[priority == Depth ? 0 : priority].front();
}
[[nodiscard]] const T& front(u32 max_priority = 0) const {
const u32 priority = highest_priority_set(max_priority);
return levels[priority == Depth ? 0 : priority].front();
}
[[nodiscard]] T& back(u32 min_priority = Depth - 1) {
const u32 priority = lowest_priority_set(min_priority); // intended
return levels[priority == Depth ? 63 : priority].back();
}
[[nodiscard]] const T& back(u32 min_priority = Depth - 1) const {
const u32 priority = lowest_priority_set(min_priority); // intended
return levels[priority == Depth ? 63 : priority].back();
}
void clear() {
used_priorities = 0;
for (std::size_t i = 0; i < Depth; i++) {
levels[i].clear();
}
}
private:
using const_list_iterator = typename std::list<T>::const_iterator;
static void ListShiftForward(std::list<T>& list, const std::size_t shift = 1) {
if (shift >= list.size()) {
return;
}
const auto begin_range = list.begin();
const auto end_range = std::next(begin_range, shift);
list.splice(list.end(), list, begin_range, end_range);
}
static void ListSplice(std::list<T>& in_list, const_list_iterator position,
std::list<T>& out_list, const_list_iterator element) {
in_list.splice(position, out_list, element);
}
[[nodiscard]] static const_list_iterator ListIterateTo(const std::list<T>& list,
const T& element) {
auto it = list.cbegin();
while (it != list.cend() && *it != element) {
++it;
}
return it;
}
std::array<std::list<T>, Depth> levels;
u64 used_priorities = 0;
};
} // namespace Common

View File

@@ -10,7 +10,7 @@
namespace detail {
template <typename Func>
struct ScopeExitHelper {
explicit ScopeExitHelper(Func&& func_) : func(std::move(func_)) {}
explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {}
~ScopeExitHelper() {
if (active) {
func();

View File

@@ -52,8 +52,8 @@ public:
template <typename T>
class Field : public FieldInterface {
public:
Field(FieldType type_, std::string name_, T value_)
: name(std::move(name_)), type(type_), value(std::move(value_)) {}
Field(FieldType type, std::string name, T value)
: name(std::move(name)), type(type), value(std::move(value)) {}
Field(const Field&) = default;
Field& operator=(const Field&) = default;

View File

@@ -17,8 +17,8 @@ using base_time_point = std::chrono::time_point<base_timer>;
class StandardWallClock final : public WallClock {
public:
explicit StandardWallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_)
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, false) {
StandardWallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency)
: WallClock(emulated_cpu_frequency, emulated_clock_frequency, false) {
start_time = base_timer::now();
}

View File

@@ -38,9 +38,9 @@ public:
}
protected:
explicit WallClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_, bool is_native_)
: emulated_cpu_frequency{emulated_cpu_frequency_},
emulated_clock_frequency{emulated_clock_frequency_}, is_native{is_native_} {}
WallClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, bool is_native)
: emulated_cpu_frequency{emulated_cpu_frequency},
emulated_clock_frequency{emulated_clock_frequency}, is_native{is_native} {}
u64 emulated_cpu_frequency;
u64 emulated_clock_frequency;

View File

@@ -43,10 +43,10 @@ u64 EstimateRDTSCFrequency() {
}
namespace X64 {
NativeClock::NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
u64 rtsc_frequency_)
: WallClock(emulated_cpu_frequency_, emulated_clock_frequency_, true), rtsc_frequency{
rtsc_frequency_} {
NativeClock::NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency,
u64 rtsc_frequency)
: WallClock(emulated_cpu_frequency, emulated_clock_frequency, true), rtsc_frequency{
rtsc_frequency} {
_mm_mfence();
last_measure = __rdtsc();
accumulated_ticks = 0U;

View File

@@ -14,8 +14,7 @@ namespace Common {
namespace X64 {
class NativeClock final : public WallClock {
public:
explicit NativeClock(u64 emulated_cpu_frequency_, u64 emulated_clock_frequency_,
u64 rtsc_frequency_);
NativeClock(u64 emulated_cpu_frequency, u64 emulated_clock_frequency, u64 rtsc_frequency);
std::chrono::nanoseconds GetTimeNS() override;

View File

@@ -11,25 +11,25 @@
namespace Common::X64 {
constexpr size_t RegToIndex(const Xbyak::Reg& reg) {
constexpr std::size_t RegToIndex(const Xbyak::Reg& reg) {
using Kind = Xbyak::Reg::Kind;
ASSERT_MSG((reg.getKind() & (Kind::REG | Kind::XMM)) != 0,
"RegSet only support GPRs and XMM registers.");
ASSERT_MSG(reg.getIdx() < 16, "RegSet only supports XXM0-15.");
return static_cast<size_t>(reg.getIdx()) + (reg.getKind() == Kind::REG ? 0 : 16);
return reg.getIdx() + (reg.getKind() == Kind::REG ? 0 : 16);
}
constexpr Xbyak::Reg64 IndexToReg64(size_t reg_index) {
constexpr Xbyak::Reg64 IndexToReg64(std::size_t reg_index) {
ASSERT(reg_index < 16);
return Xbyak::Reg64(static_cast<int>(reg_index));
}
constexpr Xbyak::Xmm IndexToXmm(size_t reg_index) {
constexpr Xbyak::Xmm IndexToXmm(std::size_t reg_index) {
ASSERT(reg_index >= 16 && reg_index < 32);
return Xbyak::Xmm(static_cast<int>(reg_index - 16));
}
constexpr Xbyak::Reg IndexToReg(size_t reg_index) {
constexpr Xbyak::Reg IndexToReg(std::size_t reg_index) {
if (reg_index < 16) {
return IndexToReg64(reg_index);
} else {
@@ -182,7 +182,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b
size_t rsp_alignment, size_t needed_frame_size = 0) {
auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size);
for (size_t i = 0; i < regs.size(); ++i) {
for (std::size_t i = 0; i < regs.size(); ++i) {
if (regs[i] && ABI_ALL_GPRS[i]) {
code.push(IndexToReg64(i));
}
@@ -192,7 +192,7 @@ inline size_t ABI_PushRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::b
code.sub(code.rsp, frame_info.subtraction);
}
for (size_t i = 0; i < regs.size(); ++i) {
for (std::size_t i = 0; i < regs.size(); ++i) {
if (regs[i] && ABI_ALL_XMMS[i]) {
code.movaps(code.xword[code.rsp + frame_info.xmm_offset], IndexToXmm(i));
frame_info.xmm_offset += 0x10;
@@ -206,7 +206,7 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits
size_t rsp_alignment, size_t needed_frame_size = 0) {
auto frame_info = ABI_CalculateFrameSize(regs, rsp_alignment, needed_frame_size);
for (size_t i = 0; i < regs.size(); ++i) {
for (std::size_t i = 0; i < regs.size(); ++i) {
if (regs[i] && ABI_ALL_XMMS[i]) {
code.movaps(IndexToXmm(i), code.xword[code.rsp + frame_info.xmm_offset]);
frame_info.xmm_offset += 0x10;
@@ -218,8 +218,8 @@ inline void ABI_PopRegistersAndAdjustStack(Xbyak::CodeGenerator& code, std::bits
}
// GPRs need to be popped in reverse order
for (size_t j = 0; j < regs.size(); ++j) {
const size_t i = regs.size() - j - 1;
for (std::size_t j = 0; j < regs.size(); ++j) {
const std::size_t i = regs.size() - j - 1;
if (regs[i] && ABI_ALL_GPRS[i]) {
code.pop(IndexToReg64(i));
}

View File

@@ -41,7 +41,6 @@ add_library(core STATIC
file_sys/bis_factory.h
file_sys/card_image.cpp
file_sys/card_image.h
file_sys/common_funcs.h
file_sys/content_archive.cpp
file_sys/content_archive.h
file_sys/control_metadata.cpp
@@ -135,9 +134,9 @@ add_library(core STATIC
frontend/emu_window.h
frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h
frontend/input_interpreter.cpp
frontend/input_interpreter.h
frontend/input.h
gdbstub/gdbstub.cpp
gdbstub/gdbstub.h
hardware_interrupt_manager.cpp
hardware_interrupt_manager.h
hle/ipc.h
@@ -151,19 +150,10 @@ add_library(core STATIC
hle/kernel/code_set.cpp
hle/kernel/code_set.h
hle/kernel/errors.h
hle/kernel/global_scheduler_context.cpp
hle/kernel/global_scheduler_context.h
hle/kernel/handle_table.cpp
hle/kernel/handle_table.h
hle/kernel/hle_ipc.cpp
hle/kernel/hle_ipc.h
hle/kernel/k_affinity_mask.h
hle/kernel/k_priority_queue.h
hle/kernel/k_scheduler.cpp
hle/kernel/k_scheduler.h
hle/kernel/k_scheduler_lock.h
hle/kernel/k_scoped_lock.h
hle/kernel/k_scoped_scheduler_lock_and_sleep.h
hle/kernel/kernel.cpp
hle/kernel/kernel.h
hle/kernel/memory/address_space_info.cpp
@@ -198,6 +188,8 @@ add_library(core STATIC
hle/kernel/readable_event.h
hle/kernel/resource_limit.cpp
hle/kernel/resource_limit.h
hle/kernel/scheduler.cpp
hle/kernel/scheduler.h
hle/kernel/server_port.cpp
hle/kernel/server_port.h
hle/kernel/server_session.cpp

View File

@@ -64,25 +64,15 @@ public:
/// Step CPU by one instruction
virtual void Step() = 0;
/// Exits execution from a callback, the callback must rewind the stack
virtual void ExceptionalExit() = 0;
/// Clear all instruction cache
virtual void ClearInstructionCache() = 0;
/**
* Clear instruction cache range
* @param addr Start address of the cache range to clear
* @param size Size of the cache range to clear, starting at addr
*/
virtual void InvalidateCacheRange(VAddr addr, std::size_t size) = 0;
/**
* Notifies CPU emulation that the current page table has changed.
* @param new_page_table The new page table.
* @param new_address_space_size_in_bits The new usable size of the address space in bits.
* This can be either 32, 36, or 39 on official software.
*/
/// Notifies CPU emulation that the current page table has changed.
///
/// @param new_page_table The new page table.
/// @param new_address_space_size_in_bits The new usable size of the address space in bits.
/// This can be either 32, 36, or 39 on official software.
///
virtual void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) = 0;

View File

@@ -189,10 +189,6 @@ void ARM_Dynarmic_32::Run() {
jit->Run();
}
void ARM_Dynarmic_32::ExceptionalExit() {
jit->ExceptionalExit();
}
void ARM_Dynarmic_32::Step() {
jit->Step();
}
@@ -286,17 +282,7 @@ void ARM_Dynarmic_32::ClearInstructionCache() {
jit->ClearCache();
}
void ARM_Dynarmic_32::InvalidateCacheRange(VAddr addr, std::size_t size) {
if (!jit) {
return;
}
jit->InvalidateCacheRange(static_cast<u32>(addr), size);
}
void ARM_Dynarmic_32::ClearExclusiveState() {
if (!jit) {
return;
}
jit->ClearExclusiveState();
}

View File

@@ -42,7 +42,6 @@ public:
u32 GetPSTATE() const override;
void SetPSTATE(u32 pstate) override;
void Run() override;
void ExceptionalExit() override;
void Step() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
@@ -59,7 +58,6 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;

View File

@@ -14,9 +14,10 @@
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/svc.h"
#include "core/memory.h"
#include "core/settings.h"
@@ -95,6 +96,16 @@ public:
case Dynarmic::A64::Exception::Yield:
return;
case Dynarmic::A64::Exception::Breakpoint:
if (GDBStub::IsServerEnabled()) {
parent.jit->HaltExecution();
parent.SetPC(pc);
Kernel::Thread* const thread = parent.system.CurrentScheduler().GetCurrentThread();
parent.SaveContext(thread->GetContext64());
GDBStub::Break();
GDBStub::SendTrap(thread, 5);
return;
}
[[fallthrough]];
default:
ASSERT_MSG(false, "ExceptionRaised(exception = {}, pc = {:08X}, code = {:08X})",
static_cast<std::size_t>(exception), pc, MemoryReadCode(pc));
@@ -220,10 +231,6 @@ void ARM_Dynarmic_64::Run() {
jit->Run();
}
void ARM_Dynarmic_64::ExceptionalExit() {
jit->ExceptionalExit();
}
void ARM_Dynarmic_64::Step() {
cb->InterpreterFallback(jit->GetPC(), 1);
}
@@ -322,17 +329,7 @@ void ARM_Dynarmic_64::ClearInstructionCache() {
jit->ClearCache();
}
void ARM_Dynarmic_64::InvalidateCacheRange(VAddr addr, std::size_t size) {
if (!jit) {
return;
}
jit->InvalidateCacheRange(addr, size);
}
void ARM_Dynarmic_64::ClearExclusiveState() {
if (!jit) {
return;
}
jit->ClearExclusiveState();
}

View File

@@ -40,7 +40,6 @@ public:
void SetPSTATE(u32 pstate) override;
void Run() override;
void Step() override;
void ExceptionalExit() override;
VAddr GetTlsAddress() const override;
void SetTlsAddress(VAddr address) override;
void SetTPIDR_EL0(u64 value) override;
@@ -56,7 +55,6 @@ public:
void ClearExclusiveState() override;
void ClearInstructionCache() override;
void InvalidateCacheRange(VAddr addr, std::size_t size) override;
void PageTableChanged(Common::PageTable& new_page_table,
std::size_t new_address_space_size_in_bits) override;

View File

@@ -25,12 +25,13 @@
#include "core/file_sys/sdmc_factory.h"
#include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hardware_interrupt_manager.h"
#include "core/hle/kernel/client_port.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/process.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/apm/controller.h"
@@ -91,43 +92,33 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
std::string dir_name;
std::string filename;
Common::SplitPath(path, &dir_name, &filename, nullptr);
if (filename == "00") {
const auto dir = vfs->OpenDirectory(dir_name, FileSys::Mode::Read);
std::vector<FileSys::VirtualFile> concat;
for (u32 i = 0; i < 0x10; ++i) {
const auto file_name = fmt::format("{:02X}", i);
auto next = dir->GetFile(file_name);
if (next != nullptr) {
for (u8 i = 0; i < 0x10; ++i) {
auto next = dir->GetFile(fmt::format("{:02X}", i));
if (next != nullptr)
concat.push_back(std::move(next));
} else {
next = dir->GetFile(file_name);
if (next == nullptr) {
else {
next = dir->GetFile(fmt::format("{:02x}", i));
if (next != nullptr)
concat.push_back(std::move(next));
else
break;
}
concat.push_back(std::move(next));
}
}
if (concat.empty()) {
if (concat.empty())
return nullptr;
}
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(std::move(concat),
dir->GetName());
return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName());
}
if (Common::FS::IsDirectory(path)) {
return vfs->OpenFile(path + "/main", FileSys::Mode::Read);
}
if (Common::FS::IsDirectory(path))
return vfs->OpenFile(path + "/" + "main", FileSys::Mode::Read);
return vfs->OpenFile(path, FileSys::Mode::Read);
}
struct System::Impl {
explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system},
@@ -154,7 +145,7 @@ struct System::Impl {
}
ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) {
LOG_DEBUG(Core, "initialized OK");
LOG_DEBUG(HW_Memory, "initialized OK");
device_memory = std::make_unique<Core::DeviceMemory>();
@@ -195,8 +186,11 @@ struct System::Impl {
}
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
services = std::make_unique<Service::Services>(service_manager, system);
interrupt_manager = std::make_unique<Hardware::InterruptManager>(system);
GDBStub::DeferStart();
interrupt_manager = std::make_unique<Core::Hardware::InterruptManager>(system);
// Initialize time manager, which must happen after kernel is created
time_manager.Initialize();
@@ -214,11 +208,9 @@ struct System::Impl {
return ResultStatus::Success;
}
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, const std::string& filepath,
std::size_t program_index) {
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
program_index);
ResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath) {
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath));
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return ResultStatus::ErrorGetLoader;
@@ -237,7 +229,7 @@ struct System::Impl {
Kernel::Process::Create(system, "main", Kernel::Process::ProcessType::Userland);
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", static_cast<int>(load_result));
Shutdown();
return static_cast<ResultStatus>(static_cast<u32>(ResultStatus::ErrorLoader) +
@@ -245,7 +237,6 @@ struct System::Impl {
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
kernel.MakeCurrentProcess(main_process.get());
kernel.InitializeCores();
// Initialize cheat engine
if (cheat_engine) {
@@ -267,7 +258,8 @@ struct System::Impl {
u64 title_id{0};
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})", load_result);
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
static_cast<u32>(load_result));
}
perf_stats = std::make_unique<PerfStats>(title_id);
// Reset counters and set time origin to current frame
@@ -303,6 +295,7 @@ struct System::Impl {
}
// Shutdown emulation session
GDBStub::Shutdown();
services.reset();
service_manager.reset();
cheat_engine.reset();
@@ -423,8 +416,6 @@ struct System::Impl {
bool is_multicore{};
bool is_async_gpu{};
ExecuteProgramCallback execute_program_callback;
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_dynarmic{};
};
@@ -456,17 +447,8 @@ void System::InvalidateCpuInstructionCaches() {
impl->kernel.InvalidateAllInstructionCaches();
}
void System::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
impl->kernel.InvalidateCpuInstructionCacheRange(addr, size);
}
void System::Shutdown() {
impl->Shutdown();
}
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
std::size_t program_index) {
return impl->Load(*this, emu_window, filepath, program_index);
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
return impl->Load(*this, emu_window, filepath);
}
bool System::IsPoweredOn() const {
@@ -494,11 +476,11 @@ const TelemetrySession& System::TelemetrySession() const {
}
ARM_Interface& System::CurrentArmInterface() {
return impl->kernel.CurrentPhysicalCore().ArmInterface();
return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface();
}
const ARM_Interface& System::CurrentArmInterface() const {
return impl->kernel.CurrentPhysicalCore().ArmInterface();
return impl->kernel.CurrentScheduler().GetCurrentThread()->ArmInterface();
}
std::size_t System::CurrentCoreIndex() const {
@@ -507,6 +489,14 @@ std::size_t System::CurrentCoreIndex() const {
return core;
}
Kernel::Scheduler& System::CurrentScheduler() {
return impl->kernel.CurrentScheduler();
}
const Kernel::Scheduler& System::CurrentScheduler() const {
return impl->kernel.CurrentScheduler();
}
Kernel::PhysicalCore& System::CurrentPhysicalCore() {
return impl->kernel.CurrentPhysicalCore();
}
@@ -515,14 +505,22 @@ const Kernel::PhysicalCore& System::CurrentPhysicalCore() const {
return impl->kernel.CurrentPhysicalCore();
}
/// Gets the global scheduler
Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() {
return impl->kernel.GlobalSchedulerContext();
Kernel::Scheduler& System::Scheduler(std::size_t core_index) {
return impl->kernel.Scheduler(core_index);
}
const Kernel::Scheduler& System::Scheduler(std::size_t core_index) const {
return impl->kernel.Scheduler(core_index);
}
/// Gets the global scheduler
const Kernel::GlobalSchedulerContext& System::GlobalSchedulerContext() const {
return impl->kernel.GlobalSchedulerContext();
Kernel::GlobalScheduler& System::GlobalScheduler() {
return impl->kernel.GlobalScheduler();
}
/// Gets the global scheduler
const Kernel::GlobalScheduler& System::GlobalScheduler() const {
return impl->kernel.GlobalScheduler();
}
Kernel::Process* System::CurrentProcess() {
@@ -542,11 +540,15 @@ const Kernel::Process* System::CurrentProcess() const {
}
ARM_Interface& System::ArmInterface(std::size_t core_index) {
return impl->kernel.PhysicalCore(core_index).ArmInterface();
auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread();
ASSERT(thread && !thread->IsHLEThread());
return thread->ArmInterface();
}
const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
return impl->kernel.PhysicalCore(core_index).ArmInterface();
auto* thread = impl->kernel.Scheduler(core_index).GetCurrentThread();
ASSERT(thread && !thread->IsHLEThread());
return thread->ArmInterface();
}
ExclusiveMonitor& System::Monitor() {
@@ -633,11 +635,7 @@ const std::string& System::GetStatusDetails() const {
return impl->status_details;
}
Loader::AppLoader& System::GetAppLoader() {
return *impl->app_loader;
}
const Loader::AppLoader& System::GetAppLoader() const {
Loader::AppLoader& System::GetAppLoader() const {
return *impl->app_loader;
}
@@ -753,6 +751,14 @@ const System::CurrentBuildProcessID& System::GetCurrentProcessBuildID() const {
return impl->build_id;
}
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
return impl->Init(*this, emu_window);
}
void System::Shutdown() {
impl->Shutdown();
}
Service::SM::ServiceManager& System::ServiceManager() {
return *impl->service_manager;
}
@@ -783,16 +789,4 @@ bool System::IsMulticore() const {
return impl->is_multicore;
}
void System::RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback) {
impl->execute_program_callback = std::move(callback);
}
void System::ExecuteProgram(std::size_t program_index) {
if (impl->execute_program_callback) {
impl->execute_program_callback(program_index);
} else {
LOG_CRITICAL(Core, "execute_program_callback must be initialized by the frontend");
}
}
} // namespace Core

View File

@@ -5,7 +5,6 @@
#pragma once
#include <cstddef>
#include <functional>
#include <memory>
#include <string>
#include <vector>
@@ -26,11 +25,11 @@ class VfsFilesystem;
} // namespace FileSys
namespace Kernel {
class GlobalSchedulerContext;
class GlobalScheduler;
class KernelCore;
class PhysicalCore;
class Process;
class KScheduler;
class Scheduler;
} // namespace Kernel
namespace Loader {
@@ -145,19 +144,19 @@ public:
* Run the OS and Application
* This function will start emulation and run the relevant devices
*/
[[nodiscard]] ResultStatus Run();
ResultStatus Run();
/**
* Pause the OS and Application
* This function will pause emulation and stop the relevant devices
*/
[[nodiscard]] ResultStatus Pause();
ResultStatus Pause();
/**
* Step the CPU one instruction
* @return Result status, indicating whether or not the operation succeeded.
*/
[[nodiscard]] ResultStatus SingleStep();
ResultStatus SingleStep();
/**
* Invalidate the CPU instruction caches
@@ -166,8 +165,6 @@ public:
*/
void InvalidateCpuInstructionCaches();
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);
/// Shutdown the emulated system.
void Shutdown();
@@ -176,24 +173,22 @@ public:
* @param emu_window Reference to the host-system window used for video output and keyboard
* input.
* @param filepath String path to the executable application to load on the host file system.
* @param program_index Specifies the index within the container of the program to launch.
* @returns ResultStatus code, indicating if the operation succeeded.
*/
[[nodiscard]] ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath,
std::size_t program_index = 0);
ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath);
/**
* Indicates if the emulated system is powered on (all subsystems initialized and able to run an
* application).
* @returns True if the emulated system is powered on, otherwise false.
*/
[[nodiscard]] bool IsPoweredOn() const;
bool IsPoweredOn() const;
/// Gets a reference to the telemetry session for this emulation session.
[[nodiscard]] Core::TelemetrySession& TelemetrySession();
Core::TelemetrySession& TelemetrySession();
/// Gets a reference to the telemetry session for this emulation session.
[[nodiscard]] const Core::TelemetrySession& TelemetrySession() const;
const Core::TelemetrySession& TelemetrySession() const;
/// Prepare the core emulation for a reschedule
void PrepareReschedule();
@@ -202,166 +197,185 @@ public:
void PrepareReschedule(u32 core_index);
/// Gets and resets core performance statistics
[[nodiscard]] PerfStatsResults GetAndResetPerfStats();
PerfStatsResults GetAndResetPerfStats();
/// Gets an ARM interface to the CPU core that is currently running
[[nodiscard]] ARM_Interface& CurrentArmInterface();
ARM_Interface& CurrentArmInterface();
/// Gets an ARM interface to the CPU core that is currently running
[[nodiscard]] const ARM_Interface& CurrentArmInterface() const;
const ARM_Interface& CurrentArmInterface() const;
/// Gets the index of the currently running CPU core
[[nodiscard]] std::size_t CurrentCoreIndex() const;
std::size_t CurrentCoreIndex() const;
/// Gets the scheduler for the CPU core that is currently running
Kernel::Scheduler& CurrentScheduler();
/// Gets the scheduler for the CPU core that is currently running
const Kernel::Scheduler& CurrentScheduler() const;
/// Gets the physical core for the CPU core that is currently running
[[nodiscard]] Kernel::PhysicalCore& CurrentPhysicalCore();
Kernel::PhysicalCore& CurrentPhysicalCore();
/// Gets the physical core for the CPU core that is currently running
[[nodiscard]] const Kernel::PhysicalCore& CurrentPhysicalCore() const;
const Kernel::PhysicalCore& CurrentPhysicalCore() const;
/// Gets a reference to an ARM interface for the CPU core with the specified index
[[nodiscard]] ARM_Interface& ArmInterface(std::size_t core_index);
ARM_Interface& ArmInterface(std::size_t core_index);
/// Gets a const reference to an ARM interface from the CPU core with the specified index
[[nodiscard]] const ARM_Interface& ArmInterface(std::size_t core_index) const;
const ARM_Interface& ArmInterface(std::size_t core_index) const;
/// Gets a reference to the underlying CPU manager.
[[nodiscard]] CpuManager& GetCpuManager();
CpuManager& GetCpuManager();
/// Gets a const reference to the underlying CPU manager
[[nodiscard]] const CpuManager& GetCpuManager() const;
const CpuManager& GetCpuManager() const;
/// Gets a reference to the exclusive monitor
[[nodiscard]] ExclusiveMonitor& Monitor();
ExclusiveMonitor& Monitor();
/// Gets a constant reference to the exclusive monitor
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance.
[[nodiscard]] Core::Memory::Memory& Memory();
Core::Memory::Memory& Memory();
/// Gets a constant reference to the system memory instance.
[[nodiscard]] const Core::Memory::Memory& Memory() const;
const Core::Memory::Memory& Memory() const;
/// Gets a mutable reference to the GPU interface
[[nodiscard]] Tegra::GPU& GPU();
Tegra::GPU& GPU();
/// Gets an immutable reference to the GPU interface.
[[nodiscard]] const Tegra::GPU& GPU() const;
const Tegra::GPU& GPU() const;
/// Gets a mutable reference to the renderer.
[[nodiscard]] VideoCore::RendererBase& Renderer();
VideoCore::RendererBase& Renderer();
/// Gets an immutable reference to the renderer.
[[nodiscard]] const VideoCore::RendererBase& Renderer() const;
const VideoCore::RendererBase& Renderer() const;
/// Gets the scheduler for the CPU core with the specified index
Kernel::Scheduler& Scheduler(std::size_t core_index);
/// Gets the scheduler for the CPU core with the specified index
const Kernel::Scheduler& Scheduler(std::size_t core_index) const;
/// Gets the global scheduler
[[nodiscard]] Kernel::GlobalSchedulerContext& GlobalSchedulerContext();
Kernel::GlobalScheduler& GlobalScheduler();
/// Gets the global scheduler
[[nodiscard]] const Kernel::GlobalSchedulerContext& GlobalSchedulerContext() const;
const Kernel::GlobalScheduler& GlobalScheduler() const;
/// Gets the manager for the guest device memory
[[nodiscard]] Core::DeviceMemory& DeviceMemory();
Core::DeviceMemory& DeviceMemory();
/// Gets the manager for the guest device memory
[[nodiscard]] const Core::DeviceMemory& DeviceMemory() const;
const Core::DeviceMemory& DeviceMemory() const;
/// Provides a pointer to the current process
[[nodiscard]] Kernel::Process* CurrentProcess();
Kernel::Process* CurrentProcess();
/// Provides a constant pointer to the current process.
[[nodiscard]] const Kernel::Process* CurrentProcess() const;
const Kernel::Process* CurrentProcess() const;
/// Provides a reference to the core timing instance.
[[nodiscard]] Timing::CoreTiming& CoreTiming();
Timing::CoreTiming& CoreTiming();
/// Provides a constant reference to the core timing instance.
[[nodiscard]] const Timing::CoreTiming& CoreTiming() const;
const Timing::CoreTiming& CoreTiming() const;
/// Provides a reference to the interrupt manager instance.
[[nodiscard]] Core::Hardware::InterruptManager& InterruptManager();
Core::Hardware::InterruptManager& InterruptManager();
/// Provides a constant reference to the interrupt manager instance.
[[nodiscard]] const Core::Hardware::InterruptManager& InterruptManager() const;
const Core::Hardware::InterruptManager& InterruptManager() const;
/// Provides a reference to the kernel instance.
[[nodiscard]] Kernel::KernelCore& Kernel();
Kernel::KernelCore& Kernel();
/// Provides a constant reference to the kernel instance.
[[nodiscard]] const Kernel::KernelCore& Kernel() const;
const Kernel::KernelCore& Kernel() const;
/// Provides a reference to the internal PerfStats instance.
[[nodiscard]] Core::PerfStats& GetPerfStats();
Core::PerfStats& GetPerfStats();
/// Provides a constant reference to the internal PerfStats instance.
[[nodiscard]] const Core::PerfStats& GetPerfStats() const;
const Core::PerfStats& GetPerfStats() const;
/// Provides a reference to the frame limiter;
[[nodiscard]] Core::FrameLimiter& FrameLimiter();
Core::FrameLimiter& FrameLimiter();
/// Provides a constant referent to the frame limiter
[[nodiscard]] const Core::FrameLimiter& FrameLimiter() const;
const Core::FrameLimiter& FrameLimiter() const;
/// Gets the name of the current game
[[nodiscard]] Loader::ResultStatus GetGameName(std::string& out) const;
Loader::ResultStatus GetGameName(std::string& out) const;
void SetStatus(ResultStatus new_status, const char* details);
[[nodiscard]] const std::string& GetStatusDetails() const;
const std::string& GetStatusDetails() const;
[[nodiscard]] Loader::AppLoader& GetAppLoader();
[[nodiscard]] const Loader::AppLoader& GetAppLoader() const;
Loader::AppLoader& GetAppLoader() const;
[[nodiscard]] Service::SM::ServiceManager& ServiceManager();
[[nodiscard]] const Service::SM::ServiceManager& ServiceManager() const;
Service::SM::ServiceManager& ServiceManager();
const Service::SM::ServiceManager& ServiceManager() const;
void SetFilesystem(FileSys::VirtualFilesystem vfs);
[[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
FileSys::VirtualFilesystem GetFilesystem() const;
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
u64 main_region_size);
void SetAppletFrontendSet(Service::AM::Applets::AppletFrontendSet&& set);
void SetDefaultAppletFrontendSet();
[[nodiscard]] Service::AM::Applets::AppletManager& GetAppletManager();
[[nodiscard]] const Service::AM::Applets::AppletManager& GetAppletManager() const;
Service::AM::Applets::AppletManager& GetAppletManager();
const Service::AM::Applets::AppletManager& GetAppletManager() const;
void SetContentProvider(std::unique_ptr<FileSys::ContentProviderUnion> provider);
[[nodiscard]] FileSys::ContentProvider& GetContentProvider();
[[nodiscard]] const FileSys::ContentProvider& GetContentProvider() const;
FileSys::ContentProvider& GetContentProvider();
[[nodiscard]] Service::FileSystem::FileSystemController& GetFileSystemController();
[[nodiscard]] const Service::FileSystem::FileSystemController& GetFileSystemController() const;
const FileSys::ContentProvider& GetContentProvider() const;
Service::FileSystem::FileSystemController& GetFileSystemController();
const Service::FileSystem::FileSystemController& GetFileSystemController() const;
void RegisterContentProvider(FileSys::ContentProviderUnionSlot slot,
FileSys::ContentProvider* provider);
void ClearContentProvider(FileSys::ContentProviderUnionSlot slot);
[[nodiscard]] const Reporter& GetReporter() const;
const Reporter& GetReporter() const;
[[nodiscard]] Service::Glue::ARPManager& GetARPManager();
[[nodiscard]] const Service::Glue::ARPManager& GetARPManager() const;
Service::Glue::ARPManager& GetARPManager();
[[nodiscard]] Service::APM::Controller& GetAPMController();
[[nodiscard]] const Service::APM::Controller& GetAPMController() const;
const Service::Glue::ARPManager& GetARPManager() const;
[[nodiscard]] Service::LM::Manager& GetLogManager();
[[nodiscard]] const Service::LM::Manager& GetLogManager() const;
Service::APM::Controller& GetAPMController();
[[nodiscard]] Service::Time::TimeManager& GetTimeManager();
[[nodiscard]] const Service::Time::TimeManager& GetTimeManager() const;
const Service::APM::Controller& GetAPMController() const;
Service::LM::Manager& GetLogManager();
const Service::LM::Manager& GetLogManager() const;
Service::Time::TimeManager& GetTimeManager();
const Service::Time::TimeManager& GetTimeManager() const;
void SetExitLock(bool locked);
[[nodiscard]] bool GetExitLock() const;
bool GetExitLock() const;
void SetCurrentProcessBuildID(const CurrentBuildProcessID& id);
[[nodiscard]] const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
const CurrentBuildProcessID& GetCurrentProcessBuildID() const;
/// Register a host thread as an emulated CPU Core.
void RegisterCoreThread(std::size_t id);
@@ -376,28 +390,19 @@ public:
void ExitDynarmicProfile();
/// Tells if system is running on multicore.
[[nodiscard]] bool IsMulticore() const;
/// Type used for the frontend to designate a callback for System to re-launch the application
/// using a specified program index.
using ExecuteProgramCallback = std::function<void(std::size_t)>;
/**
* Registers a callback from the frontend for System to re-launch the application using a
* specified program index.
* @param callback Callback from the frontend to relaunch the application.
*/
void RegisterExecuteProgramCallback(ExecuteProgramCallback&& callback);
/**
* Instructs the frontend to re-launch the application using the specified program_index.
* @param program_index Specifies the index within the application of the program to launch.
*/
void ExecuteProgram(std::size_t program_index);
bool IsMulticore() const;
private:
System();
/**
* Initialize the emulated system.
* @param emu_window Reference to the host-system window used for video output and keyboard
* input.
* @return ResultStatus code, indicating if the operation succeeded.
*/
ResultStatus Init(Frontend::EmuWindow& emu_window);
struct Impl;
std::unique_ptr<Impl> impl;

View File

@@ -27,8 +27,8 @@ using TimedCallback =
/// Contains the characteristics of a particular event.
struct EventType {
explicit EventType(TimedCallback&& callback_, std::string&& name_)
: callback{std::move(callback_)}, name{std::move(name_)} {}
EventType(TimedCallback&& callback, std::string&& name)
: callback{std::move(callback)}, name{std::move(name)} {}
/// The event's callback function.
TimedCallback callback;
@@ -67,8 +67,8 @@ public:
void Shutdown();
/// Sets if emulation is multicore or single core, must be set before Initialize
void SetMulticore(bool is_multicore_) {
is_multicore = is_multicore_;
void SetMulticore(bool is_multicore) {
this->is_multicore = is_multicore;
}
/// Check if it's using host timing.

View File

@@ -4,15 +4,15 @@
#include "common/fiber.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "common/thread.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/cpu_manager.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/gdbstub/gdbstub.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/kernel/physical_core.h"
#include "core/hle/kernel/scheduler.h"
#include "core/hle/kernel/thread.h"
#include "video_core/gpu.h"
@@ -109,26 +109,28 @@ void* CpuManager::GetStartFuncParamater() {
void CpuManager::MultiCoreRunGuestThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
auto& host_context = thread->GetHostContext();
host_context->SetRewindPoint(GuestRewindFunction, this);
{
auto& sched = kernel.CurrentScheduler();
sched.OnThreadStart();
}
MultiCoreRunGuestLoop();
}
void CpuManager::MultiCoreRunGuestLoop() {
auto& kernel = system.Kernel();
auto* thread = kernel.CurrentScheduler().GetCurrentThread();
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
auto& arm_interface = thread->ArmInterface();
system.EnterDynarmicProfile();
while (!physical_core->IsInterrupted()) {
physical_core->Run();
arm_interface.Run();
physical_core = &kernel.CurrentPhysicalCore();
}
system.ExitDynarmicProfile();
physical_core->ArmInterface().ClearExclusiveState();
kernel.CurrentScheduler()->RescheduleCurrentCore();
arm_interface.ClearExclusiveState();
auto& scheduler = kernel.CurrentScheduler();
scheduler.TryDoContextSwitch();
}
}
@@ -137,21 +139,25 @@ void CpuManager::MultiCoreRunIdleThread() {
while (true) {
auto& physical_core = kernel.CurrentPhysicalCore();
physical_core.Idle();
kernel.CurrentScheduler()->RescheduleCurrentCore();
auto& scheduler = kernel.CurrentScheduler();
scheduler.TryDoContextSwitch();
}
}
void CpuManager::MultiCoreRunSuspendThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
{
auto& sched = kernel.CurrentScheduler();
sched.OnThreadStart();
}
while (true) {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
auto& scheduler = kernel.CurrentScheduler();
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[core].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
scheduler.RescheduleCurrentCore();
scheduler.TryDoContextSwitch();
}
}
@@ -199,31 +205,32 @@ void CpuManager::MultiCorePause(bool paused) {
void CpuManager::SingleCoreRunGuestThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
auto& host_context = thread->GetHostContext();
host_context->SetRewindPoint(GuestRewindFunction, this);
{
auto& sched = kernel.CurrentScheduler();
sched.OnThreadStart();
}
SingleCoreRunGuestLoop();
}
void CpuManager::SingleCoreRunGuestLoop() {
auto& kernel = system.Kernel();
auto* thread = kernel.CurrentScheduler()->GetCurrentThread();
auto* thread = kernel.CurrentScheduler().GetCurrentThread();
while (true) {
auto* physical_core = &kernel.CurrentPhysicalCore();
auto& arm_interface = thread->ArmInterface();
system.EnterDynarmicProfile();
if (!physical_core->IsInterrupted()) {
physical_core->Run();
arm_interface.Run();
physical_core = &kernel.CurrentPhysicalCore();
}
system.ExitDynarmicProfile();
thread->SetPhantomMode(true);
system.CoreTiming().Advance();
thread->SetPhantomMode(false);
physical_core->ArmInterface().ClearExclusiveState();
arm_interface.ClearExclusiveState();
PreemptSingleCore();
auto& scheduler = kernel.Scheduler(current_core);
scheduler.RescheduleCurrentCore();
scheduler.TryDoContextSwitch();
}
}
@@ -235,53 +242,51 @@ void CpuManager::SingleCoreRunIdleThread() {
system.CoreTiming().AddTicks(1000U);
idle_count++;
auto& scheduler = physical_core.Scheduler();
scheduler.RescheduleCurrentCore();
scheduler.TryDoContextSwitch();
}
}
void CpuManager::SingleCoreRunSuspendThread() {
auto& kernel = system.Kernel();
kernel.CurrentScheduler()->OnThreadStart();
{
auto& sched = kernel.CurrentScheduler();
sched.OnThreadStart();
}
while (true) {
auto core = kernel.GetCurrentHostThreadID();
auto& scheduler = *kernel.CurrentScheduler();
auto& scheduler = kernel.CurrentScheduler();
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
Common::Fiber::YieldTo(current_thread->GetHostContext(), core_data[0].host_context);
ASSERT(scheduler.ContextSwitchPending());
ASSERT(core == kernel.GetCurrentHostThreadID());
scheduler.RescheduleCurrentCore();
scheduler.TryDoContextSwitch();
}
}
void CpuManager::PreemptSingleCore(bool from_running_enviroment) {
{
auto& scheduler = system.Kernel().Scheduler(current_core);
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
if (idle_count >= 4 || from_running_enviroment) {
if (!from_running_enviroment) {
system.CoreTiming().Idle();
idle_count = 0;
}
current_thread->SetPhantomMode(true);
system.CoreTiming().Advance();
current_thread->SetPhantomMode(false);
}
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
system.CoreTiming().ResetTicks();
scheduler.Unload(scheduler.GetCurrentThread());
auto& next_scheduler = system.Kernel().Scheduler(current_core);
Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
}
// May have changed scheduler
{
auto& scheduler = system.Kernel().Scheduler(current_core);
scheduler.Reload(scheduler.GetCurrentThread());
auto* currrent_thread2 = scheduler.GetCurrentThread();
if (!currrent_thread2->IsIdleThread()) {
std::size_t old_core = current_core;
auto& scheduler = system.Kernel().Scheduler(old_core);
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
if (idle_count >= 4 || from_running_enviroment) {
if (!from_running_enviroment) {
system.CoreTiming().Idle();
idle_count = 0;
}
current_thread->SetPhantomMode(true);
system.CoreTiming().Advance();
current_thread->SetPhantomMode(false);
}
current_core.store((current_core + 1) % Core::Hardware::NUM_CPU_CORES);
system.CoreTiming().ResetTicks();
scheduler.Unload();
auto& next_scheduler = system.Kernel().Scheduler(current_core);
Common::Fiber::YieldTo(current_thread->GetHostContext(), next_scheduler.ControlContext());
/// May have changed scheduler
auto& current_scheduler = system.Kernel().Scheduler(current_core);
current_scheduler.Reload();
auto* currrent_thread2 = current_scheduler.GetCurrentThread();
if (!currrent_thread2->IsIdleThread()) {
idle_count = 0;
}
}
@@ -338,16 +343,6 @@ void CpuManager::RunThread(std::size_t core) {
data.initialized = true;
const bool sc_sync = !is_async_gpu && !is_multicore;
bool sc_sync_first_use = sc_sync;
// Cleanup
SCOPE_EXIT({
data.host_context->Exit();
data.enter_barrier.reset();
data.exit_barrier.reset();
data.initialized = false;
MicroProfileOnThreadExit();
});
/// Running
while (running_mode) {
data.is_running = false;
@@ -356,13 +351,8 @@ void CpuManager::RunThread(std::size_t core) {
system.GPU().ObtainContext();
sc_sync_first_use = false;
}
// Abort if emulation was killed before the session really starts
if (!system.IsPoweredOn()) {
return;
}
auto current_thread = system.Kernel().CurrentScheduler()->GetCurrentThread();
auto& scheduler = system.Kernel().CurrentScheduler();
Kernel::Thread* current_thread = scheduler.GetCurrentThread();
data.is_running = true;
Common::Fiber::YieldTo(data.host_context, current_thread->GetHostContext());
data.is_running = false;
@@ -370,6 +360,13 @@ void CpuManager::RunThread(std::size_t core) {
data.exit_barrier->Wait();
data.is_paused = false;
}
/// Time to cleanup
data.host_context->Exit();
data.enter_barrier.reset();
data.exit_barrier.reset();
data.initialized = false;
MicroProfileOnThreadExit();
}
} // namespace Core

View File

@@ -29,7 +29,7 @@ constexpr std::array partition_names{
"logo",
};
XCI::XCI(VirtualFile file_, std::size_t program_index)
XCI::XCI(VirtualFile file_)
: file(std::move(file_)), program_nca_status{Loader::ResultStatus::ErrorXCIMissingProgramNCA},
partitions(partition_names.size()),
partitions_raw(partition_names.size()), keys{Core::Crypto::KeyManager::Instance()} {
@@ -62,8 +62,7 @@ XCI::XCI(VirtualFile file_, std::size_t program_index)
}
secure_partition = std::make_shared<NSP>(
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]),
program_index);
main_hfs.GetFile(partition_names[static_cast<std::size_t>(XCIPartition::Secure)]));
ncas = secure_partition->GetNCAsCollapsed();
program =

View File

@@ -78,7 +78,7 @@ enum class XCIPartition : u8 { Update, Normal, Secure, Logo };
class XCI : public ReadOnlyVfsDirectory {
public:
explicit XCI(VirtualFile file, std::size_t program_index = 0);
explicit XCI(VirtualFile file);
~XCI() override;
Loader::ResultStatus GetStatus() const;

View File

@@ -1,56 +0,0 @@
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace FileSys {
constexpr u64 AOC_TITLE_ID_MASK = 0x7FF;
constexpr u64 AOC_TITLE_ID_OFFSET = 0x1000;
constexpr u64 BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
/**
* Gets the base title ID from a given title ID.
*
* @param title_id The title ID.
* @returns The base title ID.
*/
[[nodiscard]] constexpr u64 GetBaseTitleID(u64 title_id) {
return title_id & BASE_TITLE_ID_MASK;
}
/**
* Gets the base title ID with a program index offset from a given title ID.
*
* @param title_id The title ID.
* @param program_index The program index.
* @returns The base title ID with a program index offset.
*/
[[nodiscard]] constexpr u64 GetBaseTitleIDWithProgramIndex(u64 title_id, u64 program_index) {
return GetBaseTitleID(title_id) + program_index;
}
/**
* Gets the AOC (Add-On Content) base title ID from a given title ID.
*
* @param title_id The title ID.
* @returns The AOC base title ID.
*/
[[nodiscard]] constexpr u64 GetAOCBaseTitleID(u64 title_id) {
return GetBaseTitleID(title_id) + AOC_TITLE_ID_OFFSET;
}
/**
* Gets the AOC (Add-On Content) ID from a given AOC title ID.
*
* @param aoc_title_id The AOC title ID.
* @returns The AOC ID.
*/
[[nodiscard]] constexpr u64 GetAOCID(u64 aoc_title_id) {
return aoc_title_id & AOC_TITLE_ID_MASK;
}
} // namespace FileSys

View File

@@ -410,9 +410,8 @@ u8 NCA::GetCryptoRevision() const {
std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type) const {
const auto master_key_id = GetCryptoRevision();
if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index)) {
return std::nullopt;
}
if (!keys.HasKey(Core::Crypto::S128KeyType::KeyArea, master_key_id, header.key_index))
return {};
std::vector<u8> key_area(header.key_area.begin(), header.key_area.end());
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(
@@ -421,17 +420,15 @@ std::optional<Core::Crypto::Key128> NCA::GetKeyAreaKey(NCASectionCryptoType type
cipher.Transcode(key_area.data(), key_area.size(), key_area.data(), Core::Crypto::Op::Decrypt);
Core::Crypto::Key128 out;
if (type == NCASectionCryptoType::XTS) {
if (type == NCASectionCryptoType::XTS)
std::copy(key_area.begin(), key_area.begin() + 0x10, out.begin());
} else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR) {
else if (type == NCASectionCryptoType::CTR || type == NCASectionCryptoType::BKTR)
std::copy(key_area.begin() + 0x20, key_area.begin() + 0x30, out.begin());
} else {
else
LOG_CRITICAL(Crypto, "Called GetKeyAreaKey on invalid NCASectionCryptoType type={:02X}",
type);
}
static_cast<u8>(type));
u128 out_128{};
std::memcpy(out_128.data(), out.data(), sizeof(u128));
memcpy(out_128.data(), out.data(), 16);
LOG_TRACE(Crypto, "called with crypto_rev={:02X}, kak_index={:02X}, key={:016X}{:016X}",
master_key_id, header.key_index, out_128[1], out_128[0]);
@@ -510,7 +507,7 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
// TODO(DarkLordZach): Find a test case for XTS-encrypted NCAs
default:
LOG_ERROR(Crypto, "called with unhandled crypto type={:02X}",
s_header.raw.header.crypto_type);
static_cast<u8>(s_header.raw.header.crypto_type));
return nullptr;
}
}
@@ -519,17 +516,15 @@ Loader::ResultStatus NCA::GetStatus() const {
return status;
}
std::vector<VirtualFile> NCA::GetFiles() const {
if (status != Loader::ResultStatus::Success) {
std::vector<std::shared_ptr<VfsFile>> NCA::GetFiles() const {
if (status != Loader::ResultStatus::Success)
return {};
}
return files;
}
std::vector<VirtualDir> NCA::GetSubdirectories() const {
if (status != Loader::ResultStatus::Success) {
std::vector<std::shared_ptr<VfsDirectory>> NCA::GetSubdirectories() const {
if (status != Loader::ResultStatus::Success)
return {};
}
return dirs;
}
@@ -537,7 +532,7 @@ std::string NCA::GetName() const {
return file->GetName();
}
VirtualDir NCA::GetParentDirectory() const {
std::shared_ptr<VfsDirectory> NCA::GetParentDirectory() const {
return file->GetContainingDirectory();
}

View File

@@ -82,7 +82,7 @@ struct NCAHeader {
};
static_assert(sizeof(NCAHeader) == 0x400, "NCAHeader has incorrect size.");
inline bool IsDirectoryExeFS(const VirtualDir& pfs) {
inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
// According to switchbrew, an exefs must only contain these two files:
return pfs->GetFile("main") != nullptr && pfs->GetFile("main.npdm") != nullptr;
}
@@ -104,10 +104,10 @@ public:
Loader::ResultStatus GetStatus() const;
std::vector<VirtualFile> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
NCAContentType GetType() const;
u64 GetTitleId() const;

View File

@@ -191,7 +191,7 @@ bool BKTR::Resize(std::size_t new_size) {
return false;
}
VirtualDir BKTR::GetContainingDirectory() const {
std::shared_ptr<VfsDirectory> BKTR::GetContainingDirectory() const {
return base_romfs->GetContainingDirectory();
}

View File

@@ -106,7 +106,7 @@ public:
bool Resize(std::size_t new_size) override;
VirtualDir GetContainingDirectory() const override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;

View File

@@ -12,7 +12,6 @@
#include "common/logging/log.h"
#include "common/string_util.h"
#include "core/core.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/ips_layer.h"
@@ -31,6 +30,7 @@ namespace FileSys {
namespace {
constexpr u32 SINGLE_BYTE_MODULUS = 0x100;
constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{
"main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2",
@@ -532,7 +532,7 @@ PatchManager::PatchVersionNames PatchManager::GetPatchVersionNames(VirtualFile u
dlc_match.reserve(dlc_entries.size());
std::copy_if(dlc_entries.begin(), dlc_entries.end(), std::back_inserter(dlc_match),
[this](const ContentProviderEntry& entry) {
return GetBaseTitleID(entry.title_id) == title_id &&
return (entry.title_id & DLC_BASE_TITLE_ID_MASK) == title_id &&
content_provider.GetEntry(entry)->GetStatus() ==
Loader::ResultStatus::Success;
});

View File

@@ -7,7 +7,6 @@
#include "common/common_types.h"
#include "common/logging/log.h"
#include "core/file_sys/card_image.h"
#include "core/file_sys/common_funcs.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
@@ -48,27 +47,6 @@ ResultVal<VirtualFile> RomFSFactory::OpenCurrentProcess(u64 current_process_titl
patch_manager.PatchRomFS(file, ivfc_offset, ContentRecordType::Program, update_raw));
}
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFS(u64 title_id, ContentRecordType type) const {
auto nca = content_provider.GetEntry(title_id, type);
if (nca == nullptr) {
// TODO: Find the right error code to use here
return RESULT_UNKNOWN;
}
const PatchManager patch_manager{title_id, filesystem_controller, content_provider};
return MakeResult<VirtualFile>(
patch_manager.PatchRomFS(nca->GetRomFS(), nca->GetBaseIVFCOffset(), type));
}
ResultVal<VirtualFile> RomFSFactory::OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, ContentRecordType type) const {
const auto res_title_id = GetBaseTitleIDWithProgramIndex(title_id, program_index);
return OpenPatchedRomFS(res_title_id, type);
}
ResultVal<VirtualFile> RomFSFactory::Open(u64 title_id, StorageId storage,
ContentRecordType type) const {
const std::shared_ptr<NCA> res = GetEntry(title_id, storage, type);

View File

@@ -42,10 +42,6 @@ public:
void SetPackedUpdate(VirtualFile update_raw);
[[nodiscard]] ResultVal<VirtualFile> OpenCurrentProcess(u64 current_process_title_id) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFS(u64 title_id,
ContentRecordType type) const;
[[nodiscard]] ResultVal<VirtualFile> OpenPatchedRomFSWithProgramIndex(
u64 title_id, u8 program_index, ContentRecordType type) const;
[[nodiscard]] ResultVal<VirtualFile> Open(u64 title_id, StorageId storage,
ContentRecordType type) const;

View File

@@ -70,8 +70,7 @@ std::string SaveDataAttribute::DebugInfo() const {
static_cast<u8>(rank), index);
}
SaveDataFactory::SaveDataFactory(Core::System& system_, VirtualDir save_directory_)
: dir{std::move(save_directory_)}, system{system_} {
SaveDataFactory::SaveDataFactory(VirtualDir save_directory) : dir(std::move(save_directory)) {
// Delete all temporary storages
// On hardware, it is expected that temporary storage be empty at first use.
dir->DeleteSubdirectoryRecursive("temp");
@@ -84,7 +83,7 @@ ResultVal<VirtualDir> SaveDataFactory::Create(SaveDataSpaceId space,
PrintSaveDataAttributeWarnings(meta);
const auto save_directory =
GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->CreateDirectoryRelative(save_directory);
@@ -101,7 +100,7 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space,
const SaveDataAttribute& meta) const {
const auto save_directory =
GetFullPath(system, space, meta.type, meta.title_id, meta.user_id, meta.save_id);
GetFullPath(space, meta.type, meta.title_id, meta.user_id, meta.save_id);
auto out = dir->GetDirectoryRelative(save_directory);
@@ -136,14 +135,13 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
}
}
std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId space,
SaveDataType type, u64 title_id, u128 user_id,
u64 save_id) {
std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id) {
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
// be interpreted as the title id of the current process.
if (type == SaveDataType::SaveData || type == SaveDataType::DeviceSaveData) {
if (title_id == 0) {
title_id = system.CurrentProcess()->GetTitleID();
title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID();
}
}
@@ -169,7 +167,7 @@ std::string SaveDataFactory::GetFullPath(Core::System& system, SaveDataSpaceId s
SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
u128 user_id) const {
const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
const auto size_file = dir->GetFile(SAVE_DATA_SIZE_FILENAME);
@@ -184,7 +182,7 @@ SaveDataSize SaveDataFactory::ReadSaveDataSize(SaveDataType type, u64 title_id,
void SaveDataFactory::WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
SaveDataSize new_value) const {
const auto path = GetFullPath(system, SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto path = GetFullPath(SaveDataSpaceId::NandUser, type, title_id, user_id, 0);
const auto dir = GetOrCreateDirectoryRelative(this->dir, path);
const auto size_file = dir->CreateFile(SAVE_DATA_SIZE_FILENAME);

View File

@@ -12,10 +12,6 @@
#include "core/file_sys/vfs.h"
#include "core/hle/result.h"
namespace Core {
class System;
}
namespace FileSys {
enum class SaveDataSpaceId : u8 {
@@ -88,7 +84,7 @@ struct SaveDataSize {
/// File system interface to the SaveData archive
class SaveDataFactory {
public:
explicit SaveDataFactory(Core::System& system_, VirtualDir save_directory_);
explicit SaveDataFactory(VirtualDir dir);
~SaveDataFactory();
ResultVal<VirtualDir> Create(SaveDataSpaceId space, const SaveDataAttribute& meta) const;
@@ -97,8 +93,8 @@ public:
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
static std::string GetFullPath(Core::System& system, SaveDataSpaceId space, SaveDataType type,
u64 title_id, u128 user_id, u64 save_id);
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
u128 user_id, u64 save_id);
SaveDataSize ReadSaveDataSize(SaveDataType type, u64 title_id, u128 user_id) const;
void WriteSaveDataSize(SaveDataType type, u64 title_id, u128 user_id,
@@ -106,7 +102,6 @@ public:
private:
VirtualDir dir;
Core::System& system;
};
} // namespace FileSys

View File

@@ -20,8 +20,8 @@
namespace FileSys {
NSP::NSP(VirtualFile file_, std::size_t program_index)
: file(std::move(file_)), program_index(program_index), status{Loader::ResultStatus::Success},
NSP::NSP(VirtualFile file_)
: file(std::move(file_)), status{Loader::ResultStatus::Success},
pfs(std::make_shared<PartitionFilesystem>(file)), keys{Core::Crypto::KeyManager::Instance()} {
if (pfs->GetStatus() != Loader::ResultStatus::Success) {
status = pfs->GetStatus();
@@ -146,7 +146,7 @@ std::shared_ptr<NCA> NSP::GetNCA(u64 title_id, ContentRecordType type, TitleType
if (extracted)
LOG_WARNING(Service_FS, "called on an NSP that is of type extracted.");
const auto title_id_iter = ncas.find(title_id + program_index);
const auto title_id_iter = ncas.find(title_id);
if (title_id_iter == ncas.end())
return nullptr;

View File

@@ -27,7 +27,7 @@ enum class ContentRecordType : u8;
class NSP : public ReadOnlyVfsDirectory {
public:
explicit NSP(VirtualFile file, std::size_t program_index = 0);
explicit NSP(VirtualFile file);
~NSP() override;
Loader::ResultStatus GetStatus() const;
@@ -69,8 +69,6 @@ private:
VirtualFile file;
const std::size_t program_index;
bool extracted = false;
Loader::ResultStatus status;
std::map<u64, Loader::ResultStatus> program_status;

View File

@@ -6,384 +6,191 @@
namespace FileSys::SystemArchive::SharedFontData {
const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED{{
0x00, 0x01, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x80, 0x00, 0x03, 0x00, 0x60, 0x4F, 0x53, 0x2F, 0x32,
0x34, 0x00, 0x1E, 0x26, 0x00, 0x00, 0x01, 0x68, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6D, 0x61, 0x70,
0xC1, 0xE7, 0xC8, 0xF3, 0x00, 0x00, 0x02, 0x0C, 0x00, 0x00, 0x01, 0x72, 0x63, 0x76, 0x74, 0x20,
0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x66, 0x70, 0x67, 0x6D,
0x06, 0x59, 0x9C, 0x37, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x01, 0x73, 0x67, 0x61, 0x73, 0x70,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x17, 0x80, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6C, 0x79, 0x66,
0x50, 0x0B, 0xEA, 0xFA, 0x00, 0x00, 0x05, 0x50, 0x00, 0x00, 0x0F, 0x04, 0x68, 0x65, 0x61, 0x64,
0x18, 0x65, 0x81, 0x09, 0x00, 0x00, 0x00, 0xEC, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61,
0x09, 0x88, 0x03, 0x86, 0x00, 0x00, 0x01, 0x24, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6D, 0x74, 0x78,
0x0A, 0xF0, 0x01, 0x94, 0x00, 0x00, 0x01, 0xC8, 0x00, 0x00, 0x00, 0x42, 0x6C, 0x6F, 0x63, 0x61,
0x34, 0x80, 0x30, 0x6E, 0x00, 0x00, 0x05, 0x14, 0x00, 0x00, 0x00, 0x3A, 0x6D, 0x61, 0x78, 0x70,
0x02, 0x2C, 0x00, 0x72, 0x00, 0x00, 0x01, 0x48, 0x00, 0x00, 0x00, 0x20, 0x6E, 0x61, 0x6D, 0x65,
0xDB, 0xC5, 0x42, 0x4D, 0x00, 0x00, 0x14, 0x54, 0x00, 0x00, 0x01, 0xFE, 0x70, 0x6F, 0x73, 0x74,
0xF4, 0xB4, 0xAC, 0xAB, 0x00, 0x00, 0x16, 0x54, 0x00, 0x00, 0x01, 0x2A, 0x70, 0x72, 0x65, 0x70,
0x1C, 0xFC, 0x7D, 0x9C, 0x00, 0x00, 0x04, 0xF4, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0xC9, 0x16, 0x5B, 0x71, 0x5F, 0x0F, 0x3C, 0xF5, 0x00, 0x0B, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0xD9, 0x44, 0x2F, 0x5D, 0x00, 0x00, 0x00, 0x00, 0xDC, 0x02, 0x0D, 0xA7,
0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x9A, 0xFF, 0x80, 0x02, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x03, 0xEC, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x71,
0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0xC4, 0x01, 0x90, 0x00, 0x05,
0x00, 0x04, 0x00, 0xD2, 0x00, 0xD2, 0x00, 0x00, 0x01, 0x26, 0x00, 0xD2, 0x00, 0xD2, 0x00, 0x00,
0x03, 0xDA, 0x00, 0x68, 0x02, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
const std::array<unsigned char, 2932> FONT_NINTENDO_EXTENDED{{
0x00, 0x01, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x80, 0x00, 0x03, 0x00, 0x70, 0x44, 0x53, 0x49, 0x47,
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0b, 0x6c, 0x00, 0x00, 0x00, 0x08, 0x4f, 0x53, 0x2f, 0x32,
0x33, 0x86, 0x1d, 0x9b, 0x00, 0x00, 0x01, 0x78, 0x00, 0x00, 0x00, 0x60, 0x63, 0x6d, 0x61, 0x70,
0xc2, 0x06, 0x20, 0xde, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x63, 0x76, 0x74, 0x20,
0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x04, 0x2c, 0x00, 0x00, 0x00, 0x06, 0x66, 0x70, 0x67, 0x6d,
0x06, 0x59, 0x9c, 0x37, 0x00, 0x00, 0x02, 0xa0, 0x00, 0x00, 0x01, 0x73, 0x67, 0x61, 0x73, 0x70,
0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x0b, 0x64, 0x00, 0x00, 0x00, 0x08, 0x67, 0x6c, 0x79, 0x66,
0x10, 0x31, 0x88, 0x00, 0x00, 0x00, 0x04, 0x34, 0x00, 0x00, 0x04, 0x64, 0x68, 0x65, 0x61, 0x64,
0x15, 0x9d, 0xef, 0x91, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x36, 0x68, 0x68, 0x65, 0x61,
0x09, 0x60, 0x03, 0x71, 0x00, 0x00, 0x01, 0x34, 0x00, 0x00, 0x00, 0x24, 0x68, 0x6d, 0x74, 0x78,
0x0d, 0x2e, 0x03, 0xa7, 0x00, 0x00, 0x01, 0xd8, 0x00, 0x00, 0x00, 0x26, 0x6c, 0x6f, 0x63, 0x61,
0x05, 0xc0, 0x04, 0x6c, 0x00, 0x00, 0x08, 0x98, 0x00, 0x00, 0x00, 0x1e, 0x6d, 0x61, 0x78, 0x70,
0x02, 0x1c, 0x00, 0x5f, 0x00, 0x00, 0x01, 0x58, 0x00, 0x00, 0x00, 0x20, 0x6e, 0x61, 0x6d, 0x65,
0x7c, 0xe0, 0x84, 0x5c, 0x00, 0x00, 0x08, 0xb8, 0x00, 0x00, 0x02, 0x09, 0x70, 0x6f, 0x73, 0x74,
0x47, 0x4e, 0x74, 0x19, 0x00, 0x00, 0x0a, 0xc4, 0x00, 0x00, 0x00, 0x9e, 0x70, 0x72, 0x65, 0x70,
0x1c, 0xfc, 0x7d, 0x9c, 0x00, 0x00, 0x04, 0x14, 0x00, 0x00, 0x00, 0x16, 0x00, 0x01, 0x00, 0x00,
0x00, 0x01, 0x00, 0x00, 0x7c, 0xc7, 0xb1, 0x63, 0x5f, 0x0f, 0x3c, 0xf5, 0x00, 0x1b, 0x03, 0xe8,
0x00, 0x00, 0x00, 0x00, 0xd9, 0x44, 0x2f, 0x5d, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x45, 0x7b, 0x69,
0x00, 0x00, 0x00, 0x00, 0x03, 0xe6, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x84, 0xff, 0x83, 0x01, 0xf4, 0x03, 0xe8,
0x00, 0x00, 0x00, 0x00, 0x03, 0xe6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x5e,
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x03, 0x74, 0x01, 0x90, 0x00, 0x05,
0x00, 0x04, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x00, 0x01, 0x1f, 0x00, 0xcd, 0x00, 0xcd, 0x00, 0x00,
0x03, 0xc3, 0x00, 0x66, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0xC0, 0x00, 0x0D, 0xE0, 0xF0, 0x03, 0x9A, 0xFF, 0x80,
0x02, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x02, 0xCD, 0x00, 0x00, 0x00, 0x20, 0x00, 0x01, 0x04, 0x00, 0x00, 0xA4, 0x00, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14,
0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C,
0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x04, 0x00, 0x50, 0x00, 0x00, 0x00, 0x10,
0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0xE0, 0xA9, 0xE0, 0xB4,
0xE0, 0xE9, 0xE0, 0xF0, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00, 0x20, 0xE0, 0xA0,
0xE0, 0xB3, 0xE0, 0xE0, 0xE0, 0xEF, 0xFF, 0xFF, 0x00, 0x01, 0xFF, 0xF5, 0xFF, 0xE3, 0x1F, 0x64,
0x1F, 0x5B, 0x1F, 0x30, 0x1F, 0x2B, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x00, 0x00, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x03, 0x00,
0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x00, 0xc0, 0x00, 0x00, 0xe0, 0xe9, 0x03, 0x84, 0xff, 0x83,
0x01, 0xf4, 0x02, 0xee, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0xe8,
0x02, 0xbc, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x03, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0xfa, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x03, 0xe8, 0x00, 0xeb, 0x01, 0x21, 0x00, 0xff,
0x00, 0xff, 0x01, 0x3d, 0x01, 0x17, 0x00, 0x42, 0x00, 0x1c, 0x00, 0x3e, 0x00, 0x17, 0x00, 0x00,
0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x68, 0x00, 0x01, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1c, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00, 0x68, 0x00, 0x06, 0x00, 0x4c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x04, 0x00, 0x38, 0x00, 0x00, 0x00, 0x0a,
0x00, 0x08, 0x00, 0x02, 0x00, 0x02, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xe0, 0xe9, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x20, 0xe0, 0xe0, 0xff, 0xff, 0x00, 0x01, 0xff, 0xf5,
0xff, 0xe3, 0x1f, 0x24, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xb8, 0x00, 0x00, 0x2c, 0x4b, 0xb8, 0x00, 0x09, 0x50, 0x58, 0xb1, 0x01, 0x01, 0x8e, 0x59, 0xb8,
0x01, 0xff, 0x85, 0xb8, 0x00, 0x44, 0x1d, 0xb9, 0x00, 0x09, 0x00, 0x03, 0x5f, 0x5e, 0x2d, 0xb8,
0x00, 0x01, 0x2c, 0x20, 0x20, 0x45, 0x69, 0x44, 0xb0, 0x01, 0x60, 0x2d, 0xb8, 0x00, 0x02, 0x2c,
0xb8, 0x00, 0x01, 0x2a, 0x21, 0x2d, 0xb8, 0x00, 0x03, 0x2c, 0x20, 0x46, 0xb0, 0x03, 0x25, 0x46,
0x52, 0x58, 0x23, 0x59, 0x20, 0x8a, 0x20, 0x8a, 0x49, 0x64, 0x8a, 0x20, 0x46, 0x20, 0x68, 0x61,
0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, 0x65, 0x8a, 0x59, 0x2f,
0x20, 0xb0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xb0, 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x59, 0x1b,
0x69, 0x20, 0xb0, 0x00, 0x54, 0x58, 0x21, 0xb0, 0x40, 0x65, 0x59, 0x59, 0x3a, 0x2d, 0xb8, 0x00,
0x04, 0x2c, 0x20, 0x46, 0xb0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8a, 0x59, 0x20, 0x46, 0x20,
0x6a, 0x61, 0x64, 0xb0, 0x04, 0x25, 0x46, 0x20, 0x6a, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8a, 0x59,
0x2f, 0xfd, 0x2d, 0xb8, 0x00, 0x05, 0x2c, 0x4b, 0x20, 0xb0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58,
0xb0, 0x80, 0x44, 0x1b, 0xb0, 0x40, 0x44, 0x59, 0x1b, 0x21, 0x21, 0x20, 0x45, 0xb0, 0xc0, 0x50,
0x58, 0xb0, 0xc0, 0x44, 0x1b, 0x21, 0x59, 0x59, 0x2d, 0xb8, 0x00, 0x06, 0x2c, 0x20, 0x20, 0x45,
0x69, 0x44, 0xb0, 0x01, 0x60, 0x20, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0xb0, 0x01, 0x60, 0x2d,
0xb8, 0x00, 0x07, 0x2c, 0xb8, 0x00, 0x06, 0x2a, 0x2d, 0xb8, 0x00, 0x08, 0x2c, 0x4b, 0x20, 0xb0,
0x03, 0x26, 0x53, 0x58, 0xb0, 0x40, 0x1b, 0xb0, 0x00, 0x59, 0x8a, 0x8a, 0x20, 0xb0, 0x03, 0x26,
0x53, 0x58, 0x23, 0x21, 0xb0, 0x80, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03, 0x26,
0x53, 0x58, 0x23, 0x21, 0xb8, 0x00, 0xc0, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0, 0x03,
0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x00, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20, 0xb0,
0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xb8, 0x01, 0x40, 0x8a, 0x8a, 0x1b, 0x8a, 0x23, 0x59, 0x20,
0xb8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xb0, 0x03, 0x25, 0x45, 0xb8, 0x01, 0x80, 0x50, 0x58, 0x23,
0x21, 0xb8, 0x01, 0x80, 0x23, 0x21, 0x1b, 0xb0, 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59,
0x1b, 0x21, 0x59, 0x44, 0x2d, 0xb8, 0x00, 0x09, 0x2c, 0x4b, 0x53, 0x58, 0x45, 0x44, 0x1b, 0x21,
0x21, 0x59, 0x2d, 0x00, 0xb8, 0x00, 0x00, 0x2b, 0x00, 0xba, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07,
0x2b, 0xb8, 0x00, 0x00, 0x20, 0x45, 0x7d, 0x69, 0x18, 0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x03, 0xe6, 0x03, 0xe8, 0x00, 0x06,
0x00, 0x00, 0x35, 0x01, 0x33, 0x15, 0x01, 0x23, 0x35, 0x03, 0x52, 0x94, 0xfc, 0xa6, 0x8c, 0x90,
0x03, 0x58, 0x86, 0xfc, 0xa0, 0x8e, 0x00, 0x00, 0x00, 0x02, 0x00, 0xeb, 0x00, 0xcc, 0x02, 0xfb,
0x03, 0x1e, 0x00, 0x08, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x33, 0x13, 0x23, 0x27, 0x23, 0x07, 0x23,
0x13, 0x17, 0x07, 0x06, 0x15, 0x33, 0x27, 0x07, 0x01, 0xbc, 0x6d, 0xd2, 0x7c, 0x26, 0xcc, 0x26,
0x7c, 0xd1, 0x35, 0x40, 0x02, 0x89, 0x45, 0x02, 0x03, 0x1e, 0xfd, 0xae, 0x77, 0x77, 0x02, 0x52,
0x9b, 0xcc, 0x08, 0x04, 0xda, 0x02, 0x00, 0x00, 0x00, 0x03, 0x01, 0x21, 0x00, 0xcc, 0x02, 0xc5,
0x03, 0x1e, 0x00, 0x15, 0x00, 0x1f, 0x00, 0x2b, 0x00, 0x00, 0x25, 0x11, 0x33, 0x32, 0x1e, 0x02,
0x15, 0x14, 0x0e, 0x02, 0x07, 0x1e, 0x01, 0x15, 0x14, 0x0e, 0x02, 0x2b, 0x01, 0x13, 0x33, 0x32,
0x36, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x1d, 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x2b,
0x01, 0x15, 0x01, 0x21, 0xea, 0x25, 0x3f, 0x2e, 0x1a, 0x0e, 0x15, 0x1b, 0x0e, 0x2d, 0x2d, 0x1a,
0x2e, 0x3f, 0x25, 0xf8, 0x76, 0x62, 0x20, 0x2a, 0x28, 0x22, 0x62, 0x76, 0x10, 0x18, 0x11, 0x09,
0x22, 0x22, 0x74, 0xcc, 0x02, 0x52, 0x18, 0x2b, 0x3c, 0x24, 0x1d, 0x1f, 0x17, 0x17, 0x14, 0x0f,
0x48, 0x2f, 0x24, 0x3f, 0x2e, 0x1a, 0x01, 0x5b, 0x29, 0x20, 0x20, 0x2b, 0x94, 0xf8, 0x0e, 0x16,
0x1c, 0x0e, 0x1f, 0x31, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xff, 0x00, 0xcc, 0x02, 0xe7,
0x03, 0x1e, 0x00, 0x0c, 0x00, 0x00, 0x01, 0x33, 0x17, 0x37, 0x33, 0x03, 0x13, 0x23, 0x27, 0x07,
0x23, 0x13, 0x03, 0x01, 0x04, 0x86, 0x69, 0x69, 0x86, 0xa3, 0xa8, 0x88, 0x6c, 0x6c, 0x88, 0xa8,
0xa3, 0x03, 0x1e, 0xcb, 0xcb, 0xfe, 0xda, 0xfe, 0xd4, 0xcf, 0xcf, 0x01, 0x2c, 0x01, 0x26, 0x00,
0x00, 0x01, 0x00, 0xff, 0x00, 0xcc, 0x02, 0xe7, 0x03, 0x1e, 0x00, 0x0f, 0x00, 0x00, 0x01, 0x03,
0x33, 0x17, 0x32, 0x15, 0x1e, 0x01, 0x15, 0x1b, 0x01, 0x33, 0x03, 0x15, 0x23, 0x35, 0x01, 0xb8,
0xb9, 0x7e, 0x01, 0x01, 0x01, 0x03, 0x70, 0x75, 0x7f, 0xb9, 0x76, 0x01, 0xa3, 0x01, 0x7b, 0x01,
0x01, 0x01, 0x05, 0x02, 0xff, 0x00, 0x01, 0x0a, 0xfe, 0x85, 0xd7, 0xd7, 0x00, 0x01, 0x01, 0x3d,
0x00, 0xcc, 0x02, 0xa9, 0x03, 0x1e, 0x00, 0x06, 0x00, 0x00, 0x25, 0x11, 0x33, 0x11, 0x33, 0x15,
0x21, 0x01, 0x3d, 0x75, 0xf7, 0xfe, 0x94, 0xcc, 0x02, 0x52, 0xfe, 0x10, 0x62, 0x00, 0x00, 0x00,
0x00, 0x02, 0x01, 0x17, 0x00, 0xbc, 0x02, 0xcf, 0x03, 0x0e, 0x00, 0x15, 0x00, 0x21, 0x00, 0x00,
0x25, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x1d, 0x01, 0x0e, 0x03, 0x1d, 0x01, 0x17, 0x15, 0x23, 0x27,
0x23, 0x15, 0x23, 0x13, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x2b, 0x01, 0x15, 0x01, 0x17,
0xf4, 0x27, 0x40, 0x2e, 0x19, 0x01, 0x1f, 0x24, 0x1e, 0x78, 0x7d, 0x6a, 0x5c, 0x75, 0x76, 0x72,
0x12, 0x19, 0x11, 0x08, 0x26, 0x26, 0x6a, 0xbc, 0x02, 0x52, 0x1d, 0x31, 0x42, 0x25, 0x16, 0x18,
0x32, 0x2a, 0x1b, 0x02, 0x01, 0xef, 0x06, 0xd7, 0xd7, 0x01, 0x3f, 0x10, 0x1a, 0x1e, 0x0f, 0x23,
0x36, 0xb0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x42, 0x00, 0xbc, 0x03, 0xa4, 0x03, 0x0e, 0x00, 0x0a,
0x00, 0x11, 0x00, 0x00, 0x13, 0x35, 0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x01,
0x11, 0x33, 0x11, 0x33, 0x15, 0x21, 0x42, 0x01, 0xa7, 0xfe, 0xeb, 0x01, 0x1b, 0xfe, 0x53, 0x01,
0x15, 0xfe, 0xeb, 0x01, 0xf7, 0x75, 0xf6, 0xfe, 0x95, 0x02, 0xac, 0x62, 0x45, 0xfe, 0x55, 0x62,
0x47, 0x01, 0xa9, 0xfe, 0x10, 0x02, 0x52, 0xfe, 0x10, 0x62, 0x00, 0x00, 0x00, 0x03, 0x00, 0x1c,
0x00, 0xbc, 0x03, 0xca, 0x03, 0x0e, 0x00, 0x0a, 0x00, 0x21, 0x00, 0x2f, 0x00, 0x00, 0x13, 0x35,
0x21, 0x15, 0x01, 0x21, 0x15, 0x21, 0x35, 0x01, 0x21, 0x01, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x15,
0x14, 0x06, 0x07, 0x0e, 0x03, 0x15, 0x17, 0x15, 0x23, 0x27, 0x23, 0x15, 0x23, 0x13, 0x33, 0x32,
0x3e, 0x02, 0x35, 0x34, 0x2e, 0x02, 0x2b, 0x01, 0x15, 0x1c, 0x01, 0xa7, 0xfe, 0xeb, 0x01, 0x1b,
0xfe, 0x53, 0x01, 0x15, 0xfe, 0xeb, 0x01, 0xf7, 0xf3, 0x27, 0x41, 0x2d, 0x19, 0x1c, 0x20, 0x01,
0x0d, 0x0e, 0x0a, 0x78, 0x7d, 0x69, 0x5c, 0x75, 0x76, 0x71, 0x11, 0x1a, 0x12, 0x09, 0x0a, 0x14,
0x1d, 0x13, 0x69, 0x02, 0xac, 0x62, 0x45, 0xfe, 0x55, 0x62, 0x47, 0x01, 0xa9, 0xfe, 0x10, 0x02,
0x52, 0x1d, 0x31, 0x42, 0x25, 0x2b, 0x44, 0x1d, 0x01, 0x08, 0x09, 0x07, 0x01, 0xf1, 0x06, 0xd7,
0xd7, 0x01, 0x3f, 0x11, 0x19, 0x1f, 0x0e, 0x11, 0x20, 0x19, 0x0f, 0xb0, 0x00, 0x02, 0x00, 0x3e,
0x00, 0xb3, 0x03, 0xa8, 0x03, 0x17, 0x00, 0x3a, 0x00, 0x41, 0x00, 0x00, 0x13, 0x34, 0x3e, 0x02,
0x33, 0x32, 0x1e, 0x02, 0x15, 0x23, 0x27, 0x34, 0x27, 0x2e, 0x01, 0x23, 0x22, 0x0e, 0x02, 0x15,
0x14, 0x16, 0x15, 0x1e, 0x05, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e, 0x02, 0x35, 0x33, 0x1e,
0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x04, 0x35, 0x01, 0x11, 0x33, 0x11, 0x33, 0x15,
0x21, 0x50, 0x24, 0x3b, 0x4a, 0x27, 0x28, 0x4b, 0x39, 0x22, 0x73, 0x01, 0x01, 0x08, 0x2b, 0x29,
0x10, 0x20, 0x19, 0x0f, 0x01, 0x0b, 0x35, 0x41, 0x46, 0x3b, 0x25, 0x23, 0x3a, 0x4b, 0x27, 0x2b,
0x50, 0x3f, 0x26, 0x74, 0x05, 0x34, 0x33, 0x10, 0x20, 0x1a, 0x11, 0x2c, 0x42, 0x4d, 0x42, 0x2c,
0x01, 0xef, 0x73, 0xf6, 0xfe, 0x97, 0x02, 0x70, 0x2a, 0x3f, 0x2a, 0x14, 0x18, 0x2e, 0x44, 0x2c,
0x02, 0x03, 0x01, 0x27, 0x27, 0x07, 0x10, 0x1a, 0x12, 0x02, 0x0b, 0x02, 0x1f, 0x22, 0x19, 0x17,
0x27, 0x3f, 0x34, 0x2c, 0x3e, 0x28, 0x13, 0x1a, 0x32, 0x48, 0x2e, 0x30, 0x30, 0x06, 0x0f, 0x1a,
0x13, 0x21, 0x27, 0x1e, 0x1b, 0x29, 0x3e, 0x31, 0xfe, 0x4c, 0x02, 0x53, 0xfe, 0x10, 0x63, 0x00,
0x00, 0x03, 0x00, 0x17, 0x00, 0xb3, 0x03, 0xce, 0x03, 0x17, 0x00, 0x38, 0x00, 0x4f, 0x00, 0x5d,
0x00, 0x00, 0x13, 0x34, 0x3e, 0x02, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x23, 0x27, 0x34, 0x23, 0x2e,
0x01, 0x23, 0x22, 0x0e, 0x02, 0x15, 0x14, 0x1e, 0x04, 0x15, 0x14, 0x0e, 0x02, 0x23, 0x22, 0x2e,
0x02, 0x35, 0x33, 0x1e, 0x01, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x26, 0x27, 0x2e, 0x03, 0x35,
0x01, 0x11, 0x33, 0x32, 0x1e, 0x02, 0x15, 0x14, 0x06, 0x07, 0x30, 0x0e, 0x02, 0x31, 0x17, 0x15,
0x23, 0x27, 0x23, 0x15, 0x23, 0x13, 0x33, 0x32, 0x3e, 0x02, 0x35, 0x34, 0x2e, 0x02, 0x2b, 0x01,
0x15, 0x2a, 0x24, 0x3a, 0x4a, 0x26, 0x29, 0x4b, 0x39, 0x23, 0x73, 0x01, 0x01, 0x08, 0x2a, 0x2a,
0x10, 0x1f, 0x1a, 0x10, 0x2c, 0x42, 0x4d, 0x42, 0x2c, 0x23, 0x39, 0x4b, 0x27, 0x2b, 0x51, 0x3f,
0x27, 0x75, 0x05, 0x34, 0x33, 0x10, 0x20, 0x1a, 0x10, 0x1f, 0x1c, 0x25, 0x53, 0x47, 0x2e, 0x01,
0xed, 0xf3, 0x27, 0x41, 0x2d, 0x19, 0x1c, 0x20, 0x0c, 0x0e, 0x0c, 0x78, 0x7d, 0x68, 0x5d, 0x75,
0x76, 0x71, 0x11, 0x1a, 0x12, 0x09, 0x0a, 0x14, 0x1d, 0x13, 0x69, 0x02, 0x71, 0x2a, 0x3e, 0x2a,
0x14, 0x18, 0x2e, 0x44, 0x2c, 0x02, 0x02, 0x27, 0x29, 0x07, 0x11, 0x1a, 0x12, 0x1d, 0x24, 0x1c,
0x1d, 0x2b, 0x40, 0x32, 0x2c, 0x3f, 0x29, 0x13, 0x1a, 0x31, 0x49, 0x2e, 0x30, 0x30, 0x06, 0x0f,
0x19, 0x13, 0x1e, 0x22, 0x0b, 0x0e, 0x20, 0x2f, 0x43, 0x30, 0xfe, 0x4b, 0x02, 0x52, 0x1d, 0x32,
0x42, 0x25, 0x2c, 0x42, 0x1d, 0x08, 0x0a, 0x08, 0xf1, 0x06, 0xd7, 0xd7, 0x01, 0x3f, 0x11, 0x19,
0x1f, 0x0e, 0x11, 0x20, 0x19, 0x0f, 0xb0, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x12, 0x00, 0x12,
0x00, 0x12, 0x00, 0x32, 0x00, 0x72, 0x00, 0x8e, 0x00, 0xac, 0x00, 0xbe, 0x00, 0xf0, 0x01, 0x14,
0x01, 0x5c, 0x01, 0xb6, 0x02, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0xa2, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x07, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x2f,
0x00, 0x17, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x12, 0x00, 0x46, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0d, 0x00, 0x58, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x00, 0x12, 0x00, 0x65, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x01, 0x00, 0x20,
0x00, 0x77, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0e, 0x00, 0x97, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x5e, 0x00, 0xa5, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x04, 0x00, 0x24, 0x01, 0x03, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x05, 0x00, 0x1a,
0x01, 0x27, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x24, 0x01, 0x41, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x11, 0x00, 0x02, 0x01, 0x65, 0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53,
0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x67, 0x75, 0x6c, 0x61,
0x72, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x3b, 0x3b,
0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x2d, 0x52, 0x3b, 0x32, 0x30, 0x31, 0x39, 0x3b, 0x46, 0x4c, 0x56, 0x49, 0x2d, 0x36, 0x31, 0x34,
0x59, 0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e,
0x20, 0x52, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x20, 0x31, 0x2e, 0x30, 0x30, 0x30, 0x59,
0x75, 0x7a, 0x75, 0x4f, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, 0x6e, 0x2d,
0x52, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00,
0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00,
0x6e, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x72, 0x00,
0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00,
0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x3b, 0x00, 0x3b, 0x00, 0x59, 0x00,
0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00,
0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00,
0x52, 0x00, 0x3b, 0x00, 0x32, 0x00, 0x30, 0x00, 0x31, 0x00, 0x39, 0x00, 0x3b, 0x00, 0x46, 0x00,
0x4c, 0x00, 0x56, 0x00, 0x49, 0x00, 0x2d, 0x00, 0x36, 0x00, 0x31, 0x00, 0x34, 0x00, 0x59, 0x00,
0x75, 0x00, 0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00,
0x74, 0x00, 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x20, 0x00,
0x52, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00,
0x20, 0x00, 0x31, 0x00, 0x2e, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x59, 0x00, 0x75, 0x00,
0x7a, 0x00, 0x75, 0x00, 0x4f, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00,
0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6f, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x52, 0x00,
0x52, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x9c, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xB8, 0x00, 0x00, 0x2C, 0x4B, 0xB8, 0x00, 0x09, 0x50, 0x58, 0xB1, 0x01, 0x01, 0x8E, 0x59, 0xB8,
0x01, 0xFF, 0x85, 0xB8, 0x00, 0x44, 0x1D, 0xB9, 0x00, 0x09, 0x00, 0x03, 0x5F, 0x5E, 0x2D, 0xB8,
0x00, 0x01, 0x2C, 0x20, 0x20, 0x45, 0x69, 0x44, 0xB0, 0x01, 0x60, 0x2D, 0xB8, 0x00, 0x02, 0x2C,
0xB8, 0x00, 0x01, 0x2A, 0x21, 0x2D, 0xB8, 0x00, 0x03, 0x2C, 0x20, 0x46, 0xB0, 0x03, 0x25, 0x46,
0x52, 0x58, 0x23, 0x59, 0x20, 0x8A, 0x20, 0x8A, 0x49, 0x64, 0x8A, 0x20, 0x46, 0x20, 0x68, 0x61,
0x64, 0xB0, 0x04, 0x25, 0x46, 0x20, 0x68, 0x61, 0x64, 0x52, 0x58, 0x23, 0x65, 0x8A, 0x59, 0x2F,
0x20, 0xB0, 0x00, 0x53, 0x58, 0x69, 0x20, 0xB0, 0x00, 0x54, 0x58, 0x21, 0xB0, 0x40, 0x59, 0x1B,
0x69, 0x20, 0xB0, 0x00, 0x54, 0x58, 0x21, 0xB0, 0x40, 0x65, 0x59, 0x59, 0x3A, 0x2D, 0xB8, 0x00,
0x04, 0x2C, 0x20, 0x46, 0xB0, 0x04, 0x25, 0x46, 0x52, 0x58, 0x23, 0x8A, 0x59, 0x20, 0x46, 0x20,
0x6A, 0x61, 0x64, 0xB0, 0x04, 0x25, 0x46, 0x20, 0x6A, 0x61, 0x64, 0x52, 0x58, 0x23, 0x8A, 0x59,
0x2F, 0xFD, 0x2D, 0xB8, 0x00, 0x05, 0x2C, 0x4B, 0x20, 0xB0, 0x03, 0x26, 0x50, 0x58, 0x51, 0x58,
0xB0, 0x80, 0x44, 0x1B, 0xB0, 0x40, 0x44, 0x59, 0x1B, 0x21, 0x21, 0x20, 0x45, 0xB0, 0xC0, 0x50,
0x58, 0xB0, 0xC0, 0x44, 0x1B, 0x21, 0x59, 0x59, 0x2D, 0xB8, 0x00, 0x06, 0x2C, 0x20, 0x20, 0x45,
0x69, 0x44, 0xB0, 0x01, 0x60, 0x20, 0x20, 0x45, 0x7D, 0x69, 0x18, 0x44, 0xB0, 0x01, 0x60, 0x2D,
0xB8, 0x00, 0x07, 0x2C, 0xB8, 0x00, 0x06, 0x2A, 0x2D, 0xB8, 0x00, 0x08, 0x2C, 0x4B, 0x20, 0xB0,
0x03, 0x26, 0x53, 0x58, 0xB0, 0x40, 0x1B, 0xB0, 0x00, 0x59, 0x8A, 0x8A, 0x20, 0xB0, 0x03, 0x26,
0x53, 0x58, 0x23, 0x21, 0xB0, 0x80, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, 0x03, 0x26,
0x53, 0x58, 0x23, 0x21, 0xB8, 0x00, 0xC0, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0, 0x03,
0x26, 0x53, 0x58, 0x23, 0x21, 0xB8, 0x01, 0x00, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20, 0xB0,
0x03, 0x26, 0x53, 0x58, 0x23, 0x21, 0xB8, 0x01, 0x40, 0x8A, 0x8A, 0x1B, 0x8A, 0x23, 0x59, 0x20,
0xB8, 0x00, 0x03, 0x26, 0x53, 0x58, 0xB0, 0x03, 0x25, 0x45, 0xB8, 0x01, 0x80, 0x50, 0x58, 0x23,
0x21, 0xB8, 0x01, 0x80, 0x23, 0x21, 0x1B, 0xB0, 0x03, 0x25, 0x45, 0x23, 0x21, 0x23, 0x21, 0x59,
0x1B, 0x21, 0x59, 0x44, 0x2D, 0xB8, 0x00, 0x09, 0x2C, 0x4B, 0x53, 0x58, 0x45, 0x44, 0x1B, 0x21,
0x21, 0x59, 0x2D, 0x00, 0xB8, 0x00, 0x00, 0x2B, 0x00, 0xBA, 0x00, 0x01, 0x00, 0x01, 0x00, 0x07,
0x2B, 0xB8, 0x00, 0x00, 0x20, 0x45, 0x7D, 0x69, 0x18, 0x44, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x16, 0x00, 0x70,
0x00, 0xDC, 0x01, 0x34, 0x01, 0x7C, 0x01, 0xA2, 0x01, 0xF4, 0x02, 0x3C, 0x02, 0xA8, 0x03, 0x4C,
0x03, 0xE2, 0x04, 0x20, 0x04, 0x58, 0x04, 0x9A, 0x04, 0xEE, 0x05, 0x32, 0x05, 0x64, 0x05, 0x80,
0x05, 0xC6, 0x05, 0xF6, 0x06, 0x54, 0x06, 0xB2, 0x07, 0x38, 0x07, 0x60, 0x07, 0x82, 0x00, 0x00,
0x00, 0x02, 0x00, 0xA4, 0xFF, 0xFF, 0x03, 0x5C, 0x03, 0x09, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00,
0x13, 0x11, 0x21, 0x11, 0x25, 0x21, 0x11, 0x21, 0xCD, 0x02, 0x66, 0xFD, 0x71, 0x02, 0xB8, 0xFD,
0x48, 0x02, 0xE0, 0xFD, 0x48, 0x02, 0xB8, 0x29, 0xFC, 0xF6, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14,
0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1F, 0x00, 0x2F, 0x00, 0x39, 0x00, 0x00,
0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, 0x32, 0x1E,
0x02, 0x14, 0x0E, 0x02, 0x22, 0x2E, 0x02, 0x34, 0x3E, 0x01, 0x13, 0x12, 0x37, 0x33, 0x13, 0x12,
0x15, 0x16, 0x23, 0x2F, 0x01, 0x23, 0x07, 0x23, 0x22, 0x26, 0x25, 0x30, 0x27, 0x26, 0x2F, 0x01,
0x06, 0x07, 0x06, 0x32, 0x02, 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77,
0x46, 0x46, 0x77, 0xFE, 0x9E, 0xC8, 0xB7, 0x83, 0x4E, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, 0x83, 0x4E,
0x4E, 0x83, 0x23, 0x6C, 0x5E, 0x6D, 0x68, 0x68, 0x01, 0x39, 0x38, 0x2E, 0xD1, 0x2B, 0x37, 0x33,
0x04, 0x01, 0x48, 0x1D, 0x1C, 0x0A, 0x05, 0x01, 0x45, 0x01, 0x89, 0x03, 0x3F, 0x46, 0x77, 0xA4,
0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x4E, 0x83, 0xB7, 0xC8, 0xB7,
0x83, 0x4E, 0x4E, 0x83, 0xB7, 0xC8, 0xB7, 0x83, 0xFD, 0x64, 0x01, 0x1A, 0xEB, 0xFE, 0xFE, 0xFE,
0xFD, 0x03, 0x01, 0x01, 0x77, 0x78, 0x01, 0xCF, 0x4C, 0x4C, 0x1C, 0x0C, 0x02, 0xBE, 0x02, 0x00,
0x00, 0x05, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x2F,
0x00, 0x3A, 0x00, 0x44, 0x00, 0x00, 0x12, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x02,
0x22, 0x0E, 0x01, 0x02, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x26, 0x01,
0x16, 0x17, 0x14, 0x06, 0x07, 0x06, 0x2B, 0x01, 0x19, 0x01, 0x17, 0x32, 0x17, 0x16, 0x17, 0x16,
0x07, 0x06, 0x0F, 0x01, 0x36, 0x37, 0x34, 0x2E, 0x01, 0x27, 0x23, 0x15, 0x33, 0x32, 0x27, 0x32,
0x37, 0x36, 0x26, 0x27, 0x26, 0x2B, 0x01, 0x15, 0x45, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46,
0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE,
0xF4, 0xE2, 0x01, 0xF7, 0x61, 0x01, 0x4E, 0x3E, 0x29, 0xAF, 0x4E, 0x81, 0x8B, 0x1D, 0x3C, 0x1F,
0x19, 0x04, 0x06, 0x39, 0x57, 0x44, 0x01, 0x1B, 0x2D, 0x51, 0x46, 0x46, 0x47, 0x66, 0x70, 0x16,
0x1F, 0x01, 0x2C, 0x08, 0x4B, 0x4C, 0x01, 0xDE, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4,
0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2,
0x84, 0x84, 0x01, 0x6D, 0x21, 0x5B, 0x40, 0x50, 0x05, 0x03, 0x01, 0x03, 0x01, 0x05, 0x01, 0x05,
0x09, 0x30, 0x25, 0x29, 0x40, 0x21, 0xC2, 0x06, 0x3E, 0x1A, 0x21, 0x0B, 0x01, 0x8C, 0xE1, 0x0A,
0x0E, 0x54, 0x0B, 0x02, 0x79, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC,
0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x38, 0x00, 0x00, 0x12, 0x14, 0x1E, 0x02, 0x32, 0x3E,
0x02, 0x34, 0x2E, 0x02, 0x22, 0x0E, 0x01, 0x02, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10, 0x0E,
0x01, 0x20, 0x26, 0x36, 0x34, 0x3F, 0x01, 0x27, 0x26, 0x27, 0x33, 0x17, 0x16, 0x33, 0x36, 0x3F,
0x02, 0x32, 0x14, 0x06, 0x16, 0x12, 0x14, 0x2B, 0x01, 0x27, 0x26, 0x06, 0x0F, 0x01, 0x23, 0x45,
0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2,
0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x7B, 0x58, 0x58, 0x4D, 0x4F, 0x05, 0x7A,
0x34, 0x34, 0x02, 0x01, 0x33, 0x32, 0x3C, 0x3C, 0xA1, 0x01, 0xB0, 0x3E, 0x3F, 0x39, 0x3B, 0x02,
0x3A, 0x38, 0x3F, 0x01, 0xDE, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46,
0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x60,
0x02, 0x87, 0x88, 0x79, 0x7A, 0x06, 0x54, 0x54, 0x01, 0x53, 0x53, 0x01, 0x01, 0xFB, 0x04, 0xFE,
0xF8, 0x02, 0x5B, 0x5A, 0x03, 0x59, 0x59, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC,
0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x2B, 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E,
0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E,
0x01, 0x10, 0x36, 0x01, 0x35, 0x27, 0x26, 0x34, 0x3B, 0x01, 0x17, 0x16, 0x36, 0x3F, 0x01, 0x33,
0x03, 0x15, 0x23, 0x02, 0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46,
0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01,
0x36, 0x5E, 0x5F, 0x3C, 0x3D, 0x3D, 0x3D, 0x03, 0x3B, 0x3B, 0x77, 0xBE, 0x68, 0x03, 0x3F, 0x46,
0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2, 0xFE,
0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0xF9, 0x6E, 0x96, 0x95, 0x01, 0x67, 0x67,
0x03, 0x66, 0x65, 0xFE, 0xD3, 0xDA, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0xFF, 0xBD, 0x03, 0xEC,
0x03, 0x4B, 0x00, 0x06, 0x00, 0x0C, 0x00, 0x12, 0x00, 0x00, 0x01, 0x21, 0x22, 0x15, 0x30, 0x11,
0x21, 0x17, 0x21, 0x11, 0x10, 0x25, 0x21, 0x01, 0x11, 0x33, 0x11, 0x21, 0x15, 0x03, 0xBB, 0xFD,
0x77, 0xED, 0x03, 0x76, 0x31, 0xFC, 0x28, 0x01, 0x1E, 0x02, 0xBA, 0xFD, 0x5C, 0x68, 0x01, 0x08,
0x03, 0x1A, 0xEE, 0xFD, 0xC2, 0x31, 0x02, 0x6F, 0x01, 0x1E, 0x01, 0xFD, 0x36, 0x02, 0x07, 0xFE,
0x50, 0x57, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0xBD, 0x03, 0xEC, 0x03, 0x4B, 0x00, 0x06,
0x00, 0x0C, 0x00, 0x27, 0x00, 0x32, 0x00, 0x00, 0x05, 0x11, 0x34, 0x27, 0x30, 0x21, 0x11, 0x07,
0x11, 0x21, 0x20, 0x19, 0x01, 0x25, 0x11, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x07,
0x06, 0x07, 0x06, 0x07, 0x1E, 0x02, 0x15, 0x07, 0x23, 0x27, 0x2E, 0x01, 0x2F, 0x01, 0x15, 0x13,
0x36, 0x35, 0x34, 0x27, 0x26, 0x27, 0x23, 0x15, 0x33, 0x36, 0x03, 0xBB, 0xED, 0xFD, 0x77, 0x31,
0x02, 0xBA, 0x01, 0x1E, 0xFD, 0x2A, 0x77, 0x76, 0x15, 0x49, 0x20, 0x35, 0x08, 0x04, 0x06, 0x13,
0x66, 0x0C, 0x01, 0x1F, 0x2E, 0x65, 0x3D, 0x3D, 0x2A, 0x56, 0x28, 0x2E, 0x19, 0x99, 0x3C, 0x20,
0x10, 0x56, 0x4F, 0x46, 0x47, 0x12, 0x02, 0x3E, 0xED, 0x01, 0xFC, 0xD4, 0x31, 0x03, 0x8E, 0xFE,
0xE1, 0xFD, 0x91, 0xC4, 0x02, 0x07, 0x01, 0x04, 0x13, 0x21, 0x44, 0x1D, 0x19, 0x58, 0x15, 0x02,
0x01, 0x13, 0x2D, 0xA2, 0x01, 0x01, 0x3D, 0x81, 0x1A, 0x01, 0x01, 0xDA, 0x01, 0x2D, 0x08, 0x3A,
0x29, 0x0F, 0x08, 0x01, 0x85, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0xF5, 0x03, 0xEC,
0x03, 0x13, 0x00, 0x09, 0x00, 0x11, 0x00, 0x26, 0x00, 0x32, 0x00, 0x00, 0x37, 0x21, 0x34, 0x10,
0x35, 0x34, 0x27, 0x21, 0x04, 0x11, 0x23, 0x10, 0x25, 0x21, 0x16, 0x15, 0x11, 0x21, 0x37, 0x35,
0x37, 0x36, 0x22, 0x2B, 0x01, 0x3D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x0F, 0x01, 0x3B, 0x01, 0x1D,
0x01, 0x2B, 0x01, 0x25, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x3B, 0x01, 0x1D, 0x01, 0x2B, 0x01, 0x45,
0x03, 0x76, 0x45, 0xFE, 0x2D, 0xFE, 0xA2, 0x31, 0x01, 0x8F, 0x01, 0xD3, 0x76, 0xFC, 0x28, 0xA7,
0x68, 0x68, 0x01, 0x5B, 0x5D, 0x90, 0x91, 0x6C, 0x6D, 0x71, 0x70, 0xA0, 0xA0, 0x01, 0x75, 0x27,
0x28, 0x63, 0x63, 0x8B, 0x8A, 0x27, 0x69, 0x01, 0xA4, 0x69, 0x44, 0x01, 0x02, 0xFE, 0xA4, 0x01,
0x8C, 0x03, 0x01, 0x75, 0xFD, 0x58, 0xBB, 0x24, 0x80, 0x80, 0x21, 0x21, 0x1F, 0x1E, 0x85, 0x86,
0x20, 0x22, 0xC3, 0xC3, 0xA1, 0xA3, 0x20, 0x22, 0x00, 0x05, 0x00, 0x14, 0xFF, 0xF5, 0x03, 0xEC,
0x03, 0x13, 0x00, 0x08, 0x00, 0x10, 0x00, 0x2B, 0x00, 0x37, 0x00, 0x44, 0x00, 0x00, 0x37, 0x21,
0x11, 0x10, 0x25, 0x30, 0x21, 0x06, 0x15, 0x03, 0x11, 0x34, 0x37, 0x21, 0x04, 0x19, 0x01, 0x01,
0x35, 0x17, 0x32, 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17,
0x16, 0x23, 0x2F, 0x01, 0x2E, 0x01, 0x2F, 0x01, 0x15, 0x23, 0x37, 0x32, 0x36, 0x37, 0x36, 0x35,
0x26, 0x27, 0x26, 0x2B, 0x01, 0x15, 0x05, 0x35, 0x37, 0x36, 0x26, 0x2B, 0x01, 0x35, 0x21, 0x15,
0x03, 0x17, 0x15, 0x45, 0x03, 0x76, 0xFE, 0xA2, 0xFE, 0x2D, 0x45, 0x31, 0x76, 0x01, 0xD3, 0x01,
0x8F, 0xFE, 0x1E, 0x65, 0x6F, 0x15, 0x46, 0x10, 0x05, 0x04, 0x0D, 0x4F, 0x09, 0x09, 0x1F, 0x1D,
0x3A, 0x06, 0x01, 0x30, 0x2F, 0x22, 0x37, 0x1E, 0x29, 0x14, 0x4E, 0x82, 0x34, 0x19, 0x0E, 0x13,
0x0A, 0x22, 0x07, 0x38, 0x37, 0xFE, 0x3E, 0x68, 0x68, 0x01, 0x5C, 0x5C, 0x01, 0x20, 0xD8, 0xE1,
0x27, 0x01, 0x5D, 0x01, 0x5B, 0x03, 0x01, 0x44, 0xFD, 0x58, 0x02, 0xA8, 0x75, 0x01, 0x03, 0xFE,
0x74, 0xFE, 0x71, 0x01, 0x5C, 0xC5, 0x01, 0x04, 0x0C, 0x43, 0x15, 0x1D, 0x44, 0x10, 0x04, 0x06,
0x14, 0x2B, 0x56, 0x10, 0x01, 0x01, 0x34, 0x52, 0x1C, 0x01, 0x01, 0xA5, 0xE3, 0x04, 0x06, 0x0A,
0x20, 0x2C, 0x04, 0x01, 0x65, 0xE3, 0x47, 0x80, 0x80, 0x01, 0x42, 0x3D, 0xFE, 0xF5, 0x01, 0x41,
0x00, 0x04, 0x00, 0x14, 0x00, 0x52, 0x03, 0xEC, 0x02, 0xB6, 0x00, 0x08, 0x00, 0x16, 0x00, 0x64,
0x00, 0x70, 0x00, 0x00, 0x25, 0x11, 0x21, 0x22, 0x15, 0x30, 0x15, 0x14, 0x33, 0x11, 0x21, 0x32,
0x15, 0x11, 0x14, 0x27, 0x21, 0x22, 0x26, 0x3D, 0x01, 0x34, 0x36, 0x13, 0x26, 0x27, 0x26, 0x27,
0x26, 0x37, 0x33, 0x36, 0x37, 0x36, 0x33, 0x16, 0x17, 0x16, 0x17, 0x16, 0x37, 0x36, 0x37, 0x36,
0x35, 0x34, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26, 0x34, 0x37, 0x36, 0x37,
0x36, 0x37, 0x36, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16, 0x0F, 0x01, 0x22, 0x06, 0x23,
0x27, 0x26, 0x27, 0x26, 0x23, 0x22, 0x07, 0x06, 0x07, 0x06, 0x17, 0x16, 0x17, 0x16, 0x17, 0x16,
0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07, 0x06, 0x27, 0x37, 0x35, 0x3B, 0x01, 0x1D, 0x01, 0x3B,
0x01, 0x1D, 0x01, 0x2B, 0x01, 0x03, 0xBB, 0xFD, 0x2A, 0xA0, 0xA0, 0x02, 0xEE, 0x19, 0x19, 0xFD,
0x12, 0x57, 0x7A, 0x7A, 0xCA, 0x38, 0x1D, 0x16, 0x08, 0x03, 0x01, 0x02, 0x0F, 0x0C, 0x1E, 0x01,
0x02, 0x04, 0x0C, 0x2B, 0x0F, 0x0E, 0x18, 0x0C, 0x09, 0x04, 0x15, 0x32, 0x23, 0x12, 0x1C, 0x0E,
0x09, 0x03, 0x01, 0x01, 0x09, 0x21, 0x0F, 0x14, 0x2E, 0x2A, 0x13, 0x0F, 0x0C, 0x08, 0x0B, 0x05,
0x02, 0x01, 0x02, 0x03, 0x36, 0x03, 0x02, 0x03, 0x08, 0x0D, 0x23, 0x16, 0x0E, 0x10, 0x01, 0x01,
0x07, 0x0B, 0x32, 0x25, 0x13, 0x26, 0x0F, 0x09, 0x01, 0x01, 0x0F, 0x11, 0x24, 0x21, 0x2A, 0xE3,
0x20, 0x20, 0x52, 0x50, 0x71, 0x71, 0x84, 0x02, 0x00, 0xAF, 0xA2, 0xAF, 0x02, 0x32, 0x19, 0xFD,
0xCE, 0x19, 0x01, 0x84, 0x5C, 0xA2, 0x5C, 0x85, 0xFE, 0x29, 0x04, 0x1E, 0x18, 0x26, 0x0F, 0x01,
0x02, 0x01, 0x03, 0x05, 0x0B, 0x29, 0x06, 0x02, 0x03, 0x04, 0x11, 0x0B, 0x0D, 0x0A, 0x06, 0x12,
0x0D, 0x0A, 0x07, 0x0C, 0x18, 0x0D, 0x10, 0x06, 0x18, 0x05, 0x27, 0x14, 0x09, 0x03, 0x0A, 0x0D,
0x06, 0x09, 0x09, 0x0D, 0x0F, 0x14, 0x0C, 0x06, 0x03, 0x02, 0x04, 0x10, 0x0A, 0x11, 0x08, 0x09,
0x0E, 0x0C, 0x07, 0x0C, 0x0C, 0x0A, 0x07, 0x0F, 0x20, 0x11, 0x18, 0x1E, 0x1A, 0x1E, 0x0C, 0x0B,
0x03, 0xAA, 0xA5, 0x89, 0x8A, 0x1C, 0x1B, 0x00, 0x00, 0x05, 0x00, 0x14, 0x00, 0x53, 0x03, 0xEC,
0x02, 0xB6, 0x00, 0x08, 0x00, 0x16, 0x00, 0x2E, 0x00, 0x38, 0x00, 0x65, 0x00, 0x00, 0x01, 0x30,
0x21, 0x11, 0x21, 0x32, 0x3D, 0x01, 0x34, 0x27, 0x32, 0x16, 0x1D, 0x01, 0x14, 0x06, 0x23, 0x21,
0x26, 0x35, 0x11, 0x34, 0x33, 0x01, 0x11, 0x33, 0x32, 0x17, 0x16, 0x17, 0x16, 0x07, 0x06, 0x07,
0x17, 0x1E, 0x01, 0x1F, 0x01, 0x23, 0x2A, 0x01, 0x2E, 0x01, 0x23, 0x27, 0x15, 0x37, 0x32, 0x37,
0x36, 0x27, 0x2E, 0x01, 0x2B, 0x01, 0x15, 0x05, 0x26, 0x27, 0x37, 0x32, 0x3F, 0x01, 0x16, 0x17,
0x1E, 0x01, 0x37, 0x36, 0x27, 0x2E, 0x04, 0x37, 0x3E, 0x01, 0x33, 0x32, 0x17, 0x16, 0x17, 0x14,
0x06, 0x27, 0x26, 0x27, 0x26, 0x0E, 0x01, 0x1E, 0x02, 0x17, 0x16, 0x06, 0x07, 0x06, 0x07, 0x06,
0x03, 0x1B, 0xFD, 0x2A, 0x02, 0xD6, 0xA0, 0xA0, 0x57, 0x7A, 0x7A, 0x57, 0xFD, 0x12, 0x19, 0x19,
0x01, 0xD3, 0x47, 0x44, 0x11, 0x3E, 0x18, 0x21, 0x0B, 0x0C, 0x43, 0x04, 0x17, 0x1C, 0x1E, 0x16,
0x26, 0x26, 0x03, 0x4D, 0x18, 0x1E, 0x11, 0x25, 0x3A, 0x0C, 0x22, 0x08, 0x03, 0x1B, 0x3E, 0x29,
0xFE, 0xAC, 0x0D, 0x04, 0x02, 0x02, 0x1E, 0x1D, 0x03, 0x02, 0x0C, 0x4C, 0x13, 0x20, 0x07, 0x04,
0x1B, 0x56, 0x2D, 0x1C, 0x01, 0x02, 0x44, 0x35, 0x49, 0x1F, 0x10, 0x03, 0x41, 0x01, 0x06, 0x0A,
0x16, 0x3C, 0x18, 0x0C, 0x16, 0x5D, 0x15, 0x33, 0x03, 0x2B, 0x1E, 0x34, 0x59, 0x02, 0x84, 0xFE,
0x00, 0xAF, 0xA2, 0xAF, 0x32, 0x85, 0x5C, 0xA2, 0x5C, 0x84, 0x01, 0x17, 0x02, 0x32, 0x19, 0xFE,
0x2F, 0x01, 0x45, 0x01, 0x02, 0x19, 0x22, 0x32, 0x39, 0x0B, 0x08, 0x0F, 0x27, 0x2F, 0x24, 0x75,
0x12, 0x01, 0x88, 0xBB, 0x04, 0x09, 0x2A, 0x0F, 0x0D, 0x53, 0x8A, 0x17, 0x1E, 0x04, 0x03, 0x03,
0x0C, 0x04, 0x26, 0x0E, 0x0C, 0x14, 0x1A, 0x0E, 0x0E, 0x16, 0x16, 0x2C, 0x1A, 0x2D, 0x2D, 0x2A,
0x16, 0x1D, 0x06, 0x04, 0x01, 0x1A, 0x09, 0x11, 0x09, 0x17, 0x18, 0x0D, 0x17, 0x0C, 0x1B, 0x71,
0x1B, 0x12, 0x01, 0x03, 0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F,
0x00, 0x1B, 0x00, 0x27, 0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02,
0x34, 0x2E, 0x01, 0x24, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13,
0x33, 0x35, 0x33, 0x15, 0x33, 0x15, 0x23, 0x15, 0x23, 0x35, 0x23, 0x02, 0x5A, 0xB4, 0xA4, 0x77,
0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C, 0x01, 0x0C, 0xE2, 0x84,
0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0xC5, 0x4E, 0xC5, 0xC4, 0x50, 0xC4, 0x03, 0x3F,
0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2,
0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0xC0, 0xC4, 0xC5, 0x4E, 0xC5, 0xC5,
0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0F, 0x00, 0x1B, 0x00, 0x1F,
0x00, 0x00, 0x00, 0x22, 0x0E, 0x02, 0x14, 0x1E, 0x02, 0x32, 0x3E, 0x02, 0x34, 0x2E, 0x01, 0x24,
0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x35, 0x21, 0x15, 0x02,
0x5A, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xFE, 0x7C,
0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0x01, 0xD8, 0x03, 0x3F,
0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x46, 0x46, 0x77, 0xA4, 0xB4, 0xA4, 0x77, 0x77, 0x84, 0xE2,
0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0x71, 0x4E, 0x4E, 0x00, 0x00, 0x00,
0x00, 0x03, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x1B, 0x00, 0x25,
0x00, 0x00, 0x00, 0x20, 0x0E, 0x01, 0x10, 0x1E, 0x01, 0x20, 0x3E, 0x01, 0x10, 0x26, 0x01, 0x12,
0x37, 0x33, 0x13, 0x12, 0x15, 0x16, 0x23, 0x2F, 0x01, 0x23, 0x07, 0x23, 0x22, 0x26, 0x25, 0x30,
0x27, 0x26, 0x2F, 0x01, 0x06, 0x07, 0x06, 0x32, 0x02, 0x86, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2,
0x01, 0x0C, 0xE2, 0x84, 0x84, 0xFD, 0xA0, 0x6C, 0x5E, 0x6D, 0x68, 0x68, 0x01, 0x39, 0x38, 0x2E,
0xD1, 0x2B, 0x37, 0x33, 0x04, 0x01, 0x48, 0x1D, 0x1C, 0x0A, 0x05, 0x01, 0x45, 0x01, 0x89, 0x03,
0x70, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0x9A, 0x01, 0x1A,
0xEB, 0xFE, 0xFE, 0xFE, 0xFD, 0x03, 0x01, 0x01, 0x77, 0x78, 0x01, 0xCF, 0x4C, 0x4C, 0x1C, 0x0C,
0x02, 0xBE, 0x02, 0x00, 0x00, 0x04, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B,
0x00, 0x20, 0x00, 0x2B, 0x00, 0x35, 0x00, 0x00, 0x36, 0x10, 0x3E, 0x01, 0x20, 0x1E, 0x01, 0x10,
0x0E, 0x01, 0x20, 0x26, 0x01, 0x30, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x23, 0x27,
0x19, 0x01, 0x33, 0x32, 0x37, 0x3E, 0x01, 0x35, 0x26, 0x07, 0x06, 0x2B, 0x01, 0x35, 0x33, 0x1E,
0x02, 0x15, 0x06, 0x27, 0x23, 0x35, 0x33, 0x16, 0x17, 0x16, 0x14, 0x07, 0x06, 0x14, 0x84, 0xE2,
0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x01, 0xF7, 0x0A, 0x3A, 0x05, 0x04, 0x19,
0x20, 0x3B, 0x1D, 0x8B, 0x81, 0x4E, 0xAF, 0x29, 0x3E, 0x4E, 0x01, 0xAE, 0x0D, 0x47, 0x46, 0x46,
0x52, 0x2C, 0x1B, 0x01, 0xB7, 0x27, 0x4C, 0x4C, 0x07, 0x2C, 0x1E, 0x16, 0xFE, 0x01, 0x0C, 0xE2,
0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, 0x6D, 0x06, 0x21, 0x40, 0x2A, 0x24, 0x30,
0x09, 0x05, 0x01, 0xFE, 0xFB, 0xFE, 0xFD, 0x03, 0x05, 0x4F, 0x41, 0x5B, 0x9B, 0x01, 0x8C, 0x01,
0x0B, 0x21, 0x1A, 0x3E, 0xDA, 0x79, 0x01, 0x01, 0x0B, 0x54, 0x0E, 0x0A, 0x00, 0x02, 0x00, 0x14,
0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x29, 0x00, 0x00, 0x36, 0x10, 0x3E, 0x01,
0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x26, 0x36, 0x14, 0x3B, 0x01, 0x37, 0x36, 0x37, 0x36,
0x1F, 0x01, 0x33, 0x32, 0x34, 0x02, 0x26, 0x36, 0x34, 0x23, 0x0F, 0x01, 0x06, 0x07, 0x22, 0x2F,
0x01, 0x23, 0x16, 0x1F, 0x01, 0x07, 0x14, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE,
0xF4, 0xE2, 0x7B, 0x3D, 0x3F, 0x38, 0x3A, 0x01, 0x02, 0x3A, 0x39, 0x3F, 0x3E, 0xB0, 0x01, 0xA1,
0x3C, 0x3C, 0x32, 0x33, 0x01, 0x02, 0x34, 0x34, 0x7A, 0x05, 0x4F, 0x4D, 0x58, 0xFE, 0x01, 0x0C,
0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x62, 0x02, 0x59, 0x59, 0x02, 0x01, 0x5A,
0x5B, 0x02, 0x01, 0x08, 0x04, 0xFB, 0x01, 0x01, 0x53, 0x53, 0x01, 0x54, 0x54, 0x06, 0x7A, 0x79,
0x88, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B,
0x00, 0x1B, 0x00, 0x00, 0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36,
0x01, 0x15, 0x33, 0x35, 0x13, 0x23, 0x07, 0x0E, 0x01, 0x2F, 0x01, 0x23, 0x22, 0x16, 0x1F, 0x01,
0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x01, 0x36, 0x68,
0xBE, 0x77, 0x3B, 0x3C, 0x02, 0x3D, 0x3D, 0x3D, 0x3D, 0x01, 0x5F, 0x5E, 0x03, 0x70, 0x84, 0xE2,
0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFD, 0xF9, 0x6D, 0xDA, 0x01, 0x2D, 0x65,
0x66, 0x03, 0x67, 0x67, 0x01, 0x95, 0x96, 0x00, 0x00, 0x02, 0x00, 0x14, 0xFF, 0xBF, 0x03, 0xEC,
0x03, 0x4A, 0x00, 0x05, 0x00, 0x0B, 0x00, 0x00, 0x05, 0x21, 0x11, 0x10, 0x05, 0x21, 0x01, 0x21,
0x35, 0x21, 0x11, 0x23, 0x03, 0xEC, 0xFC, 0x28, 0x01, 0x14, 0x02, 0xC4, 0xFD, 0x5C, 0x01, 0x70,
0xFE, 0xF8, 0x68, 0x41, 0x02, 0x77, 0x01, 0x14, 0x01, 0xFD, 0x38, 0x57, 0x01, 0xB0, 0x00, 0x00,
0x00, 0x03, 0x00, 0x14, 0xFF, 0xBF, 0x03, 0xEC, 0x03, 0x49, 0x00, 0x05, 0x00, 0x20, 0x00, 0x2B,
0x00, 0x00, 0x17, 0x11, 0x21, 0x20, 0x19, 0x01, 0x25, 0x33, 0x35, 0x17, 0x1E, 0x01, 0x1F, 0x01,
0x33, 0x37, 0x2E, 0x02, 0x27, 0x34, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x27, 0x26,
0x2B, 0x01, 0x05, 0x06, 0x2B, 0x01, 0x35, 0x33, 0x16, 0x17, 0x16, 0x15, 0x14, 0x14, 0x02, 0xC4,
0x01, 0x14, 0xFD, 0x2A, 0x69, 0x19, 0x2E, 0x28, 0x56, 0x2A, 0x3D, 0x3D, 0x01, 0x65, 0x2C, 0x20,
0x0D, 0x66, 0x13, 0x06, 0x04, 0x09, 0x34, 0x20, 0x49, 0x15, 0x76, 0x77, 0x01, 0x02, 0x0C, 0x47,
0x46, 0x4F, 0x56, 0x10, 0x20, 0x41, 0x03, 0x8A, 0xFE, 0xED, 0xFD, 0x89, 0xC2, 0xDA, 0x01, 0x01,
0x1A, 0x81, 0x3D, 0x01, 0x01, 0xA3, 0x2C, 0x13, 0x01, 0x02, 0x13, 0x5A, 0x1A, 0x1C, 0x44, 0x21,
0x13, 0x04, 0x01, 0xDA, 0x02, 0x85, 0x01, 0x08, 0x0F, 0x29, 0x3A, 0x00, 0x00, 0x03, 0x00, 0x14,
0xFF, 0xFB, 0x03, 0xEC, 0x03, 0x0E, 0x00, 0x08, 0x00, 0x15, 0x00, 0x1B, 0x00, 0x00, 0x05, 0x21,
0x11, 0x10, 0x21, 0x30, 0x21, 0x32, 0x15, 0x01, 0x21, 0x35, 0x23, 0x13, 0x35, 0x21, 0x15, 0x33,
0x32, 0x22, 0x0F, 0x01, 0x05, 0x21, 0x35, 0x23, 0x11, 0x23, 0x03, 0xEC, 0xFC, 0x28, 0x01, 0x8A,
0x01, 0xEC, 0x62, 0xFC, 0xCF, 0x01, 0x40, 0xE1, 0xD9, 0xFE, 0xDF, 0x5D, 0x5C, 0x01, 0x67, 0x68,
0x01, 0x75, 0x01, 0x15, 0xC6, 0x4F, 0x05, 0x01, 0x89, 0x01, 0x8A, 0x63, 0xFD, 0xE1, 0x42, 0x01,
0x0B, 0x3D, 0x42, 0x80, 0x80, 0x48, 0x42, 0x01, 0x44, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x14,
0xFF, 0xFB, 0x03, 0xEC, 0x03, 0x0E, 0x00, 0x07, 0x00, 0x22, 0x00, 0x2F, 0x00, 0x3C, 0x00, 0x00,
0x17, 0x11, 0x34, 0x37, 0x21, 0x20, 0x19, 0x01, 0x01, 0x15, 0x33, 0x35, 0x17, 0x1E, 0x01, 0x1F,
0x02, 0x32, 0x35, 0x26, 0x27, 0x26, 0x27, 0x26, 0x37, 0x36, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26,
0x23, 0x27, 0x17, 0x30, 0x23, 0x35, 0x33, 0x32, 0x17, 0x16, 0x17, 0x14, 0x07, 0x0E, 0x01, 0x05,
0x21, 0x35, 0x27, 0x13, 0x35, 0x21, 0x15, 0x33, 0x32, 0x14, 0x0F, 0x01, 0x14, 0x62, 0x01, 0xEC,
0x01, 0x8A, 0xFE, 0x1E, 0x4E, 0x14, 0x29, 0x1E, 0x37, 0x22, 0x2F, 0x2F, 0x06, 0x3A, 0x1D, 0x1F,
0x09, 0x09, 0x4E, 0x0E, 0x04, 0x05, 0x0F, 0x47, 0x15, 0x6F, 0x65, 0x82, 0x34, 0x37, 0x38, 0x07,
0x23, 0x09, 0x13, 0x0D, 0x1A, 0xFD, 0xD6, 0x01, 0x40, 0xE1, 0xD8, 0xFE, 0xE0, 0x5C, 0x5C, 0x67,
0x68, 0x05, 0x02, 0xB0, 0x62, 0x01, 0xFE, 0x76, 0xFE, 0x77, 0x01, 0x56, 0xC5, 0xA5, 0x01, 0x01,
0x1C, 0x52, 0x34, 0x01, 0x01, 0x0E, 0x58, 0x2C, 0x13, 0x06, 0x04, 0x0F, 0x45, 0x1E, 0x14, 0x42,
0x0D, 0x04, 0x01, 0xA7, 0x65, 0x01, 0x04, 0x2C, 0x21, 0x09, 0x07, 0x03, 0xE3, 0x41, 0x01, 0x01,
0x0B, 0x3D, 0x42, 0x01, 0x80, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x14, 0x00, 0x5D, 0x03, 0xEC,
0x02, 0xAB, 0x00, 0x08, 0x00, 0x37, 0x00, 0x3D, 0x00, 0x00, 0x13, 0x30, 0x21, 0x11, 0x21, 0x22,
0x3D, 0x01, 0x34, 0x05, 0x37, 0x34, 0x27, 0x26, 0x27, 0x26, 0x07, 0x06, 0x07, 0x0E, 0x01, 0x17,
0x1E, 0x01, 0x17, 0x16, 0x14, 0x07, 0x06, 0x26, 0x27, 0x26, 0x27, 0x22, 0x06, 0x07, 0x22, 0x17,
0x1E, 0x01, 0x17, 0x16, 0x37, 0x36, 0x27, 0x26, 0x27, 0x2E, 0x02, 0x37, 0x36, 0x33, 0x32, 0x1F,
0x02, 0x33, 0x35, 0x23, 0x11, 0x23, 0xD6, 0x03, 0x16, 0xFC, 0xEA, 0xC2, 0x01, 0xC6, 0x02, 0x01,
0x0C, 0x3A, 0x2B, 0x2D, 0x13, 0x10, 0x2B, 0x01, 0x33, 0x17, 0x55, 0x15, 0x04, 0x09, 0x14, 0x58,
0x0C, 0x04, 0x02, 0x02, 0x26, 0x14, 0x01, 0x03, 0x08, 0x33, 0x38, 0x5F, 0x20, 0x10, 0x01, 0x03,
0x3C, 0x12, 0x59, 0x11, 0x01, 0x02, 0x39, 0x2C, 0x09, 0x02, 0x9D, 0xE2, 0xA2, 0x40, 0x02, 0xAB,
0xFD, 0xB2, 0xD2, 0xAA, 0xD2, 0xDC, 0x03, 0x07, 0x0B, 0x38, 0x10, 0x0C, 0x09, 0x04, 0x08, 0x19,
0x6C, 0x17, 0x0B, 0x17, 0x11, 0x07, 0x17, 0x0A, 0x1A, 0x0A, 0x29, 0x0C, 0x04, 0x04, 0x02, 0x10,
0x25, 0x37, 0x04, 0x06, 0x37, 0x1D, 0x1C, 0x3F, 0x19, 0x08, 0x16, 0x13, 0x0B, 0x1F, 0x2B, 0x04,
0xE9, 0x37, 0x01, 0x13, 0x00, 0x04, 0x00, 0x14, 0x00, 0x5D, 0x03, 0xEC, 0x02, 0xAB, 0x00, 0x07,
0x00, 0x1F, 0x00, 0x2A, 0x00, 0x58, 0x00, 0x00, 0x01, 0x32, 0x1D, 0x01, 0x14, 0x23, 0x21, 0x11,
0x01, 0x33, 0x35, 0x17, 0x1E, 0x03, 0x3B, 0x01, 0x27, 0x2E, 0x01, 0x2F, 0x01, 0x36, 0x37, 0x36,
0x27, 0x26, 0x27, 0x26, 0x2B, 0x01, 0x17, 0x30, 0x23, 0x35, 0x33, 0x32, 0x16, 0x17, 0x16, 0x07,
0x06, 0x05, 0x16, 0x37, 0x36, 0x37, 0x3E, 0x01, 0x27, 0x2E, 0x03, 0x3E, 0x01, 0x17, 0x16, 0x17,
0x30, 0x37, 0x36, 0x27, 0x26, 0x27, 0x26, 0x27, 0x22, 0x06, 0x07, 0x06, 0x1E, 0x03, 0x17, 0x16,
0x07, 0x06, 0x26, 0x27, 0x26, 0x27, 0x07, 0x06, 0x23, 0x07, 0x16, 0x03, 0x2A, 0xC2, 0xC2, 0xFC,
0xEA, 0x01, 0xEC, 0x41, 0x11, 0x1F, 0x17, 0x4D, 0x02, 0x27, 0x26, 0x16, 0x1E, 0x1C, 0x17, 0x04,
0x43, 0x0C, 0x0B, 0x21, 0x18, 0x3E, 0x0F, 0x46, 0x47, 0x66, 0x25, 0x29, 0x3E, 0x1B, 0x03, 0x08,
0x22, 0x0C, 0xFE, 0x4D, 0x22, 0x59, 0x34, 0x1E, 0x2B, 0x03, 0x33, 0x16, 0x5C, 0x16, 0x0C, 0x18,
0x3C, 0x16, 0x0B, 0x05, 0x22, 0x21, 0x01, 0x03, 0x10, 0x1F, 0x49, 0x36, 0x43, 0x02, 0x01, 0x1C,
0x2D, 0x56, 0x1B, 0x04, 0x07, 0x20, 0x13, 0x4B, 0x0D, 0x01, 0x04, 0x1D, 0x1E, 0x02, 0x02, 0x04,
0x02, 0xAB, 0xD2, 0xAA, 0xD2, 0x02, 0x4E, 0xFE, 0x39, 0x89, 0x01, 0x01, 0x11, 0x75, 0x01, 0x25,
0x2F, 0x27, 0x0F, 0x08, 0x0C, 0x38, 0x33, 0x21, 0x19, 0x02, 0x01, 0x8A, 0x53, 0x0D, 0x0F, 0x2A,
0x09, 0x04, 0x8A, 0x3A, 0x03, 0x01, 0x12, 0x1B, 0x71, 0x1B, 0x0C, 0x17, 0x0D, 0x18, 0x17, 0x09,
0x11, 0x09, 0x1A, 0x01, 0x01, 0x07, 0x1E, 0x15, 0x29, 0x01, 0x2D, 0x2D, 0x1A, 0x2C, 0x16, 0x16,
0x0D, 0x0F, 0x1A, 0x14, 0x0C, 0x0D, 0x27, 0x04, 0x0C, 0x03, 0x03, 0x04, 0x1E, 0x00, 0x00, 0x00,
0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x17, 0x00, 0x00,
0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x15, 0x33, 0x15,
0x33, 0x35, 0x33, 0x35, 0x23, 0x35, 0x23, 0x15, 0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2,
0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0xC4, 0x50, 0xC4, 0xC5, 0x4E, 0x03, 0x70, 0x84, 0xE2, 0xFE,
0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE, 0xC0, 0x4F, 0xC5, 0xC5, 0x4E, 0xC5, 0xC4,
0x00, 0x02, 0x00, 0x14, 0xFF, 0x98, 0x03, 0xEC, 0x03, 0x70, 0x00, 0x0B, 0x00, 0x0F, 0x00, 0x00,
0x00, 0x20, 0x1E, 0x01, 0x10, 0x0E, 0x01, 0x20, 0x2E, 0x01, 0x10, 0x36, 0x13, 0x21, 0x35, 0x21,
0x01, 0x7A, 0x01, 0x0C, 0xE2, 0x84, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0x7C, 0x01, 0xD8,
0xFE, 0x28, 0x03, 0x70, 0x84, 0xE2, 0xFE, 0xF4, 0xE2, 0x84, 0x84, 0xE2, 0x01, 0x0C, 0xE2, 0xFE,
0x71, 0x4E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0xAE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x15, 0x00, 0x2C, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x10,
0x00, 0x64, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x07, 0x00, 0x85, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x10, 0x00, 0xAF, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x00, 0x10, 0x00, 0xE2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x0D,
0x01, 0x0F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x10, 0x01, 0x3F, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x00, 0x00, 0x2A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x01, 0x00, 0x20, 0x00, 0x42, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x02, 0x00, 0x0E,
0x00, 0x75, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x03, 0x00, 0x20, 0x00, 0x8D, 0x00, 0x03,
0x00, 0x01, 0x04, 0x09, 0x00, 0x04, 0x00, 0x20, 0x00, 0xC0, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09,
0x00, 0x05, 0x00, 0x1A, 0x00, 0xF3, 0x00, 0x03, 0x00, 0x01, 0x04, 0x09, 0x00, 0x06, 0x00, 0x20,
0x01, 0x1D, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x20, 0x00, 0x45, 0x00, 0x6D,
0x00, 0x75, 0x00, 0x6C, 0x00, 0x61, 0x00, 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x20, 0x00, 0x50,
0x00, 0x72, 0x00, 0x6F, 0x00, 0x6A, 0x00, 0x65, 0x00, 0x63, 0x00, 0x74, 0x00, 0x00, 0x59, 0x75,
0x7A, 0x75, 0x20, 0x45, 0x6D, 0x75, 0x6C, 0x61, 0x74, 0x6F, 0x72, 0x20, 0x50, 0x72, 0x6F, 0x6A,
0x65, 0x63, 0x74, 0x00, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53,
0x00, 0x53, 0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69,
0x00, 0x6F, 0x00, 0x6E, 0x00, 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74,
0x65, 0x6E, 0x73, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x52, 0x00, 0x65, 0x00, 0x67, 0x00, 0x75, 0x00,
0x6C, 0x00, 0x61, 0x00, 0x72, 0x00, 0x00, 0x52, 0x65, 0x67, 0x75, 0x6C, 0x61, 0x72, 0x00, 0x00,
0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00,
0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00,
0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F,
0x6E, 0x00, 0x00, 0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53,
0x00, 0x45, 0x00, 0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F,
0x00, 0x6E, 0x00, 0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E,
0x73, 0x69, 0x6F, 0x6E, 0x00, 0x00, 0x56, 0x00, 0x65, 0x00, 0x72, 0x00, 0x73, 0x00, 0x69, 0x00,
0x6F, 0x00, 0x6E, 0x00, 0x20, 0x00, 0x31, 0x00, 0x2E, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00,
0x00, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x31, 0x2E, 0x30, 0x30, 0x30, 0x00, 0x00,
0x59, 0x00, 0x75, 0x00, 0x7A, 0x00, 0x75, 0x00, 0x4F, 0x00, 0x53, 0x00, 0x53, 0x00, 0x45, 0x00,
0x78, 0x00, 0x74, 0x00, 0x65, 0x00, 0x6E, 0x00, 0x73, 0x00, 0x69, 0x00, 0x6F, 0x00, 0x6E, 0x00,
0x00, 0x59, 0x75, 0x7A, 0x75, 0x4F, 0x53, 0x53, 0x45, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F,
0x6E, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xB5, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x00, 0x03, 0x01, 0x04,
0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0A, 0x01, 0x0B, 0x01, 0x0C,
0x01, 0x0D, 0x01, 0x0E, 0x01, 0x0F, 0x01, 0x10, 0x01, 0x11, 0x01, 0x12, 0x01, 0x13, 0x01, 0x14,
0x01, 0x15, 0x01, 0x16, 0x01, 0x17, 0x01, 0x18, 0x01, 0x19, 0x01, 0x1A, 0x01, 0x1B, 0x07, 0x75,
0x6E, 0x69, 0x30, 0x30, 0x30, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x30, 0x30, 0x30, 0x44, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x41, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x31, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x41, 0x32, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x33, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x41, 0x34, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x35, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x41, 0x36, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x37, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x41, 0x38, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x41, 0x39, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x42, 0x33, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x42, 0x34, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x45, 0x30, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x31, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x45, 0x32, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x33, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x45, 0x34, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x35, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x45, 0x36, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x37, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x45, 0x38, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x45, 0x39, 0x07, 0x75,
0x6E, 0x69, 0x45, 0x30, 0x45, 0x46, 0x07, 0x75, 0x6E, 0x69, 0x45, 0x30, 0x46, 0x30, 0x00, 0x00,
0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x0F,
0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x01, 0x02, 0x01, 0x03, 0x00, 0x03, 0x01, 0x04,
0x01, 0x05, 0x01, 0x06, 0x01, 0x07, 0x01, 0x08, 0x01, 0x09, 0x01, 0x0a, 0x01, 0x0b, 0x01, 0x0c,
0x01, 0x0d, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30, 0x30, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x30, 0x30,
0x30, 0x44, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x30, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30,
0x45, 0x31, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x32, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30,
0x45, 0x33, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x34, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30,
0x45, 0x35, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x36, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30,
0x45, 0x37, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30, 0x45, 0x38, 0x07, 0x75, 0x6e, 0x69, 0x45, 0x30,
0x45, 0x39, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0xff, 0xff, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x00,
}};
} // namespace FileSys::SystemArchive::SharedFontData

View File

@@ -8,6 +8,6 @@
namespace FileSys::SystemArchive::SharedFontData {
extern const std::array<unsigned char, 6024> FONT_NINTENDO_EXTENDED;
extern const std::array<unsigned char, 2932> FONT_NINTENDO_EXTENDED;
} // namespace FileSys::SystemArchive::SharedFontData

View File

@@ -12,17 +12,17 @@ namespace SystemVersionData {
// This section should reflect the best system version to describe yuzu's HLE api.
// TODO(DarkLordZach): Update when HLE gets better.
constexpr u8 VERSION_MAJOR = 11;
constexpr u8 VERSION_MAJOR = 10;
constexpr u8 VERSION_MINOR = 0;
constexpr u8 VERSION_MICRO = 0;
constexpr u8 VERSION_MICRO = 2;
constexpr u8 REVISION_MAJOR = 5;
constexpr u8 REVISION_MAJOR = 1;
constexpr u8 REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "34197eba8810e2edd5e9dfcfbde7b340882e856d";
constexpr char DISPLAY_VERSION[] = "11.0.0";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 11.0.0-5.0";
constexpr char VERSION_HASH[] = "f90143fa8bbc061d4f68c35f95f04f8080c0ecdc";
constexpr char DISPLAY_VERSION[] = "10.0.2";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 10.0.2-1.0";
} // namespace SystemVersionData

View File

@@ -203,7 +203,7 @@ std::string VfsFile::GetFullPath() const {
return GetContainingDirectory()->GetFullPath() + "/" + GetName();
}
VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
std::shared_ptr<VfsFile> VfsDirectory::GetFileRelative(std::string_view path) const {
auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
@@ -231,7 +231,7 @@ VirtualFile VfsDirectory::GetFileRelative(std::string_view path) const {
return dir->GetFile(vec.back());
}
VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
std::shared_ptr<VfsFile> VfsDirectory::GetFileAbsolute(std::string_view path) const {
if (IsRoot()) {
return GetFileRelative(path);
}
@@ -239,7 +239,7 @@ VirtualFile VfsDirectory::GetFileAbsolute(std::string_view path) const {
return GetParentDirectory()->GetFileAbsolute(path);
}
VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryRelative(std::string_view path) const {
auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
@@ -261,7 +261,7 @@ VirtualDir VfsDirectory::GetDirectoryRelative(std::string_view path) const {
return dir;
}
VirtualDir VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
std::shared_ptr<VfsDirectory> VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
if (IsRoot()) {
return GetDirectoryRelative(path);
}
@@ -269,14 +269,14 @@ VirtualDir VfsDirectory::GetDirectoryAbsolute(std::string_view path) const {
return GetParentDirectory()->GetDirectoryAbsolute(path);
}
VirtualFile VfsDirectory::GetFile(std::string_view name) const {
std::shared_ptr<VfsFile> VfsDirectory::GetFile(std::string_view name) const {
const auto& files = GetFiles();
const auto iter = std::find_if(files.begin(), files.end(),
[&name](const auto& file1) { return name == file1->GetName(); });
return iter == files.end() ? nullptr : *iter;
}
VirtualDir VfsDirectory::GetSubdirectory(std::string_view name) const {
std::shared_ptr<VfsDirectory> VfsDirectory::GetSubdirectory(std::string_view name) const {
const auto& subs = GetSubdirectories();
const auto iter = std::find_if(subs.begin(), subs.end(),
[&name](const auto& file1) { return name == file1->GetName(); });
@@ -301,7 +301,7 @@ std::size_t VfsDirectory::GetSize() const {
return file_total + subdir_total;
}
VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) {
std::shared_ptr<VfsFile> VfsDirectory::CreateFileRelative(std::string_view path) {
auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
@@ -324,7 +324,7 @@ VirtualFile VfsDirectory::CreateFileRelative(std::string_view path) {
return dir->CreateFileRelative(Common::FS::GetPathWithoutTop(path));
}
VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
std::shared_ptr<VfsFile> VfsDirectory::CreateFileAbsolute(std::string_view path) {
if (IsRoot()) {
return CreateFileRelative(path);
}
@@ -332,7 +332,7 @@ VirtualFile VfsDirectory::CreateFileAbsolute(std::string_view path) {
return GetParentDirectory()->CreateFileAbsolute(path);
}
VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) {
std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryRelative(std::string_view path) {
auto vec = Common::FS::SplitPathComponents(path);
vec.erase(std::remove_if(vec.begin(), vec.end(), [](const auto& str) { return str.empty(); }),
vec.end());
@@ -355,7 +355,7 @@ VirtualDir VfsDirectory::CreateDirectoryRelative(std::string_view path) {
return dir->CreateDirectoryRelative(Common::FS::GetPathWithoutTop(path));
}
VirtualDir VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
std::shared_ptr<VfsDirectory> VfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
if (IsRoot()) {
return CreateDirectoryRelative(path);
}
@@ -446,27 +446,27 @@ bool ReadOnlyVfsDirectory::IsReadable() const {
return true;
}
VirtualDir ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) {
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateSubdirectory(std::string_view name) {
return nullptr;
}
VirtualFile ReadOnlyVfsDirectory::CreateFile(std::string_view name) {
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFile(std::string_view name) {
return nullptr;
}
VirtualFile ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileAbsolute(std::string_view path) {
return nullptr;
}
VirtualFile ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
std::shared_ptr<VfsFile> ReadOnlyVfsDirectory::CreateFileRelative(std::string_view path) {
return nullptr;
}
VirtualDir ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryAbsolute(std::string_view path) {
return nullptr;
}
VirtualDir ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
std::shared_ptr<VfsDirectory> ReadOnlyVfsDirectory::CreateDirectoryRelative(std::string_view path) {
return nullptr;
}

View File

@@ -91,7 +91,7 @@ public:
// Resizes the file to new_size. Returns whether or not the operation was successful.
virtual bool Resize(std::size_t new_size) = 0;
// Gets a pointer to the directory containing this file, returning nullptr if there is none.
virtual VirtualDir GetContainingDirectory() const = 0;
virtual std::shared_ptr<VfsDirectory> GetContainingDirectory() const = 0;
// Returns whether or not the file can be written to.
virtual bool IsWritable() const = 0;
@@ -183,27 +183,27 @@ public:
// Retrives the file located at path as if the current directory was root. Returns nullptr if
// not found.
virtual VirtualFile GetFileRelative(std::string_view path) const;
virtual std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const;
// Calls GetFileRelative(path) on the root of the current directory.
virtual VirtualFile GetFileAbsolute(std::string_view path) const;
virtual std::shared_ptr<VfsFile> GetFileAbsolute(std::string_view path) const;
// Retrives the directory located at path as if the current directory was root. Returns nullptr
// if not found.
virtual VirtualDir GetDirectoryRelative(std::string_view path) const;
virtual std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const;
// Calls GetDirectoryRelative(path) on the root of the current directory.
virtual VirtualDir GetDirectoryAbsolute(std::string_view path) const;
virtual std::shared_ptr<VfsDirectory> GetDirectoryAbsolute(std::string_view path) const;
// Returns a vector containing all of the files in this directory.
virtual std::vector<VirtualFile> GetFiles() const = 0;
virtual std::vector<std::shared_ptr<VfsFile>> GetFiles() const = 0;
// Returns the file with filename matching name. Returns nullptr if directory dosen't have a
// file with name.
virtual VirtualFile GetFile(std::string_view name) const;
virtual std::shared_ptr<VfsFile> GetFile(std::string_view name) const;
// Returns a vector containing all of the subdirectories in this directory.
virtual std::vector<VirtualDir> GetSubdirectories() const = 0;
virtual std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const = 0;
// Returns the directory with name matching name. Returns nullptr if directory dosen't have a
// directory with name.
virtual VirtualDir GetSubdirectory(std::string_view name) const;
virtual std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const;
// Returns whether or not the directory can be written to.
virtual bool IsWritable() const = 0;
@@ -219,31 +219,31 @@ public:
virtual std::size_t GetSize() const;
// Returns the parent directory of this directory. Returns nullptr if this directory is root or
// has no parent.
virtual VirtualDir GetParentDirectory() const = 0;
virtual std::shared_ptr<VfsDirectory> GetParentDirectory() const = 0;
// Creates a new subdirectory with name name. Returns a pointer to the new directory or nullptr
// if the operation failed.
virtual VirtualDir CreateSubdirectory(std::string_view name) = 0;
virtual std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) = 0;
// Creates a new file with name name. Returns a pointer to the new file or nullptr if the
// operation failed.
virtual VirtualFile CreateFile(std::string_view name) = 0;
virtual std::shared_ptr<VfsFile> CreateFile(std::string_view name) = 0;
// Creates a new file at the path relative to this directory. Also creates directories if
// they do not exist and is supported by this implementation. Returns nullptr on any failure.
virtual VirtualFile CreateFileRelative(std::string_view path);
virtual std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path);
// Creates a new file at the path relative to root of this directory. Also creates directories
// if they do not exist and is supported by this implementation. Returns nullptr on any failure.
virtual VirtualFile CreateFileAbsolute(std::string_view path);
virtual std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path);
// Creates a new directory at the path relative to this directory. Also creates directories if
// they do not exist and is supported by this implementation. Returns nullptr on any failure.
virtual VirtualDir CreateDirectoryRelative(std::string_view path);
virtual std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path);
// Creates a new directory at the path relative to root of this directory. Also creates
// directories if they do not exist and is supported by this implementation. Returns nullptr on
// any failure.
virtual VirtualDir CreateDirectoryAbsolute(std::string_view path);
virtual std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path);
// Deletes the subdirectory with the given name and returns true on success.
virtual bool DeleteSubdirectory(std::string_view name) = 0;
@@ -280,12 +280,12 @@ class ReadOnlyVfsDirectory : public VfsDirectory {
public:
bool IsWritable() const override;
bool IsReadable() const override;
VirtualDir CreateSubdirectory(std::string_view name) override;
VirtualFile CreateFile(std::string_view name) override;
VirtualFile CreateFileAbsolute(std::string_view path) override;
VirtualFile CreateFileRelative(std::string_view path) override;
VirtualDir CreateDirectoryAbsolute(std::string_view path) override;
VirtualDir CreateDirectoryRelative(std::string_view path) override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFileAbsolute(std::string_view path) override;
std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
std::shared_ptr<VfsDirectory> CreateDirectoryAbsolute(std::string_view path) override;
std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
bool DeleteSubdirectory(std::string_view name) override;
bool DeleteSubdirectoryRecursive(std::string_view name) override;
bool CleanSubdirectoryRecursive(std::string_view name) override;

View File

@@ -46,7 +46,7 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> f
if (files.size() == 1)
return files[0];
return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
}
VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
@@ -71,23 +71,20 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte,
if (files.begin()->first != 0)
files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first));
return VirtualFile(new ConcatenatedVfsFile(std::move(files), std::move(name)));
return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name)));
}
std::string ConcatenatedVfsFile::GetName() const {
if (files.empty()) {
if (files.empty())
return "";
}
if (!name.empty()) {
if (!name.empty())
return name;
}
return files.begin()->second->GetName();
}
std::size_t ConcatenatedVfsFile::GetSize() const {
if (files.empty()) {
if (files.empty())
return 0;
}
return files.rbegin()->first + files.rbegin()->second->GetSize();
}
@@ -95,10 +92,9 @@ bool ConcatenatedVfsFile::Resize(std::size_t new_size) {
return false;
}
VirtualDir ConcatenatedVfsFile::GetContainingDirectory() const {
if (files.empty()) {
std::shared_ptr<VfsDirectory> ConcatenatedVfsFile::GetContainingDirectory() const {
if (files.empty())
return nullptr;
}
return files.begin()->second->GetContainingDirectory();
}

View File

@@ -31,7 +31,7 @@ public:
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
VirtualDir GetContainingDirectory() const override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;

View File

@@ -20,10 +20,10 @@ VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dir
if (dirs.size() == 1)
return dirs[0];
return VirtualDir(new LayeredVfsDirectory(std::move(dirs), std::move(name)));
return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name)));
}
VirtualFile LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
for (const auto& layer : dirs) {
const auto file = layer->GetFileRelative(path);
if (file != nullptr)
@@ -33,23 +33,23 @@ VirtualFile LayeredVfsDirectory::GetFileRelative(std::string_view path) const {
return nullptr;
}
VirtualDir LayeredVfsDirectory::GetDirectoryRelative(std::string_view path) const {
std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative(
std::string_view path) const {
std::vector<VirtualDir> out;
for (const auto& layer : dirs) {
auto dir = layer->GetDirectoryRelative(path);
if (dir != nullptr) {
if (dir != nullptr)
out.push_back(std::move(dir));
}
}
return MakeLayeredDirectory(std::move(out));
}
VirtualFile LayeredVfsDirectory::GetFile(std::string_view name) const {
std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const {
return GetFileRelative(name);
}
VirtualDir LayeredVfsDirectory::GetSubdirectory(std::string_view name) const {
std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetSubdirectory(std::string_view name) const {
return GetDirectoryRelative(name);
}
@@ -57,7 +57,7 @@ std::string LayeredVfsDirectory::GetFullPath() const {
return dirs[0]->GetFullPath();
}
std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
std::vector<std::shared_ptr<VfsFile>> LayeredVfsDirectory::GetFiles() const {
std::vector<VirtualFile> out;
for (const auto& layer : dirs) {
for (const auto& file : layer->GetFiles()) {
@@ -72,7 +72,7 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const {
return out;
}
std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const {
std::vector<std::shared_ptr<VfsDirectory>> LayeredVfsDirectory::GetSubdirectories() const {
std::vector<std::string> names;
for (const auto& layer : dirs) {
for (const auto& sd : layer->GetSubdirectories()) {
@@ -101,15 +101,15 @@ std::string LayeredVfsDirectory::GetName() const {
return name.empty() ? dirs[0]->GetName() : name;
}
VirtualDir LayeredVfsDirectory::GetParentDirectory() const {
std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetParentDirectory() const {
return dirs[0]->GetParentDirectory();
}
VirtualDir LayeredVfsDirectory::CreateSubdirectory(std::string_view name) {
std::shared_ptr<VfsDirectory> LayeredVfsDirectory::CreateSubdirectory(std::string_view name) {
return nullptr;
}
VirtualFile LayeredVfsDirectory::CreateFile(std::string_view name) {
std::shared_ptr<VfsFile> LayeredVfsDirectory::CreateFile(std::string_view name) {
return nullptr;
}

View File

@@ -21,20 +21,20 @@ public:
/// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases.
static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = "");
VirtualFile GetFileRelative(std::string_view path) const override;
VirtualDir GetDirectoryRelative(std::string_view path) const override;
VirtualFile GetFile(std::string_view name) const override;
VirtualDir GetSubdirectory(std::string_view name) const override;
std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override;
std::string GetFullPath() const override;
std::vector<VirtualFile> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
VirtualDir CreateSubdirectory(std::string_view name) override;
VirtualFile CreateFile(std::string_view name) override;
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
bool DeleteSubdirectory(std::string_view name) override;
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;

View File

@@ -9,7 +9,7 @@
namespace FileSys {
OffsetVfsFile::OffsetVfsFile(VirtualFile file_, std::size_t size_, std::size_t offset_,
OffsetVfsFile::OffsetVfsFile(std::shared_ptr<VfsFile> file_, std::size_t size_, std::size_t offset_,
std::string name_, VirtualDir parent_)
: file(file_), offset(offset_), size(size_), name(std::move(name_)),
parent(parent_ == nullptr ? file->GetContainingDirectory() : std::move(parent_)) {}
@@ -37,7 +37,7 @@ bool OffsetVfsFile::Resize(std::size_t new_size) {
return true;
}
VirtualDir OffsetVfsFile::GetContainingDirectory() const {
std::shared_ptr<VfsDirectory> OffsetVfsFile::GetContainingDirectory() const {
return parent;
}

View File

@@ -17,14 +17,14 @@ namespace FileSys {
// the size of this wrapper.
class OffsetVfsFile : public VfsFile {
public:
OffsetVfsFile(VirtualFile file, std::size_t size, std::size_t offset = 0,
OffsetVfsFile(std::shared_ptr<VfsFile> file, std::size_t size, std::size_t offset = 0,
std::string new_name = "", VirtualDir new_parent = nullptr);
~OffsetVfsFile() override;
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
VirtualDir GetContainingDirectory() const override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
@@ -42,7 +42,7 @@ public:
private:
std::size_t TrimToFit(std::size_t r_size, std::size_t r_offset) const;
VirtualFile file;
std::shared_ptr<VfsFile> file;
std::size_t offset;
std::size_t size;
std::string name;

View File

@@ -263,7 +263,7 @@ bool RealVfsFile::Resize(std::size_t new_size) {
return backing->Resize(new_size);
}
VirtualDir RealVfsFile::GetContainingDirectory() const {
std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const {
return base.OpenDirectory(parent_path, perms);
}
@@ -352,7 +352,7 @@ RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string&
RealVfsDirectory::~RealVfsDirectory() = default;
VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const {
std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const {
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
if (!FS::Exists(full_path) || FS::IsDirectory(full_path)) {
return nullptr;
@@ -360,7 +360,7 @@ VirtualFile RealVfsDirectory::GetFileRelative(std::string_view path) const {
return base.OpenFile(full_path, perms);
}
VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
if (!FS::Exists(full_path) || !FS::IsDirectory(full_path)) {
return nullptr;
@@ -368,20 +368,20 @@ VirtualDir RealVfsDirectory::GetDirectoryRelative(std::string_view path) const {
return base.OpenDirectory(full_path, perms);
}
VirtualFile RealVfsDirectory::GetFile(std::string_view name) const {
std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const {
return GetFileRelative(name);
}
VirtualDir RealVfsDirectory::GetSubdirectory(std::string_view name) const {
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const {
return GetDirectoryRelative(name);
}
VirtualFile RealVfsDirectory::CreateFileRelative(std::string_view path) {
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) {
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
return base.CreateFile(full_path, perms);
}
VirtualDir RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) {
const auto full_path = FS::SanitizePath(this->path + DIR_SEP + std::string(path));
return base.CreateDirectory(full_path, perms);
}
@@ -391,11 +391,11 @@ bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) {
return base.DeleteDirectory(full_path);
}
std::vector<VirtualFile> RealVfsDirectory::GetFiles() const {
std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const {
return IterateEntries<RealVfsFile, VfsFile>();
}
std::vector<VirtualDir> RealVfsDirectory::GetSubdirectories() const {
std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const {
return IterateEntries<RealVfsDirectory, VfsDirectory>();
}
@@ -411,7 +411,7 @@ std::string RealVfsDirectory::GetName() const {
return path_components.back();
}
VirtualDir RealVfsDirectory::GetParentDirectory() const {
std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const {
if (path_components.size() <= 1) {
return nullptr;
}
@@ -419,12 +419,12 @@ VirtualDir RealVfsDirectory::GetParentDirectory() const {
return base.OpenDirectory(parent_path, perms);
}
VirtualDir RealVfsDirectory::CreateSubdirectory(std::string_view name) {
std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) {
const std::string subdir_path = (path + DIR_SEP).append(name);
return base.CreateDirectory(subdir_path, perms);
}
VirtualFile RealVfsDirectory::CreateFile(std::string_view name) {
std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) {
const std::string file_path = (path + DIR_SEP).append(name);
return base.CreateFile(file_path, perms);
}

View File

@@ -50,7 +50,7 @@ public:
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
VirtualDir GetContainingDirectory() const override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
@@ -79,21 +79,21 @@ class RealVfsDirectory : public VfsDirectory {
public:
~RealVfsDirectory() override;
VirtualFile GetFileRelative(std::string_view path) const override;
VirtualDir GetDirectoryRelative(std::string_view path) const override;
VirtualFile GetFile(std::string_view name) const override;
VirtualDir GetSubdirectory(std::string_view name) const override;
VirtualFile CreateFileRelative(std::string_view path) override;
VirtualDir CreateDirectoryRelative(std::string_view path) override;
std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override;
std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override;
std::shared_ptr<VfsFile> GetFile(std::string_view name) const override;
std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override;
std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override;
std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override;
bool DeleteSubdirectoryRecursive(std::string_view name) override;
std::vector<VirtualFile> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
VirtualDir CreateSubdirectory(std::string_view name) override;
VirtualFile CreateFile(std::string_view name) override;
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
bool DeleteSubdirectory(std::string_view name) override;
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;

View File

@@ -31,7 +31,7 @@ public:
return true;
}
VirtualDir GetContainingDirectory() const override {
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
return parent;
}

View File

@@ -25,7 +25,7 @@ bool VectorVfsFile::Resize(size_t new_size) {
return true;
}
VirtualDir VectorVfsFile::GetContainingDirectory() const {
std::shared_ptr<VfsDirectory> VectorVfsFile::GetContainingDirectory() const {
return parent;
}
@@ -68,11 +68,11 @@ VectorVfsDirectory::VectorVfsDirectory(std::vector<VirtualFile> files_,
VectorVfsDirectory::~VectorVfsDirectory() = default;
std::vector<VirtualFile> VectorVfsDirectory::GetFiles() const {
std::vector<std::shared_ptr<VfsFile>> VectorVfsDirectory::GetFiles() const {
return files;
}
std::vector<VirtualDir> VectorVfsDirectory::GetSubdirectories() const {
std::vector<std::shared_ptr<VfsDirectory>> VectorVfsDirectory::GetSubdirectories() const {
return dirs;
}
@@ -88,7 +88,7 @@ std::string VectorVfsDirectory::GetName() const {
return name;
}
VirtualDir VectorVfsDirectory::GetParentDirectory() const {
std::shared_ptr<VfsDirectory> VectorVfsDirectory::GetParentDirectory() const {
return parent;
}
@@ -116,11 +116,11 @@ bool VectorVfsDirectory::Rename(std::string_view name_) {
return true;
}
VirtualDir VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
std::shared_ptr<VfsDirectory> VectorVfsDirectory::CreateSubdirectory(std::string_view name) {
return nullptr;
}
VirtualFile VectorVfsDirectory::CreateFile(std::string_view name) {
std::shared_ptr<VfsFile> VectorVfsDirectory::CreateFile(std::string_view name) {
return nullptr;
}

View File

@@ -17,9 +17,9 @@ namespace FileSys {
template <std::size_t size>
class ArrayVfsFile : public VfsFile {
public:
explicit ArrayVfsFile(const std::array<u8, size>& data_, std::string name_ = "",
VirtualDir parent_ = nullptr)
: data(data_), name(std::move(name_)), parent(std::move(parent_)) {}
explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "",
VirtualDir parent = nullptr)
: data(data), name(std::move(name)), parent(std::move(parent)) {}
std::string GetName() const override {
return name;
@@ -33,7 +33,7 @@ public:
return false;
}
VirtualDir GetContainingDirectory() const override {
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override {
return parent;
}
@@ -51,12 +51,12 @@ public:
return read;
}
std::size_t Write(const u8* data_, std::size_t length, std::size_t offset) override {
std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override {
return 0;
}
bool Rename(std::string_view new_name) override {
name = new_name;
bool Rename(std::string_view name) override {
this->name = name;
return true;
}
@@ -82,7 +82,7 @@ public:
std::string GetName() const override;
std::size_t GetSize() const override;
bool Resize(std::size_t new_size) override;
VirtualDir GetContainingDirectory() const override;
std::shared_ptr<VfsDirectory> GetContainingDirectory() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
@@ -106,17 +106,17 @@ public:
VirtualDir parent = nullptr);
~VectorVfsDirectory() override;
std::vector<VirtualFile> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
bool IsWritable() const override;
bool IsReadable() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
bool DeleteSubdirectory(std::string_view name) override;
bool DeleteFile(std::string_view name) override;
bool Rename(std::string_view name) override;
VirtualDir CreateSubdirectory(std::string_view name) override;
VirtualFile CreateFile(std::string_view name) override;
std::shared_ptr<VfsDirectory> CreateSubdirectory(std::string_view name) override;
std::shared_ptr<VfsFile> CreateFile(std::string_view name) override;
virtual void AddFile(VirtualFile file);
virtual void AddDirectory(VirtualDir dir);

View File

@@ -152,11 +152,11 @@ NAXContentType NAX::GetContentType() const {
return type;
}
std::vector<VirtualFile> NAX::GetFiles() const {
std::vector<std::shared_ptr<VfsFile>> NAX::GetFiles() const {
return {dec_file};
}
std::vector<VirtualDir> NAX::GetSubdirectories() const {
std::vector<std::shared_ptr<VfsDirectory>> NAX::GetSubdirectories() const {
return {};
}
@@ -164,7 +164,7 @@ std::string NAX::GetName() const {
return file->GetName();
}
VirtualDir NAX::GetParentDirectory() const {
std::shared_ptr<VfsDirectory> NAX::GetParentDirectory() const {
return file->GetContainingDirectory();
}

View File

@@ -47,13 +47,13 @@ public:
NAXContentType GetContentType() const;
std::vector<VirtualFile> GetFiles() const override;
std::vector<std::shared_ptr<VfsFile>> GetFiles() const override;
std::vector<VirtualDir> GetSubdirectories() const override;
std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override;
std::string GetName() const override;
VirtualDir GetParentDirectory() const override;
std::shared_ptr<VfsDirectory> GetParentDirectory() const override;
private:
Loader::ResultStatus Parse(std::string_view path);

View File

@@ -2,7 +2,6 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include "common/logging/log.h"
#include "core/frontend/applets/error.h"
namespace Core::Frontend {
@@ -11,7 +10,7 @@ ErrorApplet::~ErrorApplet() = default;
void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const {
LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
error.module.Value(), error.description.Value(), error.raw);
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw);
}
void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
@@ -19,7 +18,7 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::s
LOG_CRITICAL(
Service_Fatal,
"Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
error.module.Value(), error.description.Value(), error.raw, time.count());
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count());
}
void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text,
@@ -27,7 +26,7 @@ void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_
std::function<void()> finished) const {
LOG_CRITICAL(Service_Fatal,
"Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
error.module.Value(), error.description.Value(), error.raw);
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw);
LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text);
LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text);
}

View File

@@ -53,4 +53,72 @@ void DefaultPhotoViewerApplet::ShowAllPhotos(std::function<void()> finished) con
finished();
}
ECommerceApplet::~ECommerceApplet() = default;
DefaultECommerceApplet::~DefaultECommerceApplet() = default;
void DefaultECommerceApplet::ShowApplicationInformation(
std::function<void()> finished, u64 title_id, std::optional<u128> user_id,
std::optional<bool> full_display, std::optional<std::string> extra_parameter) {
const auto value = user_id.value_or(u128{});
LOG_INFO(Service_AM,
"Application requested frontend show application information for EShop, "
"title_id={:016X}, user_id={:016X}{:016X}, full_display={}, extra_parameter={}",
title_id, value[1], value[0],
full_display.has_value() ? fmt::format("{}", *full_display) : "null",
extra_parameter.value_or("null"));
finished();
}
void DefaultECommerceApplet::ShowAddOnContentList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id,
std::optional<bool> full_display) {
const auto value = user_id.value_or(u128{});
LOG_INFO(Service_AM,
"Application requested frontend show add on content list for EShop, "
"title_id={:016X}, user_id={:016X}{:016X}, full_display={}",
title_id, value[1], value[0],
full_display.has_value() ? fmt::format("{}", *full_display) : "null");
finished();
}
void DefaultECommerceApplet::ShowSubscriptionList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id) {
const auto value = user_id.value_or(u128{});
LOG_INFO(Service_AM,
"Application requested frontend show subscription list for EShop, title_id={:016X}, "
"user_id={:016X}{:016X}",
title_id, value[1], value[0]);
finished();
}
void DefaultECommerceApplet::ShowConsumableItemList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id) {
const auto value = user_id.value_or(u128{});
LOG_INFO(
Service_AM,
"Application requested frontend show consumable item list for EShop, title_id={:016X}, "
"user_id={:016X}{:016X}",
title_id, value[1], value[0]);
finished();
}
void DefaultECommerceApplet::ShowShopHome(std::function<void()> finished, u128 user_id,
bool full_display) {
LOG_INFO(Service_AM,
"Application requested frontend show home menu for EShop, user_id={:016X}{:016X}, "
"full_display={}",
user_id[1], user_id[0], full_display);
finished();
}
void DefaultECommerceApplet::ShowSettings(std::function<void()> finished, u128 user_id,
bool full_display) {
LOG_INFO(Service_AM,
"Application requested frontend show settings menu for EShop, user_id={:016X}{:016X}, "
"full_display={}",
user_id[1], user_id[0], full_display);
finished();
}
} // namespace Core::Frontend

View File

@@ -58,4 +58,55 @@ public:
void ShowAllPhotos(std::function<void()> finished) const override;
};
class ECommerceApplet {
public:
virtual ~ECommerceApplet();
// Shows a page with application icons, description, name, and price.
virtual void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id = {},
std::optional<bool> full_display = {},
std::optional<std::string> extra_parameter = {}) = 0;
// Shows a page with all of the add on content available for a game, with name, description, and
// price.
virtual void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id = {},
std::optional<bool> full_display = {}) = 0;
// Shows a page with all of the subscriptions (recurring payments) for a game, with name,
// description, price, and renewal period.
virtual void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id = {}) = 0;
// Shows a page with a list of any additional game related purchasable items (DLC,
// subscriptions, etc) for a particular game, with name, description, type, and price.
virtual void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id = {}) = 0;
// Shows the home page of the shop.
virtual void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) = 0;
// Shows the user settings page of the shop.
virtual void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) = 0;
};
class DefaultECommerceApplet : public ECommerceApplet {
public:
~DefaultECommerceApplet() override;
void ShowApplicationInformation(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id, std::optional<bool> full_display,
std::optional<std::string> extra_parameter) override;
void ShowAddOnContentList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id,
std::optional<bool> full_display) override;
void ShowSubscriptionList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id) override;
void ShowConsumableItemList(std::function<void()> finished, u64 title_id,
std::optional<u128> user_id) override;
void ShowShopHome(std::function<void()> finished, u128 user_id, bool full_display) override;
void ShowSettings(std::function<void()> finished, u128 user_id, bool full_display) override;
};
} // namespace Core::Frontend

View File

@@ -11,22 +11,14 @@ WebBrowserApplet::~WebBrowserApplet() = default;
DefaultWebBrowserApplet::~DefaultWebBrowserApplet() = default;
void DefaultWebBrowserApplet::OpenLocalWebPage(
std::string_view local_url, std::function<void()> extract_romfs_callback,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open local web page at {}",
local_url);
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
}
void DefaultWebBrowserApplet::OpenExternalWebPage(
std::string_view external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const {
LOG_WARNING(Service_AM, "(STUBBED) called, backend requested to open external web page at {}",
external_url);
callback(Service::AM::Applets::WebExitReason::WindowClosed, "http://localhost/");
void DefaultWebBrowserApplet::OpenPageLocal(std::string_view filename,
std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) {
LOG_INFO(Service_AM,
"(STUBBED) called - No suitable web browser implementation found to open website page "
"at '{}'!",
filename);
finished_callback();
}
} // namespace Core::Frontend

View File

@@ -7,34 +7,22 @@
#include <functional>
#include <string_view>
#include "core/hle/service/am/applets/web_types.h"
namespace Core::Frontend {
class WebBrowserApplet {
public:
virtual ~WebBrowserApplet();
virtual void OpenLocalWebPage(
std::string_view local_url, std::function<void()> extract_romfs_callback,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
virtual void OpenExternalWebPage(
std::string_view external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)> callback) const = 0;
virtual void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) = 0;
};
class DefaultWebBrowserApplet final : public WebBrowserApplet {
public:
~DefaultWebBrowserApplet() override;
void OpenLocalWebPage(std::string_view local_url, std::function<void()> extract_romfs_callback,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback) const override;
void OpenExternalWebPage(std::string_view external_url,
std::function<void(Service::AM::Applets::WebExitReason, std::string)>
callback) const override;
void OpenPageLocal(std::string_view url, std::function<void()> unpack_romfs_callback,
std::function<void()> finished_callback) override;
};
} // namespace Core::Frontend

View File

@@ -102,8 +102,8 @@ public:
float render_surface_scale = 1.0f;
};
/// Called from GPU thread when a frame is displayed.
virtual void OnFrameDisplayed() {}
/// Polls window events
virtual void PollEvents() = 0;
/**
* Returns a GraphicsContext that the frontend provides to be used for rendering.

View File

@@ -30,12 +30,10 @@ public:
virtual StatusType GetStatus() const {
return {};
}
virtual bool GetAnalogDirectionStatus([[maybe_unused]] AnalogDirection direction) const {
virtual bool GetAnalogDirectionStatus(AnalogDirection direction) const {
return {};
}
virtual bool SetRumblePlay([[maybe_unused]] f32 amp_low, [[maybe_unused]] f32 freq_low,
[[maybe_unused]] f32 amp_high,
[[maybe_unused]] f32 freq_high) const {
virtual bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const {
return {};
}
};
@@ -163,15 +161,10 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common
using MotionDevice = InputDevice<MotionStatus>;
/**
* A touch status is an object that returns a tuple of two floats and a bool. The floats are
* A touch device is an input device that returns a tuple of two floats and a bool. The floats are
* x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed.
*/
using TouchStatus = std::tuple<float, float, bool>;
/**
* A touch device is an input device that returns a touch status object
*/
using TouchDevice = InputDevice<TouchStatus>;
using TouchDevice = InputDevice<std::tuple<float, float, bool>>;
/**
* A mouse device is an input device that returns a tuple of two floats and four ints.

Some files were not shown because too many files have changed in this diff Show More