ctr_Repair/trunk/ConsoleDataMigration/sources/ConsoleRestore/PreinstallImporter.cpp
N2614 86a7f1526b BGSとの通信結果はNULL終端してからXMLパースする必要がある
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@603 385bec56-5757-e545-9c3a-d8741f4650f1
2012-01-25 01:18:42 +00:00

216 lines
7.1 KiB
C++

/*---------------------------------------------------------------------------*
Project: Horizon
File: PreinstallImporter.cpp
Copyright 2009-2011 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include "CommonLogger.h"
#include "HeapManager.h"
#include "PreinstallImporter.h"
#include "XmlCreator.h"
#include "SimpleXmlPreprocessor.h"
#include <nn/xml/simple/xml_simple_SimpleXmlParser.h>
#include <cstring>
#include <nn/am/am_ApiSystemMenu.h>
namespace ConsoleRestore
{
PreinstallImporter::PreinstallImporter()
{
// TODO 自動生成されたコンストラクター・スタブ
}
PreinstallImporter::~PreinstallImporter()
{
// TODO Auto-generated destructor stub
}
nn::Result PreinstallImporter::SetupSd(bool* isAlreadyAvailable)
{
// SDカードがインポート可能状態かどうかチェック
NN_UTIL_RETURN_IF_FAILED(
nn::am::QueryAvailableExternalTitleDatabase(isAlreadyAvailable)
);
// タイトルデータベースを作成する
if (!*isAlreadyAvailable)
{
NN_UTIL_RETURN_IF_FAILED(
nn::am::InitializeExternalTitleDatabase()
);
}
return nn::ResultSuccess();
}
nn::Result PreinstallImporter::ListTitles(nn::ProgramId* list, size_t* num, bit64 deviceId, u8* serialNo)
{
// 送信用のXMLデータを構築する
XmlCreator sendXml;
sendXml.Exec(deviceId, serialNo);
// 構築したXMLデータを使ってBGSと通信する
BgsCommunicator comm;
if(!comm.Execute(sendXml.GetData().c_str(), sendXml.GetData().size()))
{
return comm.GetLastResult();
}
// 通信結果をパースしてタイトルリストを作成する
NN_UTIL_RETURN_IF_FAILED(
GetHtmlBodyAndParseXmlData(comm, list, num)
);
return nn::ResultSuccess();
}
nn::Result PreinstallImporter::GetHtmlBodyAndParseXmlData(BgsCommunicator& comm, nn::ProgramId* list, size_t* num)
{
// 通信結果を取得する
size_t bodySize;
if(!comm.GetBodySize(&bodySize))
{
return comm.GetLastResult();
}
if(common::GetAllocatableSize() < bodySize + 1)
{
// 巨大な通信結果のためFATAL。1回で受信しきれるはず
return nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
}
common::HeapManager heap(bodySize + 1);
void* buf = heap.GetAddr();
if(!comm.GetBody(reinterpret_cast<u8*>(buf), bodySize + 1))
{
return comm.GetLastResult();
}
// NULL終端する
reinterpret_cast<u8*>(buf)[bodySize] = '\0';
if(!comm.Finalize())
{
return comm.GetLastResult();
}
// XMLを解析してタイトルリストを設定する
NN_UTIL_RETURN_IF_FAILED(ParseXmlData(buf, list, num));
return nn::ResultSuccess();
}
nn::Result PreinstallImporter::ParseXmlData(void* buf, nn::ProgramId* list, size_t* num)
{
// 通信結果をパースする
// SimpleXmlParserに食わせるために変換する
SimpleXmlPreprocessor pp;
// システムヒープ(8MB)を超えたら正常に動かない
std::string xmlResult(reinterpret_cast<char*>(buf));
pp.Canonicalize(xmlResult);
// XMLをパースしてタイトルリストを取得する
nn::fnd::IAllocator* pAllocator = nn::init::GetAllocator();
nn::xml::simple::SimpleXmlParser simpleXmlParser(pAllocator);
const nn::xml::simple::SimpleXmlParser::Node* pTaskIdNode;
NN_UTIL_RETURN_IF_FAILED(
SetNodetoTitleIds(simpleXmlParser, xmlResult, &pTaskIdNode)
);
// タイトルIDリストをコピーする
common::HeapManager xmlHeap(pTaskIdNode->contentSize);
void* titleIdBuffer = xmlHeap.GetAddr();
std::memcpy(titleIdBuffer, pTaskIdNode->content, pTaskIdNode->contentSize);
SplitTextAndSetupList(list, num, reinterpret_cast<char*>(titleIdBuffer));
return nn::ResultSuccess();
}
nn::Result PreinstallImporter::SetNodetoTitleIds(nn::xml::simple::SimpleXmlParser& parser, std::string& xmlData, const nn::xml::simple::SimpleXmlParser::Node** pNode)
{
/*
* SimpleXmlPreprocessorを通したXMLデータはこんな形になっている
<Envelope>
<Body>
<GetPreInstalledInfoResponse>
<GetPreInstalledInfoResponse>
<Version></Version>
<MessageId></MessageId>
<TimeStamp>1326939225587</TimeStamp>
<ErrorCode>0</ErrorCode>
<ListResultTotalSize>1</ListResultTotalSize>
<PreinstalledInfo>
<DeviceId>17179924184</DeviceId>
<SerialNo>EJA20305940</SerialNo>
<Region>JPN</Region>
<ManufactureDate>1324339327000</ManufactureDate>
<TitleIds>000400000FEEB400,000400000FEEB000</TitleIds>
</PreinstalledInfo>
</GetPreInstalledInfoResponse>
</GetPreInstalledInfoResponse>
</Body>
</Envelope>
*/
parser.parse(reinterpret_cast<u8*>(const_cast<char*>(xmlData.c_str())), xmlData.size());
if(parser.isError())
{
COMMON_LOGGER("invalid xml Data\n");
return nn::Result(nn::Result::LEVEL_STATUS, nn::Result::SUMMARY_INVALID_STATE, nn::Result::MODULE_COMMON,
nn::Result::DESCRIPTION_INVALID_RESULT_VALUE);
}
// 欲しい情報がある場所まで階層を掘り下げる
const nn::xml::simple::SimpleXmlParser::Node* pRootNode = parser.getRootNode();
const nn::xml::simple::SimpleXmlParser::Node* pTargetNode = pRootNode->firstChild;
const nn::xml::simple::SimpleXmlParser::Node* pPriorityNode = nn::xml::simple::SimpleXmlParser::FindNextNode(
pTargetNode, "Body");
pPriorityNode = nn::xml::simple::SimpleXmlParser::FindNextNode(pPriorityNode->firstChild,
"GetPreInstalledInfoResponse");
pPriorityNode = nn::xml::simple::SimpleXmlParser::FindNextNode(pPriorityNode->firstChild,
"GetPreInstalledInfoResponse");
pPriorityNode = nn::xml::simple::SimpleXmlParser::FindNextNode(pPriorityNode->firstChild, "PreinstalledInfo");
*pNode = nn::xml::simple::SimpleXmlParser::FindNextNode(pPriorityNode->firstChild, "TitleIds");
return nn::ResultSuccess();
}
void PreinstallImporter::SplitTextAndSetupList(nn::ProgramId* list, size_t* num, char* text)
{
const char* token = ",";
char* cutout;
*num = 0;
cutout = std::strtok(text, token);
if(!cutout)
{
return;
}
list[*num] = std::strtoll(cutout, NULL, 16);
(*num)++;
while( cutout )
{
cutout = std::strtok(NULL, token);
if(cutout)
{
list[*num] = std::strtoll(cutout, NULL, 16);
(*num)++;
}
}
}
} /* namespace ConsoleRestore */