| 70 | } |
| 71 | |
| 72 | void TitleCache::encode(u8* dst, Title& title, IconStore& icons) |
| 73 | { |
| 74 | std::memset(dst, 0, ENTRY_SIZE); |
| 75 | |
| 76 | u64 id = title.id(); |
| 77 | // bit 0: regular save accessible, bit 1: GBA VC raw save accessible |
| 78 | u8 accessibleSaveRaw = title.accessibleSave() ? 1 : (title.isGBAVC() ? 2 : 0); |
| 79 | bool accessibleExtdata = title.accessibleExtdata(); |
| 80 | std::string shortDescription = title.shortDescription(); |
| 81 | std::string longDescription = title.longDescription(); |
| 82 | std::string savePath = StringUtils::UTF16toUTF8(title.savePath()); |
| 83 | std::string extdataPath = StringUtils::UTF16toUTF8(title.extdataPath()); |
| 84 | FS_MediaType media = title.mediaType(); |
| 85 | FS_CardType cardType = title.cardType(); |
| 86 | CardType card = title.SPICardType(); |
| 87 | |
| 88 | if (cardType == CARD_CTR) { |
| 89 | // The probe already read this title's SMDH and stored its icon bytes in |
| 90 | // `icons`; reuse them so the full-scan export doesn't read the SMDH a |
| 91 | // second time. Fall back to a fresh SMDH read only on a cache miss. |
| 92 | u16 iconPixels[ICON_BYTES / sizeof(u16)]; |
| 93 | if (icons.copyCtrPixels(id, iconPixels)) { |
| 94 | std::memcpy(dst + OFF_ICON, iconPixels, ICON_BYTES); |
| 95 | } |
| 96 | else { |
| 97 | smdh_s* smdh = loadSMDH(title.lowId(), title.highId(), media); |
| 98 | if (smdh != NULL) { |
| 99 | std::memcpy(dst + OFF_ICON, smdh->bigIconData, ICON_BYTES); |
| 100 | } |
| 101 | delete smdh; |
| 102 | } |
| 103 | } |
| 104 | else if (media == MEDIATYPE_NAND) { |
| 105 | // DSiWare: the icon field is sized for a CTR icon; the smaller decoded |
| 106 | // 32x32 DS icon (DS_ICON_BYTES) sits in its head, rest stays zero. |
| 107 | u16 iconPixels[DS_ICON_BYTES / sizeof(u16)]; |
| 108 | if (icons.copyDsPixels(id, iconPixels)) { |
| 109 | std::memcpy(dst + OFF_ICON, iconPixels, DS_ICON_BYTES); |
| 110 | } |
| 111 | } |
| 112 | |
| 113 | std::memcpy(dst + OFF_ID, &id, sizeof(u64)); |
| 114 | std::memcpy(dst + OFF_PRODUCT, title.productCode, 16); |
| 115 | std::memcpy(dst + OFF_ACCESS, &accessibleSaveRaw, sizeof(u8)); |
| 116 | std::memcpy(dst + OFF_ACCESS_EXT, &accessibleExtdata, sizeof(u8)); |
| 117 | copyClamped(dst, OFF_SHORT, shortDescription, SHORT_LEN); |
| 118 | copyClamped(dst, OFF_LONG, longDescription, LONG_LEN); |
| 119 | copyClamped(dst, OFF_SAVE_PATH, savePath, PATH_LEN); |
| 120 | copyClamped(dst, OFF_EXT_PATH, extdataPath, PATH_LEN); |
| 121 | std::memcpy(dst + OFF_MEDIA, &media, sizeof(u8)); |
| 122 | std::memcpy(dst + OFF_FS_CARD, &cardType, sizeof(u8)); |
| 123 | std::memcpy(dst + OFF_CARD, &card, sizeof(u8)); |
| 124 | } |
| 125 | |
| 126 | Title TitleCache::decode(const u8* src, IconStore& icons) |
| 127 | { |