ctr_Repair/trunk/ConsoleDataMigration/sources/ConsoleRestore/PreinstallImporter.cpp
N2614 7320c776ea r629を巻き戻し。サイズチェック時はエラーをスキップできないので。
NN_UTIL_RETURN_IF_FAILEDをCOMMON_LOGGER_RETURN_IF_FAILEDに置換
CmacAdderが出力先ディレクトリ初期化時にエラーで止まっていたので修正

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@631 385bec56-5757-e545-9c3a-d8741f4650f1
2012-02-14 02:54:42 +00:00

247 lines
8.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カードがインポート可能状態かどうかチェック
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
nn::am::QueryAvailableExternalTitleDatabase(isAlreadyAvailable)
);
// タイトルデータベースを作成する
if (!*isAlreadyAvailable)
{
COMMON_LOGGER_RETURN_RESULT_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();
}
// 通信結果をパースしてタイトルリストを作成する
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
GetHtmlBodyAndParseXmlData(comm, list, num)
);
return nn::ResultSuccess();
}
nn::Result PreinstallImporter::ListTitlesBasedOnTickets(nn::ProgramId* list, size_t* num)
{
s32 personalizedTicketNum;
nn::am::TicketInfo ticketInfo[256];
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
nn::am::GetPersonalizedTicketInfoList(&personalizedTicketNum, ticketInfo, 256)
);
*num = 0;
for(s32 i = 0; i < personalizedTicketNum; i++)
{
list[*num] = ticketInfo[i].titleId;
(*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を解析してタイトルリストを設定する
COMMON_LOGGER_RETURN_RESULT_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;
COMMON_LOGGER_RETURN_RESULT_IF_FAILED(
SetNodetoTitleIds(simpleXmlParser, xmlResult, &pTaskIdNode)
);
*num = 0;
// プリインストールタイトルが無ければ終了
if(!pTaskIdNode)
{
return nn::MakePermanentResult(nn::Result::SUMMARY_NOT_FOUND, nn::Result::MODULE_APPLICATION,
nn::Result::DESCRIPTION_NOT_FOUND);
}
// タイトル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");
// テーブルを移行して空になっていた場合
if(pPriorityNode == NULL)
{
*pNode = NULL;
return nn::ResultSuccess();
}
*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;
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 */