mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
htc: implement service channel parsing (ReceiveReadyPacket)
This commit is contained in:
parent
4e9bc617bb
commit
6fc24d8883
5 changed files with 322 additions and 0 deletions
80
libraries/libstratosphere/source/htclow/ctrl/htclow_json.cpp
Normal file
80
libraries/libstratosphere/source/htclow/ctrl/htclow_json.cpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "htclow_json.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr const char ChannelKey[] = "Chan";
|
||||
constexpr const char ProtocolVersionKey[] = "Prot";
|
||||
|
||||
}
|
||||
|
||||
bool JsonHandler::Key(const Ch *str, rapidjson::SizeType len, bool copy) {
|
||||
if (m_state == State::ParseObject) {
|
||||
if (!util::Strncmp(str, ChannelKey, sizeof(ChannelKey))) {
|
||||
m_state = State::ParseServiceChannels;
|
||||
}
|
||||
if (!util::Strncmp(str, ProtocolVersionKey, sizeof(ProtocolVersionKey))) {
|
||||
m_state = State::ParseProtocolVersion;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::Uint(unsigned val) {
|
||||
if (m_state == State::ParseProtocolVersion) {
|
||||
*m_version = val;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::String(const Ch *str, rapidjson::SizeType len, bool copy) {
|
||||
if (m_state == State::ParseServiceChannelsArray && *m_num_strings < m_max_strings) {
|
||||
m_strings[(*m_num_strings)++] = str;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::StartObject() {
|
||||
if (m_state == State::Begin) {
|
||||
m_state = State::ParseObject;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::EndObject(rapidjson::SizeType) {
|
||||
m_state = State::End;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::StartArray() {
|
||||
if (m_state == State::ParseServiceChannels) {
|
||||
m_state = State::ParseServiceChannelsArray;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JsonHandler::EndArray(rapidjson::SizeType len) {
|
||||
if (m_state == State::ParseServiceChannelsArray && len) {
|
||||
m_state = State::ParseObject;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
50
libraries/libstratosphere/source/htclow/ctrl/htclow_json.hpp
Normal file
50
libraries/libstratosphere/source/htclow/ctrl/htclow_json.hpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
class JsonHandler : public rapidjson::BaseReaderHandler<rapidjson::UTF8<char>, JsonHandler>{
|
||||
private:
|
||||
enum class State {
|
||||
Begin = 0,
|
||||
ParseObject = 1,
|
||||
ParseServiceChannels = 2,
|
||||
ParseServiceChannelsArray = 3,
|
||||
ParseProtocolVersion = 4,
|
||||
End = 5,
|
||||
};
|
||||
private:
|
||||
State m_state;
|
||||
s16 *m_version;
|
||||
const char **m_strings;
|
||||
int *m_num_strings;
|
||||
int m_max_strings;
|
||||
public:
|
||||
JsonHandler(s16 *vers, const char **str, int *ns, int max) : m_state(State::Begin), m_version(vers), m_strings(str), m_num_strings(ns), m_max_strings(max) { /* ... */ }
|
||||
|
||||
bool Key(const Ch *str, rapidjson::SizeType len, bool copy);
|
||||
bool Uint(unsigned);
|
||||
bool String(const Ch *, rapidjson::SizeType, bool);
|
||||
|
||||
bool StartObject();
|
||||
bool EndObject(rapidjson::SizeType);
|
||||
bool StartArray();
|
||||
bool EndArray(rapidjson::SizeType);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "htclow_json.hpp"
|
||||
#include "htclow_service_channel_parser.hpp"
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
namespace {
|
||||
|
||||
void ParseBody(s16 *out_version, const char **out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size) {
|
||||
/* Create JSON handler. */
|
||||
JsonHandler json_handler(out_version, out_channels, out_num_channels, max_channels);
|
||||
|
||||
/* Create reader. */
|
||||
rapidjson::Reader json_reader;
|
||||
|
||||
/* Create stream. */
|
||||
rapidjson::InsituStringStream json_stream(static_cast<char *>(str));
|
||||
|
||||
/* Parse the json. */
|
||||
json_reader.Parse(json_stream, json_handler);
|
||||
}
|
||||
|
||||
constexpr bool IsNumericCharacter(char c) {
|
||||
return '0' <= c && c <= '9';
|
||||
}
|
||||
|
||||
constexpr bool IsValidCharacter(char c) {
|
||||
return IsNumericCharacter(c) || c == ':';
|
||||
}
|
||||
|
||||
bool IntegerToModuleId(ModuleId *out, int id) {
|
||||
switch (id) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 3:
|
||||
case 4:
|
||||
*out = static_cast<ModuleId>(id);
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool StringToChannel(impl::ChannelInternalType *out, char *str, size_t size) {
|
||||
enum class State {
|
||||
Begin,
|
||||
ModuleId,
|
||||
Sep1,
|
||||
Reserved,
|
||||
Sep2,
|
||||
ChannelId
|
||||
};
|
||||
|
||||
State state = State::Begin;
|
||||
|
||||
const char * cur = nullptr;
|
||||
|
||||
const char * const str_end = str + size;
|
||||
while (str < str_end && IsValidCharacter(*str)) {
|
||||
const char c = *str;
|
||||
|
||||
switch (state) {
|
||||
case State::Begin:
|
||||
if (IsNumericCharacter(c)) {
|
||||
cur = str;
|
||||
state = State::ModuleId;
|
||||
}
|
||||
break;
|
||||
case State::ModuleId:
|
||||
if (c == ':') {
|
||||
*str = 0;
|
||||
if (!IntegerToModuleId(std::addressof(out->module_id), atoi(cur))) {
|
||||
return false;
|
||||
}
|
||||
state = State::Sep1;
|
||||
} else if (!IsNumericCharacter(c)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case State::Sep1:
|
||||
if (IsNumericCharacter(c)) {
|
||||
cur = str;
|
||||
state = State::Reserved;
|
||||
}
|
||||
break;
|
||||
case State::Reserved:
|
||||
if (c == ':') {
|
||||
*str = 0;
|
||||
out->reserved = 0;
|
||||
state = State::Sep2;
|
||||
} else if (!IsNumericCharacter(c)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case State::Sep2:
|
||||
if (IsNumericCharacter(c)) {
|
||||
cur = str;
|
||||
state = State::ChannelId;
|
||||
}
|
||||
break;
|
||||
case State::ChannelId:
|
||||
if (!IsNumericCharacter(c)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
++str;
|
||||
}
|
||||
|
||||
if (str != str_end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
out->channel_id = atoi(cur);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ParseServiceChannel(s16 *out_version, impl::ChannelInternalType *out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size) {
|
||||
/* Parse the JSON. */
|
||||
const char *channel_strs[0x20];
|
||||
int num_channels;
|
||||
ParseBody(out_version, channel_strs, std::addressof(num_channels), util::size(channel_strs), str, str_size);
|
||||
|
||||
/* Parse the channel strings. */
|
||||
char * const str_end = static_cast<char *>(str) + str_size;
|
||||
int parsed_channels = 0;
|
||||
for (auto i = 0; i < num_channels && i < max_channels; ++i) {
|
||||
impl::ChannelInternalType channel;
|
||||
if (StringToChannel(std::addressof(channel), const_cast<char *>(channel_strs[i]), util::Strnlen(channel_strs[i], str_end - channel_strs[i]))) {
|
||||
out_channels[parsed_channels++] = channel;
|
||||
}
|
||||
}
|
||||
|
||||
*out_num_channels = parsed_channels;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* 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 <stratosphere.hpp>
|
||||
|
||||
namespace ams::htclow::ctrl {
|
||||
|
||||
void ParseServiceChannel(s16 *out_version, impl::ChannelInternalType *out_channels, int *out_num_channels, int max_channels, void *str, size_t str_size);
|
||||
|
||||
}
|
|
@ -88,4 +88,17 @@ namespace ams::util {
|
|||
return static_cast<int>(cur - src);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
constexpr int Strnlen(const T *str, int count) {
|
||||
AMS_ASSERT(str != nullptr);
|
||||
AMS_ASSERT(count >= 0);
|
||||
|
||||
int length = 0;
|
||||
while (count-- && *str++) {
|
||||
++length;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue