AppItem.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. #include <cpp3ds/System/Err.hpp>
  2. #include <iostream>
  3. #include <cpp3ds/System/I18n.hpp>
  4. #include "AssetManager.hpp"
  5. #include "AppItem.hpp"
  6. #include "Util.hpp"
  7. #include "TitleKeys.hpp"
  8. #include "DownloadQueue.hpp"
  9. #include <sstream>
  10. namespace {
  11. std::vector<std::unique_ptr<cpp3ds::Texture>> textures;
  12. #ifdef _3DS
  13. typedef struct {
  14. u16 shortDescription[0x40];
  15. u16 longDescription[0x80];
  16. u16 publisher[0x40];
  17. } SMDH_title;
  18. typedef struct {
  19. char magic[0x04];
  20. u16 version;
  21. u16 reserved1;
  22. SMDH_title titles[0x10];
  23. u8 ratings[0x10];
  24. u32 region;
  25. u32 matchMakerId;
  26. u64 matchMakerBitId;
  27. u32 flags;
  28. u16 eulaVersion;
  29. u16 reserved;
  30. u32 optimalBannerFrame;
  31. u32 streetpassId;
  32. u64 reserved2;
  33. u8 smallIcon[0x480];
  34. u8 largeIcon[0x1200];
  35. } SMDH;
  36. #endif
  37. }
  38. namespace FreeShop
  39. {
  40. AppItem::AppItem()
  41. : m_installed(false)
  42. , m_regions(0)
  43. , m_languages(0)
  44. , m_iconIndex(-1)
  45. , m_iconRect(cpp3ds::IntRect(0, 0, 48, 48))
  46. , m_systemIconTexture(nullptr)
  47. {
  48. cpp3ds::Texture &texture = AssetManager<cpp3ds::Texture>::get("images/missing-icon.png");
  49. texture.setSmooth(true);
  50. m_iconTexture = &texture;
  51. }
  52. AppItem::~AppItem()
  53. {
  54. delete m_systemIconTexture;
  55. }
  56. const cpp3ds::String &AppItem::getTitle() const
  57. {
  58. return m_title;
  59. }
  60. void AppItem::loadFromJSON(const char* titleId, const rapidjson::Value &json)
  61. {
  62. m_genres.clear();
  63. m_features.clear();
  64. m_seed.clear();
  65. m_languages = 0;
  66. m_titleIdStr = titleId;
  67. m_titleId = strtoull(titleId, 0, 16);
  68. m_updates = TitleKeys::getRelated(m_titleId, TitleKeys::Update);
  69. m_demos = TitleKeys::getRelated(m_titleId, TitleKeys::Demo);
  70. m_dlc = TitleKeys::getRelated(m_titleId, TitleKeys::DLC);
  71. const char *title = json[0].GetString();
  72. m_title = cpp3ds::String::fromUtf8(title, title + json[0].GetStringLength());
  73. m_normalizedTitle = json[1].GetString();
  74. m_contentId = json[2].GetString();
  75. m_regions = json[3].GetInt();
  76. m_uriRegion = json[4].GetString();
  77. m_filesize = json[5].GetUint64();
  78. int iconIndex = json[6].GetInt();
  79. if (iconIndex >= 0)
  80. setIconIndex(iconIndex);
  81. // Crypto seed
  82. std::string seed = json[7].GetString();
  83. if (!seed.empty())
  84. {
  85. m_seed.clear();
  86. for (int i = 0; i < 16; ++i)
  87. {
  88. std::string byteStr = seed.substr(i*2, 2);
  89. char byte = strtol(byteStr.c_str(), NULL, 16);
  90. m_seed.push_back(byte);
  91. }
  92. }
  93. // Genres
  94. auto genres = json[8].GetArray();
  95. for (int i = 0; i < genres.Size(); ++i)
  96. m_genres.push_back(genres[i].GetInt());
  97. // Languages
  98. auto languages = json[9].GetArray();
  99. for (int i = 0; i < languages.Size(); ++i)
  100. {
  101. std::string lang(languages[i].GetString());
  102. if ("ja" == lang) m_languages |= Japanese;
  103. else if ("en" == lang) m_languages |= English;
  104. else if ("es" == lang) m_languages |= Spanish;
  105. else if ("fr" == lang) m_languages |= French;
  106. else if ("de" == lang) m_languages |= German;
  107. else if ("it" == lang) m_languages |= Italian;
  108. else if ("nl" == lang) m_languages |= Dutch;
  109. else if ("pt" == lang) m_languages |= Portuguese;
  110. else if ("ru" == lang) m_languages |= Russian;
  111. }
  112. // Features
  113. auto features = json[10].GetArray();
  114. for (int i = 0; i < features.Size(); ++i)
  115. m_features.push_back(features[i].GetInt());
  116. if (!json[11].IsNull())
  117. m_voteScore = json[11].GetFloat();
  118. m_voteCount = json[12].GetInt();
  119. m_releaseDate = json[13].GetInt();
  120. m_productCode = json[14].GetString();
  121. m_platform = json[15].GetInt();
  122. m_publisher = json[16].GetInt();
  123. }
  124. void AppItem::loadFromSystemTitleId(cpp3ds::Uint64 titleId)
  125. {
  126. m_titleId = titleId;
  127. m_titleIdStr = _("%016llX", titleId);
  128. m_updates = TitleKeys::getRelated(m_titleId, TitleKeys::Update);
  129. m_demos = TitleKeys::getRelated(m_titleId, TitleKeys::Demo);
  130. m_dlc = TitleKeys::getRelated(m_titleId, TitleKeys::DLC);
  131. #ifdef _3DS
  132. Result res = 0;
  133. Handle fileHandle;
  134. char productCode[12] = {'\0'};
  135. AM_TitleEntry titleInfo;
  136. AM_GetTitleInfo(MEDIATYPE_NAND, 1, &titleId, &titleInfo);
  137. AM_GetTitleProductCode(MEDIATYPE_NAND, titleId, productCode);
  138. m_title = productCode;
  139. if (m_title.toAnsiString().compare(0, 9, "CTR-N-HMM") == 0)
  140. m_title = _("Home Menu Themes");
  141. static const u32 filePath[5] = {0x0, 0x0, 0x2, 0x6E6F6369, 0x0};
  142. u32 archivePath[4] = {(u32) (titleId & 0xFFFFFFFF), (u32) ((titleId >> 32) & 0xFFFFFFFF), MEDIATYPE_NAND, 0x0};
  143. FS_Path binArchPath = {PATH_BINARY, 0x10, archivePath};
  144. FS_Path binFilePath = {PATH_BINARY, 0x14, filePath};
  145. if(R_SUCCEEDED(res = FSUSER_OpenFileDirectly(&fileHandle, ARCHIVE_SAVEDATA_AND_CONTENT, binArchPath, binFilePath, FS_OPEN_READ, 0)))
  146. {
  147. auto smdh = new SMDH();
  148. if (smdh)
  149. {
  150. FSFILE_Read(fileHandle, nullptr, 0, smdh, sizeof(SMDH));
  151. if (smdh->magic[0] == 'S' && smdh->magic[1] == 'M' && smdh->magic[2] == 'D' && smdh->magic[3] == 'H')
  152. {
  153. u8 systemLanguage = CFG_LANGUAGE_EN;
  154. CFGU_GetSystemLanguage(&systemLanguage);
  155. u16 *title = smdh->titles[systemLanguage].shortDescription;
  156. m_title = cpp3ds::String::fromUtf16(title, title + 0x40);
  157. delete m_systemIconTexture;
  158. m_systemIconTexture = new cpp3ds::Texture();
  159. m_systemIconTexture->loadFromPreprocessedMemory(smdh->largeIcon, sizeof(smdh->largeIcon), 48, 48, GPU_RGB565);
  160. }
  161. delete smdh;
  162. }
  163. FSFILE_Close(fileHandle);
  164. }
  165. #else
  166. m_title = m_titleIdStr;
  167. #endif
  168. m_normalizedTitle = m_title;
  169. for (auto &c : m_normalizedTitle)
  170. c = std::tolower(c);
  171. }
  172. void AppItem::setIconIndex(size_t iconIndex)
  173. {
  174. size_t textureIndex = iconIndex / 441;
  175. iconIndex %= 441;
  176. // Load texture from file if not done already
  177. if (textures.size() < textureIndex + 1)
  178. {
  179. for (int i = textures.size(); i <= textureIndex; ++i)
  180. {
  181. std::unique_ptr<cpp3ds::Texture> texture(new cpp3ds::Texture());
  182. #ifdef EMULATION
  183. texture->loadFromFile(_(FREESHOP_DIR "/cache/images/icons%d.jpg", i));
  184. #else
  185. texture->loadFromPreprocessedFile(_(FREESHOP_DIR "/cache/images/icons%d.bin", i), 1024, 1024, GPU_ETC1);
  186. #endif
  187. texture->setSmooth(true);
  188. textures.push_back(std::move(texture));
  189. }
  190. }
  191. m_iconIndex = iconIndex;
  192. m_iconTexture = textures[textureIndex].get();
  193. int x = (iconIndex / 21) * 48;
  194. int y = (iconIndex % 21) * 48;
  195. m_iconRect = cpp3ds::IntRect(x, y, 48, 48);
  196. }
  197. bool AppItem::isCached() const
  198. {
  199. return pathExists(getJsonFilename().c_str());
  200. }
  201. const std::string AppItem::getJsonFilename() const
  202. {
  203. std::string filename = FREESHOP_DIR "/tmp/" + getTitleIdStr() + "/data.json";
  204. return filename;
  205. }
  206. void AppItem::setInstalled(bool installed)
  207. {
  208. m_installed = installed;
  209. }
  210. bool AppItem::isInstalled() const
  211. {
  212. return m_installed;
  213. }
  214. cpp3ds::Uint64 AppItem::getFilesize() const
  215. {
  216. return m_filesize;
  217. }
  218. const std::string &AppItem::getNormalizedTitle() const
  219. {
  220. return m_normalizedTitle;
  221. }
  222. const std::string &AppItem::getTitleIdStr() const
  223. {
  224. return m_titleIdStr;
  225. }
  226. cpp3ds::Uint64 AppItem::getTitleId() const
  227. {
  228. return m_titleId;
  229. }
  230. const std::string &AppItem::getContentId() const
  231. {
  232. return m_contentId;
  233. }
  234. const std::string &AppItem::getUriRegion() const
  235. {
  236. return m_uriRegion;
  237. }
  238. int AppItem::getRegions() const
  239. {
  240. return m_regions;
  241. }
  242. int AppItem::getLanguages() const
  243. {
  244. return m_languages;
  245. }
  246. const std::vector<char> &AppItem::getSeed() const
  247. {
  248. return m_seed;
  249. }
  250. const std::vector<int> &AppItem::getGenres() const
  251. {
  252. return m_genres;
  253. }
  254. int AppItem::getPlatform() const
  255. {
  256. return m_platform;
  257. }
  258. int AppItem::getPublisher() const
  259. {
  260. return m_publisher;
  261. }
  262. int AppItem::getIconIndex() const
  263. {
  264. return m_iconIndex;
  265. }
  266. const cpp3ds::Texture *AppItem::getIcon(cpp3ds::IntRect &outRect) const
  267. {
  268. outRect = m_iconRect;
  269. return m_systemIconTexture ? : m_iconTexture;
  270. }
  271. void AppItem::queueForInstall()
  272. {
  273. DownloadQueue::getInstance().addDownload(shared_from_this());
  274. for (auto &id : m_updates)
  275. DownloadQueue::getInstance().addDownload(shared_from_this(), id);
  276. for (auto &id : m_dlc)
  277. DownloadQueue::getInstance().addDownload(shared_from_this(), id);
  278. }
  279. const std::vector<cpp3ds::Uint64> &AppItem::getUpdates() const
  280. {
  281. return m_updates;
  282. }
  283. const std::vector<cpp3ds::Uint64> &AppItem::getDemos() const
  284. {
  285. return m_demos;
  286. }
  287. const std::vector<cpp3ds::Uint64> &AppItem::getDLC() const
  288. {
  289. return m_dlc;
  290. }
  291. float AppItem::getVoteScore() const
  292. {
  293. return m_voteScore;
  294. }
  295. int AppItem::getVoteCount() const
  296. {
  297. return m_voteCount;
  298. }
  299. time_t AppItem::getReleaseDate() const
  300. {
  301. return m_releaseDate;
  302. }
  303. const std::string &AppItem::getProductCode() const
  304. {
  305. return m_productCode;
  306. }
  307. } // namespace FreeShop