mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@548 385bec56-5757-e545-9c3a-d8741f4650f1
267 lines
7.6 KiB
C++
267 lines
7.6 KiB
C++
/*---------------------------------------------------------------------------*
|
|
Project: Horizon
|
|
File: TitleDownloader.cpp
|
|
|
|
Copyright 2009 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 <nn.h>
|
|
#include <nn/am.h>
|
|
#include <nn/nim.h>
|
|
#include <nn/CTR/CTR_ProgramId.h>
|
|
|
|
#include "common_Types.h"
|
|
#include "FileName.h"
|
|
#include "CommonLogger.h"
|
|
#include "HeapManager.h"
|
|
#include "TitleDownloader.h"
|
|
#include "Shop.h"
|
|
#include "SdReaderWriter.h"
|
|
|
|
|
|
namespace
|
|
{
|
|
|
|
bit8 s_buffer1[400 * 1024];
|
|
|
|
const size_t TITLE_DOWNLOADER_STACK_SIZE = 0x1000;
|
|
nn::os::Thread s_TitleDownloaderThread;
|
|
nn::os::StackBuffer<TITLE_DOWNLOADER_STACK_SIZE> s_TitleDownloaderThreadStack;
|
|
u64 s_Progress;
|
|
|
|
nn::fs::MediaType GetMediaType(const ES_NAMESPACE::ESTitleId titleId)
|
|
{
|
|
return (nn::CTR::IsTwlApp(titleId)) ?
|
|
nn::fs::MEDIA_TYPE_NAND : nn::fs::MEDIA_TYPE_SDMC;
|
|
}
|
|
|
|
const char *GetAttribute(EC_NAMESPACE::ECNameValuePair *attributes, u32 nAttributes, const char *attributeName)
|
|
{
|
|
for(int i=0; i<nAttributes; i++)
|
|
{
|
|
if(std::strcmp(attributes[i].name, attributeName)==0)
|
|
{
|
|
return attributes[i].value;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
nn::Result GetEntry(ES_NAMESPACE::ESTitleId titleId, EC_NAMESPACE::ECTitleCatalogEntry **entry)
|
|
{
|
|
nn::nim::AttributeName returnAttribute[] =
|
|
{"Version", "TitleName", "TitleType", "TitleDescription", "Category", "Publisher", "MaxUserFileSize", "ReleaseDate"};
|
|
nn::nim::AttributeFilter attributeFilter[] = {
|
|
{"==", "string", "PricingSelection", "RELEASED"}
|
|
};
|
|
|
|
COMMON_LOGGER_DETAIL("ID: %016llx\n", titleId);
|
|
|
|
EC_NAMESPACE::ECTitleCatalog *titleCatalog;
|
|
nn::Result result = nn::nim::Shop::ListTitles(0, 1,
|
|
returnAttribute, sizeof(returnAttribute)/sizeof(returnAttribute[0]),
|
|
attributeFilter, sizeof(attributeFilter)/sizeof(attributeFilter[0]),
|
|
&(titleId), 1,
|
|
NULL, 0,
|
|
&titleCatalog, s_buffer1, sizeof(s_buffer1));
|
|
|
|
if(result.IsSuccess())
|
|
{
|
|
if(titleCatalog->nEntries == 1)
|
|
{
|
|
*entry = &(titleCatalog->entries[0]);
|
|
}
|
|
else
|
|
{
|
|
return nn::MakeStatusResult(nn::Result::SUMMARY_NOT_FOUND, nn::Result::MODULE_COMMON, nn::Result::DESCRIPTION_NOT_FOUND);
|
|
}
|
|
|
|
}
|
|
return result;
|
|
}
|
|
|
|
nn::Result GetTitleConfig(const ES_NAMESPACE::ESTitleId titleId, nn::nim::TitleConfig *titleConfig)
|
|
{
|
|
EC_NAMESPACE::ECTitleCatalogEntry *entry;
|
|
NN_UTIL_RETURN_IF_FAILED(GetEntry(titleId, &entry));
|
|
|
|
titleConfig->titleId=titleId;
|
|
titleConfig->version=std::strtoull(GetAttribute(entry->attributes, entry->nAttributes, "Version"), NULL, 10);
|
|
titleConfig->ratingAge=0;
|
|
titleConfig->media=GetMediaType(titleId);
|
|
|
|
COMMON_LOGGER_DETAIL("titleId : 0x%016llx\n", titleConfig->titleId);
|
|
COMMON_LOGGER_DETAIL("version : %lld\n" , titleConfig->version);
|
|
COMMON_LOGGER_DETAIL("ratingAge : %d\n" , titleConfig->ratingAge);
|
|
COMMON_LOGGER_DETAIL("media : %d\n" , titleConfig->media);
|
|
|
|
|
|
return nn::ResultSuccess();
|
|
}
|
|
|
|
|
|
} // namespace <unnamed>
|
|
|
|
namespace ConsoleRestore
|
|
{
|
|
|
|
nn::Result TitleDownloader::m_Result = nn::ResultSuccess();
|
|
|
|
void TitleDownloaderThreadFunc()
|
|
{
|
|
TitleDownloader TwlTitleDownloader;
|
|
|
|
s_Progress = 0;
|
|
TwlTitleDownloader.Start();
|
|
}
|
|
|
|
void StartTitleDownload()
|
|
{
|
|
s_TitleDownloaderThread.Start(TitleDownloaderThreadFunc, s_TitleDownloaderThreadStack);
|
|
}
|
|
|
|
bool IsDownloadTitleFinished()
|
|
{
|
|
return s_TitleDownloaderThread.IsValid() && !s_TitleDownloaderThread.IsAlive();
|
|
}
|
|
|
|
void FinalizeTitleDownload()
|
|
{
|
|
s_TitleDownloaderThread.Join();
|
|
s_TitleDownloaderThread.Finalize();
|
|
}
|
|
|
|
bool DownloadTitleSucceeded()
|
|
{
|
|
return TitleDownloader::m_Result.IsSuccess() && GetShopOperationSingleResult().IsSuccess();
|
|
}
|
|
|
|
u32 GetTitleDownloadProgress()
|
|
{
|
|
return s_Progress;
|
|
}
|
|
|
|
|
|
TitleDownloader::TitleDownloader() : m_TwlTiteNum(0)
|
|
{
|
|
for(u32 i = 0; i < TWL_IMPORTABLE_TITLE_MAX; i++)
|
|
{
|
|
m_ProgramIdList[i] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
TitleDownloader::~TitleDownloader()
|
|
{
|
|
|
|
}
|
|
|
|
|
|
nn::Result WaitCancelled()
|
|
{
|
|
nn::nim::TitleProgress progress;
|
|
while(true)
|
|
{
|
|
// キャンセルがResultとして返ってくる / ダウンロード終了まで待つ
|
|
NN_UTIL_RETURN_IF_FAILED(nn::nim::Shop::GetProgress(&progress));
|
|
if(progress.lastResult==nn::nim::ResultCancelRequested() || progress.state==nn::nim::TITLE_STATE_FINISHED)
|
|
{
|
|
break;
|
|
}
|
|
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
|
|
}
|
|
return nn::ResultSuccess();
|
|
}
|
|
|
|
void WaitShopOperationAndFinalize()
|
|
{
|
|
while (!IsShopOperationSingleFinished())
|
|
{
|
|
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
|
|
}
|
|
|
|
FinalizeShopOperationSingle();
|
|
}
|
|
|
|
void TitleDownloader::Start()
|
|
{
|
|
m_Result = ListUp();
|
|
if(m_Result.IsFailure())
|
|
{
|
|
return;
|
|
}
|
|
|
|
for(u8 i = 0; i < m_TwlTiteNum; i++)
|
|
{
|
|
s_Progress = i * 100 / m_TwlTiteNum;
|
|
StartShopOperationSingle(SHOP_OPERATION_CONNECT_WITHOUT_CLOSE);
|
|
WaitShopOperationAndFinalize();
|
|
|
|
nn::nim::TitleConfig config;
|
|
m_Result = GetTitleConfig(m_ProgramIdList[i], &config);
|
|
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
|
|
if (m_Result.IsSuccess())
|
|
{
|
|
StartShopOperationSingle(SHOP_OPERATION_DOWNLOAD_TITLE, config);
|
|
WaitShopOperationAndFinalize();
|
|
}
|
|
}
|
|
}
|
|
|
|
nn::Result TitleDownloader::ListUp()
|
|
{
|
|
COMMON_LOGGER("Read TwlTitle List.\n");
|
|
|
|
size_t heapSize = common::GetAllocatableSize();
|
|
if(heapSize > common::FILE_COPY_HEAP_SIZE)
|
|
{
|
|
heapSize = common::FILE_COPY_HEAP_SIZE;
|
|
}
|
|
common::HeapManager heap(heapSize);
|
|
char* titleListBuf = reinterpret_cast<char*> (heap.GetAddr());
|
|
|
|
size_t readSize = 0;
|
|
if (titleListBuf != NULL)
|
|
{
|
|
common::SdReaderWriter sdReader;
|
|
m_Result = sdReader.ReadBufWithCmac(common::TWL_TITLELIST_PATHNAME, titleListBuf, heapSize, &readSize);
|
|
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
|
|
if (m_Result.IsSuccess())
|
|
{
|
|
u32 listHead = 0;
|
|
for (u32 i = 0; i < readSize; i++)
|
|
{
|
|
if (titleListBuf[i] == '\n')
|
|
{
|
|
char ProgramIdStr[32];
|
|
char *error;
|
|
std::memcpy(ProgramIdStr, &titleListBuf[listHead], i - listHead);
|
|
m_ProgramIdList[m_TwlTiteNum] = std::strtoull(ProgramIdStr, &error, 16);
|
|
m_TwlTiteNum++;
|
|
COMMON_LOGGER_DETAIL("%016llx\n", m_ProgramIdList[m_TwlTiteNum - 1]);
|
|
|
|
listHead = i + 1;
|
|
}
|
|
}
|
|
}
|
|
COMMON_LOGGER("%d Title(s) found.\n", m_TwlTiteNum);
|
|
}
|
|
else
|
|
{
|
|
m_Result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
|
|
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
|
|
}
|
|
|
|
return m_Result;
|
|
}
|
|
|
|
}
|