Copies a UTF-8 string into a fixed field of `fieldLen` bytes, always leaving room for a terminating NUL. The SMDH short/long descriptions are 0x40/0x80 UTF-16 units, which can expand to more UTF-8 bytes than the field holds (Japanese/emoji titles), so the copy MUST be clamped or it overruns the packed entry. When the clamp lands mid-sequence we back off to the previous codepoint boundary so a part
| 59 | // codepoint boundary so a partial UTF-8 sequence is never written. The entry |
| 60 | // is memset to 0 up front, so the unwritten tail is already the NUL padding. |
| 61 | void copyClamped(u8* dst, size_t offset, const std::string& src, size_t fieldLen) |
| 62 | { |
| 63 | size_t n = std::min(src.length(), fieldLen - 1); |
| 64 | // back off out of the middle of a multibyte sequence |
| 65 | while (n > 0 && (static_cast<u8>(src[n]) & 0xC0) == 0x80) { |
| 66 | n--; |
| 67 | } |
| 68 | std::memcpy(dst + offset, src.data(), n); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | void TitleCache::encode(u8* dst, Title& title, IconStore& icons) |