1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378 |
- // GameCube font tool
- // Copyright 2015 Dolphin Emulator Project
- // Copyright 2015 James Cowgill <james410@cowgill.org.uk>
- //
- // This program is free software; you can redistribute it and/or modify
- // it under the terms of the GNU General Public License as published by
- // the Free Software Foundation; either version 2 of the License, or
- // (at your option) any later version.
- //
- // This program is distributed in the hope that it will be useful,
- // but WITHOUT ANY WARRANTY; without even the implied warranty of
- // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- // GNU General Public License for more details.
- // Compile with:
- // g++ -O2 -std=c++11 $(freetype-config --cflags --libs) gc-font-tool.cpp
- // Yay0
- // ===============
- // Yay0 is the binary compression format used in game cube font files.
- // It is heavily based on LZ77 (used by DEFLATE).
- // HEADER
- // 0 Yay0 magic number
- // 4 Size of data uncompressed
- // 8 Offset to "link" table
- // C Offset to "chunks" table
- //
- // MASK TABLE
- // The mask table immediately follows the header (so there is no offset to it)
- // Each byte is a bitmask specifying the type of data to read next. If the bit
- // is 1, one byte should be read from the chunks table. If the bit is 0, a link
- // from the links table should be read.
- //
- // CHUNKS TABLE
- // This table contains binary data copied into the output stream by the mask
- // table, and counters for large links. Each time bytes are read from this
- // table, the chunks offset is incremented (bytes are only ever used once).
- //
- // LINK TABLE
- // The link table contains references to blocks of previously decompressed data.
- // Each link is 2 bytes long in the format:
- // CCOO OOOO
- // Where (C+2) is the count of bytes in the link and (O+1) is the offset
- // backwards in the already decompressed data to read from. If C == 0, the
- // number of bytes in the link is read from the chunks table and 18 is added
- // to it.
- //
- // Font Format
- // ===============
- // 00 Font type (0 = Windows-1252, 2 = Windows-31J)
- // 02 First character
- // 04 Last character
- // 06 Invalid character
- // 08 Ascent
- // 0A Decent
- // 0C Width of widest character
- // 0E Leading space
- // 10 Cell width
- // 12 Cell height
- // 14 Texture size
- // 18 Texture format
- // 1A Texture columns
- // 1C Texture rows
- // 1E Texture width
- // 20 Texture height
- // 22 Offset to character widths table
- // 24 Offset to tile data
- // 28 Tile data size
- // 2A Greyscale colour for 0 values
- // 2B Greyscale colour for 1 values
- // 2C Greyscale colour for 2 values
- // 2D Greyscale colour for 3 values
- // This program ignores these values and justs assumes it uses the linear
- // 4-bit colours: 00, 55, AA, FF (FIXME?)
- //
- // Font data is encoded in 2 bit greyscale and in 8x8 blocks.
- #include <cerrno>
- #include <cstring>
- #include <fstream>
- #include <iostream>
- #include <memory>
- #include <stdexcept>
- #include <vector>
- #include <ft2build.h>
- #include FT_FREETYPE_H
- using std::size_t;
- using std::uint8_t;
- using std::uint16_t;
- using std::uint32_t;
- // Font parameters
- const int FNT_CELL_SIZE = 24;
- const int FNT_RENDER_SIZE = FNT_CELL_SIZE * 5 / 6;
- const int FNT_CELLS_PER_ROW = 21;
- const int FNT_PIXMAP_WIDTH = 512; // Must be >= CELL_SIZE * CELLS_PER_ROW
- // The two types of font which can be generated
- enum class font_type
- {
- windows_1252,
- shift_jis,
- };
- #define SEQUENCE_4(x) (x), (x)+1, (x)+2, (x)+3
- #define SEQUENCE_8(x) SEQUENCE_4(x), SEQUENCE_4((x)+4)
- #define SEQUENCE_16(x) SEQUENCE_8(x), SEQUENCE_8((x)+8)
- #define SEQUENCE_32(x) SEQUENCE_16(x), SEQUENCE_16((x)+16)
- #define SEQUENCE_64(x) SEQUENCE_32(x), SEQUENCE_32((x)+32)
- // List of unicode codepoints appearing in the Windows-1252 font
- const uint16_t windows_1252_font_table[] =
- {
- SEQUENCE_32(0x20),
- SEQUENCE_64(0x40),
- 0x20AC, 0, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
- 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0, 0x017D, 0,
- 0, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
- 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0, 0x017E, 0x0178,
- SEQUENCE_32(0xA0),
- SEQUENCE_64(0xC0),
- };
- // List of unicode codepoints appearing in the Shift JIS font
- const uint16_t shift_jis_font_table[] =
- {
- // Starts at Shift JIS 0x8740. Any holes are skipped over.
- 0x3000, 0x3001, 0x3002, 0xFF0C, 0xFF0E, 0x30FB, 0xFF1A, 0xFF1B,
- 0xFF1F, 0xFF01, 0x309B, 0x309C, 0x00B4, 0xFF40, 0x00A8, 0xFF3E,
- 0xFFE3, 0xFF3F, 0x30FD, 0x30FE, 0x309D, 0x309E, 0x3003, 0x4EDD,
- 0x3005, 0x3006, 0x3007, 0x30FC, 0x2015, 0x2010, 0xFF0F, 0xFF3C,
- 0xFF5E, 0x2225, 0xFF5C, 0x2026, 0x2025, 0x2018, 0x2019, 0x201C,
- 0x201D, 0xFF08, 0xFF09, 0x3014, 0x3015, 0xFF3B, 0xFF3D, 0xFF5B,
- 0xFF5D, 0x3008, 0x3009, 0x300A, 0x300B, 0x300C, 0x300D, 0x300E,
- 0x300F, 0x3010, 0x3011, 0xFF0B, 0xFF0D, 0x00B1, 0x00D7, 0x00F7,
- 0xFF1D, 0x2260, 0xFF1C, 0xFF1E, 0x2266, 0x2267, 0x221E, 0x2234,
- 0x2642, 0x2640, 0x00B0, 0x2032, 0x2033, 0x2103, 0xFFE5, 0xFF04,
- 0xFFE0, 0xFFE1, 0xFF05, 0xFF03, 0xFF06, 0xFF0A, 0xFF20, 0x00A7,
- 0x2606, 0x2605, 0x25CB, 0x25CF, 0x25CE, 0x25C7, 0x25C6, 0x25A1,
- 0x25A0, 0x25B3, 0x25B2, 0x25BD, 0x25BC, 0x203B, 0x3012, 0x2192,
- 0x2190, 0x2191, 0x2193, 0x3013, 0x2208, 0x220B, 0x2286, 0x2287,
- 0x2282, 0x2283, 0x222A, 0x2229, 0x2227, 0x2228, 0xFFE2, 0x21D2,
- 0x21D4, 0x2200, 0x2203, 0x2220, 0x22A5, 0x2312, 0x2202, 0x2207,
- 0x2261, 0x2252, 0x226A, 0x226B, 0x221A, 0x223D, 0x221D, 0x2235,
- 0x222B, 0x222C, 0x212B, 0x2030, 0x266F, 0x266D, 0x266A, 0x2020,
- 0x2021, 0x00B6, 0x25EF, 0xFF10, 0xFF11, 0xFF12, 0xFF13, 0xFF14,
- 0xFF15, 0xFF16, 0xFF17, 0xFF18, 0xFF19, 0xFF21, 0xFF22, 0xFF23,
- 0xFF24, 0xFF25, 0xFF26, 0xFF27, 0xFF28, 0xFF29, 0xFF2A, 0xFF2B,
- 0xFF2C, 0xFF2D, 0xFF2E, 0xFF2F, 0xFF30, 0xFF31, 0xFF32, 0xFF33,
- 0xFF34, 0xFF35, 0xFF36, 0xFF37, 0xFF38, 0xFF39, 0xFF3A, 0xFF41,
- 0xFF42, 0xFF43, 0xFF44, 0xFF45, 0xFF46, 0xFF47, 0xFF48, 0xFF49,
- 0xFF4A, 0xFF4B, 0xFF4C, 0xFF4D, 0xFF4E, 0xFF4F, 0xFF50, 0xFF51,
- 0xFF52, 0xFF53, 0xFF54, 0xFF55, 0xFF56, 0xFF57, 0xFF58, 0xFF59,
- 0xFF5A, 0x3041, 0x3042, 0x3043, 0x3044, 0x3045, 0x3046, 0x3047,
- 0x3048, 0x3049, 0x304A, 0x304B, 0x304C, 0x304D, 0x304E, 0x304F,
- 0x3050, 0x3051, 0x3052, 0x3053, 0x3054, 0x3055, 0x3056, 0x3057,
- 0x3058, 0x3059, 0x305A, 0x305B, 0x305C, 0x305D, 0x305E, 0x305F,
- 0x3060, 0x3061, 0x3062, 0x3063, 0x3064, 0x3065, 0x3066, 0x3067,
- 0x3068, 0x3069, 0x306A, 0x306B, 0x306C, 0x306D, 0x306E, 0x306F,
- 0x3070, 0x3071, 0x3072, 0x3073, 0x3074, 0x3075, 0x3076, 0x3077,
- 0x3078, 0x3079, 0x307A, 0x307B, 0x307C, 0x307D, 0x307E, 0x307F,
- 0x3080, 0x3081, 0x3082, 0x3083, 0x3084, 0x3085, 0x3086, 0x3087,
- 0x3088, 0x3089, 0x308A, 0x308B, 0x308C, 0x308D, 0x308E, 0x308F,
- 0x3090, 0x3091, 0x3092, 0x3093, 0x30A1, 0x30A2, 0x30A3, 0x30A4,
- 0x30A5, 0x30A6, 0x30A7, 0x30A8, 0x30A9, 0x30AA, 0x30AB, 0x30AC,
- 0x30AD, 0x30AE, 0x30AF, 0x30B0, 0x30B1, 0x30B2, 0x30B3, 0x30B4,
- 0x30B5, 0x30B6, 0x30B7, 0x30B8, 0x30B9, 0x30BA, 0x30BB, 0x30BC,
- 0x30BD, 0x30BE, 0x30BF, 0x30C0, 0x30C1, 0x30C2, 0x30C3, 0x30C4,
- 0x30C5, 0x30C6, 0x30C7, 0x30C8, 0x30C9, 0x30CA, 0x30CB, 0x30CC,
- 0x30CD, 0x30CE, 0x30CF, 0x30D0, 0x30D1, 0x30D2, 0x30D3, 0x30D4,
- 0x30D5, 0x30D6, 0x30D7, 0x30D8, 0x30D9, 0x30DA, 0x30DB, 0x30DC,
- 0x30DD, 0x30DE, 0x30DF, 0x30E0, 0x30E1, 0x30E2, 0x30E3, 0x30E4,
- 0x30E5, 0x30E6, 0x30E7, 0x30E8, 0x30E9, 0x30EA, 0x30EB, 0x30EC,
- 0x30ED, 0x30EE, 0x30EF, 0x30F0, 0x30F1, 0x30F2, 0x30F3, 0x30F4,
- 0x30F5, 0x30F6, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396,
- 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E,
- 0x039F, 0x03A0, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
- 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6,
- 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE,
- 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
- 0x03C8, 0x03C9, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415,
- 0x0401, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C,
- 0x041D, 0x041E, 0x041F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0424,
- 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C,
- 0x042D, 0x042E, 0x042F, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434,
- 0x0435, 0x0451, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B,
- 0x043C, 0x043D, 0x043E, 0x043F, 0x0440, 0x0441, 0x0442, 0x0443,
- 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B,
- 0x044C, 0x044D, 0x044E, 0x044F, 0x2500, 0x2502, 0x250C, 0x2510,
- 0x2518, 0x2514, 0x251C, 0x252C, 0x2524, 0x2534, 0x253C, 0x2501,
- 0x2503, 0x250F, 0x2513, 0x251B, 0x2517, 0x2523, 0x2533, 0x252B,
- 0x253B, 0x254B, 0x2520, 0x252F, 0x2528, 0x2537, 0x253F, 0x251D,
- 0x2530, 0x2525, 0x2538, 0x2542,
- // ASCII Section
- SEQUENCE_32(0x20),
- SEQUENCE_32(0x40),
- SEQUENCE_16(0x60),
- SEQUENCE_8(0x70),
- 0x0078, 0x0079, 0x007A, 0x007B, 0x007C, 0x007D, 0x203E,
- // Katakana Section
- 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, 0xFF66, 0xFF67,
- SEQUENCE_8(0xFF68),
- SEQUENCE_16(0xFF70),
- SEQUENCE_32(0xFF80),
- 0x30F0, 0x30F1, 0x30EE, 0xFF76, 0xFF79, 0xFF73, 0x30AB, 0x30AE,
- 0x30B0, 0x30B2, 0x30B4, 0x3056, 0x3058, 0x305A, 0x305C, 0x305E,
- 0x30C0, 0x30C2, 0x30C5, 0x30C7, 0x30C9, 0x30D0, 0x30D1, 0x30D3,
- 0x30D4, 0x30D6, 0x30D7, 0x30D9, 0x30DA, 0x30DC, 0x30DD,
- 0x2460, 0x2461, 0x2462, 0x2463, 0x2464, 0x2465, 0x2466, 0x2467,
- 0x2468, 0x2469, 0x246A, 0x246B, 0x246C, 0x246D, 0x246E, 0x246F,
- 0x2470, 0x2471, 0x2472, 0x2473, 0x2160, 0x2161, 0x2162, 0x2163,
- 0x2164, 0x2165, 0x2166, 0x2167, 0x2168, 0x2169, 0x3349, 0x3314,
- 0x3322, 0x334D, 0x3318, 0x3327, 0x3303, 0x3336, 0x3351, 0x3357,
- 0x330D, 0x3326, 0x3323, 0x332B, 0x334A, 0x333B, 0x339C, 0x339D,
- 0x339E, 0x338E, 0x338F, 0x33C4, 0x33A1, 0x337B, 0x301D, 0x301E,
- 0x2116, 0x33CD, 0x2121, 0x32A4, 0x32A5, 0x32A6, 0x32A7, 0x32A8,
- 0x3231, 0x3232, 0x3239, 0x337E, 0x337D, 0x337C, 0x2252, 0x2261,
- 0x222B, 0x222E, 0x2211, 0x221A, 0x22A5, 0x2220, 0x221F, 0x22BF,
- 0x2235, 0x2229, 0x222A, 0x4E9C, 0x5516, 0x5A03, 0x963F, 0x54C0,
- 0x611B, 0x6328, 0x59F6, 0x9022, 0x8475, 0x831C, 0x7A50, 0x60AA,
- 0x63E1, 0x6E25, 0x65ED, 0x8466, 0x82A6, 0x9BF5, 0x6893, 0x5727,
- 0x65A1, 0x6271, 0x5B9B, 0x59D0, 0x867B, 0x98F4, 0x7D62, 0x7DBE,
- 0x9B8E, 0x6216, 0x7C9F, 0x88B7, 0x5B89, 0x5EB5, 0x6309, 0x6697,
- 0x6848, 0x95C7, 0x978D, 0x674F, 0x4EE5, 0x4F0A, 0x4F4D, 0x4F9D,
- 0x5049, 0x56F2, 0x5937, 0x59D4, 0x5A01, 0x5C09, 0x60DF, 0x610F,
- 0x6170, 0x6613, 0x6905, 0x70BA, 0x754F, 0x7570, 0x79FB, 0x7DAD,
- 0x7DEF, 0x80C3, 0x840E, 0x8863, 0x8B02, 0x9055, 0x907A, 0x533B,
- 0x4E95, 0x4EA5, 0x57DF, 0x80B2, 0x90C1, 0x78EF, 0x4E00, 0x58F1,
- 0x6EA2, 0x9038, 0x7A32, 0x8328, 0x828B, 0x9C2F, 0x5141, 0x5370,
- 0x54BD, 0x54E1, 0x56E0, 0x59FB, 0x5F15, 0x98F2, 0x6DEB, 0x80E4,
- 0x852D, 0x9662, 0x9670, 0x96A0, 0x97FB, 0x540B, 0x53F3, 0x5B87,
- 0x70CF, 0x7FBD, 0x8FC2, 0x96E8, 0x536F, 0x9D5C, 0x7ABA, 0x4E11,
- 0x7893, 0x81FC, 0x6E26, 0x5618, 0x5504, 0x6B1D, 0x851A, 0x9C3B,
- 0x59E5, 0x53A9, 0x6D66, 0x74DC, 0x958F, 0x5642, 0x4E91, 0x904B,
- 0x96F2, 0x834F, 0x990C, 0x53E1, 0x55B6, 0x5B30, 0x5F71, 0x6620,
- 0x66F3, 0x6804, 0x6C38, 0x6CF3, 0x6D29, 0x745B, 0x76C8, 0x7A4E,
- 0x9834, 0x82F1, 0x885B, 0x8A60, 0x92ED, 0x6DB2, 0x75AB, 0x76CA,
- 0x99C5, 0x60A6, 0x8B01, 0x8D8A, 0x95B2, 0x698E, 0x53AD, 0x5186,
- 0x5712, 0x5830, 0x5944, 0x5BB4, 0x5EF6, 0x6028, 0x63A9, 0x63F4,
- 0x6CBF, 0x6F14, 0x708E, 0x7114, 0x7159, 0x71D5, 0x733F, 0x7E01,
- 0x8276, 0x82D1, 0x8597, 0x9060, 0x925B, 0x9D1B, 0x5869, 0x65BC,
- 0x6C5A, 0x7525, 0x51F9, 0x592E, 0x5965, 0x5F80, 0x5FDC, 0x62BC,
- 0x65FA, 0x6A2A, 0x6B27, 0x6BB4, 0x738B, 0x7FC1, 0x8956, 0x9D2C,
- 0x9D0E, 0x9EC4, 0x5CA1, 0x6C96, 0x837B, 0x5104, 0x5C4B, 0x61B6,
- 0x81C6, 0x6876, 0x7261, 0x4E59, 0x4FFA, 0x5378, 0x6069, 0x6E29,
- 0x7A4F, 0x97F3, 0x4E0B, 0x5316, 0x4EEE, 0x4F55, 0x4F3D, 0x4FA1,
- 0x4F73, 0x52A0, 0x53EF, 0x5609, 0x590F, 0x5AC1, 0x5BB6, 0x5BE1,
- 0x79D1, 0x6687, 0x679C, 0x67B6, 0x6B4C, 0x6CB3, 0x706B, 0x73C2,
- 0x798D, 0x79BE, 0x7A3C, 0x7B87, 0x82B1, 0x82DB, 0x8304, 0x8377,
- 0x83EF, 0x83D3, 0x8766, 0x8AB2, 0x5629, 0x8CA8, 0x8FE6, 0x904E,
- 0x971E, 0x868A, 0x4FC4, 0x5CE8, 0x6211, 0x7259, 0x753B, 0x81E5,
- 0x82BD, 0x86FE, 0x8CC0, 0x96C5, 0x9913, 0x99D5, 0x4ECB, 0x4F1A,
- 0x89E3, 0x56DE, 0x584A, 0x58CA, 0x5EFB, 0x5FEB, 0x602A, 0x6094,
- 0x6062, 0x61D0, 0x6212, 0x62D0, 0x6539, 0x9B41, 0x6666, 0x68B0,
- 0x6D77, 0x7070, 0x754C, 0x7686, 0x7D75, 0x82A5, 0x87F9, 0x958B,
- 0x968E, 0x8C9D, 0x51F1, 0x52BE, 0x5916, 0x54B3, 0x5BB3, 0x5D16,
- 0x6168, 0x6982, 0x6DAF, 0x788D, 0x84CB, 0x8857, 0x8A72, 0x93A7,
- 0x9AB8, 0x6D6C, 0x99A8, 0x86D9, 0x57A3, 0x67FF, 0x86CE, 0x920E,
- 0x5283, 0x5687, 0x5404, 0x5ED3, 0x62E1, 0x64B9, 0x683C, 0x6838,
- 0x6BBB, 0x7372, 0x78BA, 0x7A6B, 0x899A, 0x89D2, 0x8D6B, 0x8F03,
- 0x90ED, 0x95A3, 0x9694, 0x9769, 0x5B66, 0x5CB3, 0x697D, 0x984D,
- 0x984E, 0x639B, 0x7B20, 0x6A2B, 0x6A7F, 0x68B6, 0x9C0D, 0x6F5F,
- 0x5272, 0x559D, 0x6070, 0x62EC, 0x6D3B, 0x6E07, 0x6ED1, 0x845B,
- 0x8910, 0x8F44, 0x4E14, 0x9C39, 0x53F6, 0x691B, 0x6A3A, 0x9784,
- 0x682A, 0x515C, 0x7AC3, 0x84B2, 0x91DC, 0x938C, 0x565B, 0x9D28,
- 0x6822, 0x8305, 0x8431, 0x7CA5, 0x5208, 0x82C5, 0x74E6, 0x4E7E,
- 0x4F83, 0x51A0, 0x5BD2, 0x520A, 0x52D8, 0x52E7, 0x5DFB, 0x559A,
- 0x582A, 0x59E6, 0x5B8C, 0x5B98, 0x5BDB, 0x5E72, 0x5E79, 0x60A3,
- 0x611F, 0x6163, 0x61BE, 0x63DB, 0x6562, 0x67D1, 0x6853, 0x68FA,
- 0x6B3E, 0x6B53, 0x6C57, 0x6F22, 0x6F97, 0x6F45, 0x74B0, 0x7518,
- 0x76E3, 0x770B, 0x7AFF, 0x7BA1, 0x7C21, 0x7DE9, 0x7F36, 0x7FF0,
- 0x809D, 0x8266, 0x839E, 0x89B3, 0x8ACC, 0x8CAB, 0x9084, 0x9451,
- 0x9593, 0x9591, 0x95A2, 0x9665, 0x97D3, 0x9928, 0x8218, 0x4E38,
- 0x542B, 0x5CB8, 0x5DCC, 0x73A9, 0x764C, 0x773C, 0x5CA9, 0x7FEB,
- 0x8D0B, 0x96C1, 0x9811, 0x9854, 0x9858, 0x4F01, 0x4F0E, 0x5371,
- 0x559C, 0x5668, 0x57FA, 0x5947, 0x5B09, 0x5BC4, 0x5C90, 0x5E0C,
- 0x5E7E, 0x5FCC, 0x63EE, 0x673A, 0x65D7, 0x65E2, 0x671F, 0x68CB,
- 0x68C4, 0x6A5F, 0x5E30, 0x6BC5, 0x6C17, 0x6C7D, 0x757F, 0x7948,
- 0x5B63, 0x7A00, 0x7D00, 0x5FBD, 0x898F, 0x8A18, 0x8CB4, 0x8D77,
- 0x8ECC, 0x8F1D, 0x98E2, 0x9A0E, 0x9B3C, 0x4E80, 0x507D, 0x5100,
- 0x5993, 0x5B9C, 0x622F, 0x6280, 0x64EC, 0x6B3A, 0x72A0, 0x7591,
- 0x7947, 0x7FA9, 0x87FB, 0x8ABC, 0x8B70, 0x63AC, 0x83CA, 0x97A0,
- 0x5409, 0x5403, 0x55AB, 0x6854, 0x6A58, 0x8A70, 0x7827, 0x6775,
- 0x9ECD, 0x5374, 0x5BA2, 0x811A, 0x8650, 0x9006, 0x4E18, 0x4E45,
- 0x4EC7, 0x4F11, 0x53CA, 0x5438, 0x5BAE, 0x5F13, 0x6025, 0x6551,
- 0x673D, 0x6C42, 0x6C72, 0x6CE3, 0x7078, 0x7403, 0x7A76, 0x7AAE,
- 0x7B08, 0x7D1A, 0x7CFE, 0x7D66, 0x65E7, 0x725B, 0x53BB, 0x5C45,
- 0x5DE8, 0x62D2, 0x62E0, 0x6319, 0x6E20, 0x865A, 0x8A31, 0x8DDD,
- 0x92F8, 0x6F01, 0x79A6, 0x9B5A, 0x4EA8, 0x4EAB, 0x4EAC, 0x4F9B,
- 0x4FA0, 0x50D1, 0x5147, 0x7AF6, 0x5171, 0x51F6, 0x5354, 0x5321,
- 0x537F, 0x53EB, 0x55AC, 0x5883, 0x5CE1, 0x5F37, 0x5F4A, 0x602F,
- 0x6050, 0x606D, 0x631F, 0x6559, 0x6A4B, 0x6CC1, 0x72C2, 0x72ED,
- 0x77EF, 0x80F8, 0x8105, 0x8208, 0x854E, 0x90F7, 0x93E1, 0x97FF,
- 0x9957, 0x9A5A, 0x4EF0, 0x51DD, 0x5C2D, 0x6681, 0x696D, 0x5C40,
- 0x66F2, 0x6975, 0x7389, 0x6850, 0x7C81, 0x50C5, 0x52E4, 0x5747,
- 0x5DFE, 0x9326, 0x65A4, 0x6B23, 0x6B3D, 0x7434, 0x7981, 0x79BD,
- 0x7B4B, 0x7DCA, 0x82B9, 0x83CC, 0x887F, 0x895F, 0x8B39, 0x8FD1,
- 0x91D1, 0x541F, 0x9280, 0x4E5D, 0x5036, 0x53E5, 0x533A, 0x72D7,
- 0x7396, 0x77E9, 0x82E6, 0x8EAF, 0x99C6, 0x99C8, 0x99D2, 0x5177,
- 0x611A, 0x865E, 0x55B0, 0x7A7A, 0x5076, 0x5BD3, 0x9047, 0x9685,
- 0x4E32, 0x6ADB, 0x91E7, 0x5C51, 0x5C48, 0x6398, 0x7A9F, 0x6C93,
- 0x9774, 0x8F61, 0x7AAA, 0x718A, 0x9688, 0x7C82, 0x6817, 0x7E70,
- 0x6851, 0x936C, 0x52F2, 0x541B, 0x85AB, 0x8A13, 0x7FA4, 0x8ECD,
- 0x90E1, 0x5366, 0x8888, 0x7941, 0x4FC2, 0x50BE, 0x5211, 0x5144,
- 0x5553, 0x572D, 0x73EA, 0x578B, 0x5951, 0x5F62, 0x5F84, 0x6075,
- 0x6176, 0x6167, 0x61A9, 0x63B2, 0x643A, 0x656C, 0x666F, 0x6842,
- 0x6E13, 0x7566, 0x7A3D, 0x7CFB, 0x7D4C, 0x7D99, 0x7E4B, 0x7F6B,
- 0x830E, 0x834A, 0x86CD, 0x8A08, 0x8A63, 0x8B66, 0x8EFD, 0x981A,
- 0x9D8F, 0x82B8, 0x8FCE, 0x9BE8, 0x5287, 0x621F, 0x6483, 0x6FC0,
- 0x9699, 0x6841, 0x5091, 0x6B20, 0x6C7A, 0x6F54, 0x7A74, 0x7D50,
- 0x8840, 0x8A23, 0x6708, 0x4EF6, 0x5039, 0x5026, 0x5065, 0x517C,
- 0x5238, 0x5263, 0x55A7, 0x570F, 0x5805, 0x5ACC, 0x5EFA, 0x61B2,
- 0x61F8, 0x62F3, 0x6372, 0x691C, 0x6A29, 0x727D, 0x72AC, 0x732E,
- 0x7814, 0x786F, 0x7D79, 0x770C, 0x80A9, 0x898B, 0x8B19, 0x8CE2,
- 0x8ED2, 0x9063, 0x9375, 0x967A, 0x9855, 0x9A13, 0x9E78, 0x5143,
- 0x539F, 0x53B3, 0x5E7B, 0x5F26, 0x6E1B, 0x6E90, 0x7384, 0x73FE,
- 0x7D43, 0x8237, 0x8A00, 0x8AFA, 0x9650, 0x4E4E, 0x500B, 0x53E4,
- 0x547C, 0x56FA, 0x59D1, 0x5B64, 0x5DF1, 0x5EAB, 0x5F27, 0x6238,
- 0x6545, 0x67AF, 0x6E56, 0x72D0, 0x7CCA, 0x88B4, 0x80A1, 0x80E1,
- 0x83F0, 0x864E, 0x8A87, 0x8DE8, 0x9237, 0x96C7, 0x9867, 0x9F13,
- 0x4E94, 0x4E92, 0x4F0D, 0x5348, 0x5449, 0x543E, 0x5A2F, 0x5F8C,
- 0x5FA1, 0x609F, 0x68A7, 0x6A8E, 0x745A, 0x7881, 0x8A9E, 0x8AA4,
- 0x8B77, 0x9190, 0x4E5E, 0x9BC9, 0x4EA4, 0x4F7C, 0x4FAF, 0x5019,
- 0x5016, 0x5149, 0x516C, 0x529F, 0x52B9, 0x52FE, 0x539A, 0x53E3,
- 0x5411, 0x540E, 0x5589, 0x5751, 0x57A2, 0x597D, 0x5B54, 0x5B5D,
- 0x5B8F, 0x5DE5, 0x5DE7, 0x5DF7, 0x5E78, 0x5E83, 0x5E9A, 0x5EB7,
- 0x5F18, 0x6052, 0x614C, 0x6297, 0x62D8, 0x63A7, 0x653B, 0x6602,
- 0x6643, 0x66F4, 0x676D, 0x6821, 0x6897, 0x69CB, 0x6C5F, 0x6D2A,
- 0x6D69, 0x6E2F, 0x6E9D, 0x7532, 0x7687, 0x786C, 0x7A3F, 0x7CE0,
- 0x7D05, 0x7D18, 0x7D5E, 0x7DB1, 0x8015, 0x8003, 0x80AF, 0x80B1,
- 0x8154, 0x818F, 0x822A, 0x8352, 0x884C, 0x8861, 0x8B1B, 0x8CA2,
- 0x8CFC, 0x90CA, 0x9175, 0x9271, 0x783F, 0x92FC, 0x95A4, 0x964D,
- 0x9805, 0x9999, 0x9AD8, 0x9D3B, 0x525B, 0x52AB, 0x53F7, 0x5408,
- 0x58D5, 0x62F7, 0x6FE0, 0x8C6A, 0x8F5F, 0x9EB9, 0x514B, 0x523B,
- 0x544A, 0x56FD, 0x7A40, 0x9177, 0x9D60, 0x9ED2, 0x7344, 0x6F09,
- 0x8170, 0x7511, 0x5FFD, 0x60DA, 0x9AA8, 0x72DB, 0x8FBC, 0x6B64,
- 0x9803, 0x4ECA, 0x56F0, 0x5764, 0x58BE, 0x5A5A, 0x6068, 0x61C7,
- 0x660F, 0x6606, 0x6839, 0x68B1, 0x6DF7, 0x75D5, 0x7D3A, 0x826E,
- 0x9B42, 0x4E9B, 0x4F50, 0x53C9, 0x5506, 0x5D6F, 0x5DE6, 0x5DEE,
- 0x67FB, 0x6C99, 0x7473, 0x7802, 0x8A50, 0x9396, 0x88DF, 0x5750,
- 0x5EA7, 0x632B, 0x50B5, 0x50AC, 0x518D, 0x6700, 0x54C9, 0x585E,
- 0x59BB, 0x5BB0, 0x5F69, 0x624D, 0x63A1, 0x683D, 0x6B73, 0x6E08,
- 0x707D, 0x91C7, 0x7280, 0x7815, 0x7826, 0x796D, 0x658E, 0x7D30,
- 0x83DC, 0x88C1, 0x8F09, 0x969B, 0x5264, 0x5728, 0x6750, 0x7F6A,
- 0x8CA1, 0x51B4, 0x5742, 0x962A, 0x583A, 0x698A, 0x80B4, 0x54B2,
- 0x5D0E, 0x57FC, 0x7895, 0x9DFA, 0x4F5C, 0x524A, 0x548B, 0x643E,
- 0x6628, 0x6714, 0x67F5, 0x7A84, 0x7B56, 0x7D22, 0x932F, 0x685C,
- 0x9BAD, 0x7B39, 0x5319, 0x518A, 0x5237, 0x5BDF, 0x62F6, 0x64AE,
- 0x64E6, 0x672D, 0x6BBA, 0x85A9, 0x96D1, 0x7690, 0x9BD6, 0x634C,
- 0x9306, 0x9BAB, 0x76BF, 0x6652, 0x4E09, 0x5098, 0x53C2, 0x5C71,
- 0x60E8, 0x6492, 0x6563, 0x685F, 0x71E6, 0x73CA, 0x7523, 0x7B97,
- 0x7E82, 0x8695, 0x8B83, 0x8CDB, 0x9178, 0x9910, 0x65AC, 0x66AB,
- 0x6B8B, 0x4ED5, 0x4ED4, 0x4F3A, 0x4F7F, 0x523A, 0x53F8, 0x53F2,
- 0x55E3, 0x56DB, 0x58EB, 0x59CB, 0x59C9, 0x59FF, 0x5B50, 0x5C4D,
- 0x5E02, 0x5E2B, 0x5FD7, 0x601D, 0x6307, 0x652F, 0x5B5C, 0x65AF,
- 0x65BD, 0x65E8, 0x679D, 0x6B62, 0x6B7B, 0x6C0F, 0x7345, 0x7949,
- 0x79C1, 0x7CF8, 0x7D19, 0x7D2B, 0x80A2, 0x8102, 0x81F3, 0x8996,
- 0x8A5E, 0x8A69, 0x8A66, 0x8A8C, 0x8AEE, 0x8CC7, 0x8CDC, 0x96CC,
- 0x98FC, 0x6B6F, 0x4E8B, 0x4F3C, 0x4F8D, 0x5150, 0x5B57, 0x5BFA,
- 0x6148, 0x6301, 0x6642, 0x6B21, 0x6ECB, 0x6CBB, 0x723E, 0x74BD,
- 0x75D4, 0x78C1, 0x793A, 0x800C, 0x8033, 0x81EA, 0x8494, 0x8F9E,
- 0x6C50, 0x9E7F, 0x5F0F, 0x8B58, 0x9D2B, 0x7AFA, 0x8EF8, 0x5B8D,
- 0x96EB, 0x4E03, 0x53F1, 0x57F7, 0x5931, 0x5AC9, 0x5BA4, 0x6089,
- 0x6E7F, 0x6F06, 0x75BE, 0x8CEA, 0x5B9F, 0x8500, 0x7BE0, 0x5072,
- 0x67F4, 0x829D, 0x5C61, 0x854A, 0x7E1E, 0x820E, 0x5199, 0x5C04,
- 0x6368, 0x8D66, 0x659C, 0x716E, 0x793E, 0x7D17, 0x8005, 0x8B1D,
- 0x8ECA, 0x906E, 0x86C7, 0x90AA, 0x501F, 0x52FA, 0x5C3A, 0x6753,
- 0x707C, 0x7235, 0x914C, 0x91C8, 0x932B, 0x82E5, 0x5BC2, 0x5F31,
- 0x60F9, 0x4E3B, 0x53D6, 0x5B88, 0x624B, 0x6731, 0x6B8A, 0x72E9,
- 0x73E0, 0x7A2E, 0x816B, 0x8DA3, 0x9152, 0x9996, 0x5112, 0x53D7,
- 0x546A, 0x5BFF, 0x6388, 0x6A39, 0x7DAC, 0x9700, 0x56DA, 0x53CE,
- 0x5468, 0x5B97, 0x5C31, 0x5DDE, 0x4FEE, 0x6101, 0x62FE, 0x6D32,
- 0x79C0, 0x79CB, 0x7D42, 0x7E4D, 0x7FD2, 0x81ED, 0x821F, 0x8490,
- 0x8846, 0x8972, 0x8B90, 0x8E74, 0x8F2F, 0x9031, 0x914B, 0x916C,
- 0x96C6, 0x919C, 0x4EC0, 0x4F4F, 0x5145, 0x5341, 0x5F93, 0x620E,
- 0x67D4, 0x6C41, 0x6E0B, 0x7363, 0x7E26, 0x91CD, 0x9283, 0x53D4,
- 0x5919, 0x5BBF, 0x6DD1, 0x795D, 0x7E2E, 0x7C9B, 0x587E, 0x719F,
- 0x51FA, 0x8853, 0x8FF0, 0x4FCA, 0x5CFB, 0x6625, 0x77AC, 0x7AE3,
- 0x821C, 0x99FF, 0x51C6, 0x5FAA, 0x65EC, 0x696F, 0x6B89, 0x6DF3,
- 0x6E96, 0x6F64, 0x76FE, 0x7D14, 0x5DE1, 0x9075, 0x9187, 0x9806,
- 0x51E6, 0x521D, 0x6240, 0x6691, 0x66D9, 0x6E1A, 0x5EB6, 0x7DD2,
- 0x7F72, 0x66F8, 0x85AF, 0x85F7, 0x8AF8, 0x52A9, 0x53D9, 0x5973,
- 0x5E8F, 0x5F90, 0x6055, 0x92E4, 0x9664, 0x50B7, 0x511F, 0x52DD,
- 0x5320, 0x5347, 0x53EC, 0x54E8, 0x5546, 0x5531, 0x5617, 0x5968,
- 0x59BE, 0x5A3C, 0x5BB5, 0x5C06, 0x5C0F, 0x5C11, 0x5C1A, 0x5E84,
- 0x5E8A, 0x5EE0, 0x5F70, 0x627F, 0x6284, 0x62DB, 0x638C, 0x6377,
- 0x6607, 0x660C, 0x662D, 0x6676, 0x677E, 0x68A2, 0x6A1F, 0x6A35,
- 0x6CBC, 0x6D88, 0x6E09, 0x6E58, 0x713C, 0x7126, 0x7167, 0x75C7,
- 0x7701, 0x785D, 0x7901, 0x7965, 0x79F0, 0x7AE0, 0x7B11, 0x7CA7,
- 0x7D39, 0x8096, 0x83D6, 0x848B, 0x8549, 0x885D, 0x88F3, 0x8A1F,
- 0x8A3C, 0x8A54, 0x8A73, 0x8C61, 0x8CDE, 0x91A4, 0x9266, 0x937E,
- 0x9418, 0x969C, 0x9798, 0x4E0A, 0x4E08, 0x4E1E, 0x4E57, 0x5197,
- 0x5270, 0x57CE, 0x5834, 0x58CC, 0x5B22, 0x5E38, 0x60C5, 0x64FE,
- 0x6761, 0x6756, 0x6D44, 0x72B6, 0x7573, 0x7A63, 0x84B8, 0x8B72,
- 0x91B8, 0x9320, 0x5631, 0x57F4, 0x98FE, 0x62ED, 0x690D, 0x6B96,
- 0x71ED, 0x7E54, 0x8077, 0x8272, 0x89E6, 0x98DF, 0x8755, 0x8FB1,
- 0x5C3B, 0x4F38, 0x4FE1, 0x4FB5, 0x5507, 0x5A20, 0x5BDD, 0x5BE9,
- 0x5FC3, 0x614E, 0x632F, 0x65B0, 0x664B, 0x68EE, 0x699B, 0x6D78,
- 0x6DF1, 0x7533, 0x75B9, 0x771F, 0x795E, 0x79E6, 0x7D33, 0x81E3,
- 0x82AF, 0x85AA, 0x89AA, 0x8A3A, 0x8EAB, 0x8F9B, 0x9032, 0x91DD,
- 0x9707, 0x4EBA, 0x4EC1, 0x5203, 0x5875, 0x58EC, 0x5C0B, 0x751A,
- 0x5C3D, 0x814E, 0x8A0A, 0x8FC5, 0x9663, 0x976D, 0x7B25, 0x8ACF,
- 0x9808, 0x9162, 0x56F3, 0x53A8, 0x9017, 0x5439, 0x5782, 0x5E25,
- 0x63A8, 0x6C34, 0x708A, 0x7761, 0x7C8B, 0x7FE0, 0x8870, 0x9042,
- 0x9154, 0x9310, 0x9318, 0x968F, 0x745E, 0x9AC4, 0x5D07, 0x5D69,
- 0x6570, 0x67A2, 0x8DA8, 0x96DB, 0x636E, 0x6749, 0x6919, 0x83C5,
- 0x9817, 0x96C0, 0x88FE, 0x6F84, 0x647A, 0x5BF8, 0x4E16, 0x702C,
- 0x755D, 0x662F, 0x51C4, 0x5236, 0x52E2, 0x59D3, 0x5F81, 0x6027,
- 0x6210, 0x653F, 0x6574, 0x661F, 0x6674, 0x68F2, 0x6816, 0x6B63,
- 0x6E05, 0x7272, 0x751F, 0x76DB, 0x7CBE, 0x8056, 0x58F0, 0x88FD,
- 0x897F, 0x8AA0, 0x8A93, 0x8ACB, 0x901D, 0x9192, 0x9752, 0x9759,
- 0x6589, 0x7A0E, 0x8106, 0x96BB, 0x5E2D, 0x60DC, 0x621A, 0x65A5,
- 0x6614, 0x6790, 0x77F3, 0x7A4D, 0x7C4D, 0x7E3E, 0x810A, 0x8CAC,
- 0x8D64, 0x8DE1, 0x8E5F, 0x78A9, 0x5207, 0x62D9, 0x63A5, 0x6442,
- 0x6298, 0x8A2D, 0x7A83, 0x7BC0, 0x8AAC, 0x96EA, 0x7D76, 0x820C,
- 0x8749, 0x4ED9, 0x5148, 0x5343, 0x5360, 0x5BA3, 0x5C02, 0x5C16,
- 0x5DDD, 0x6226, 0x6247, 0x64B0, 0x6813, 0x6834, 0x6CC9, 0x6D45,
- 0x6D17, 0x67D3, 0x6F5C, 0x714E, 0x717D, 0x65CB, 0x7A7F, 0x7BAD,
- 0x7DDA, 0x7E4A, 0x7FA8, 0x817A, 0x821B, 0x8239, 0x85A6, 0x8A6E,
- 0x8CCE, 0x8DF5, 0x9078, 0x9077, 0x92AD, 0x9291, 0x9583, 0x9BAE,
- 0x524D, 0x5584, 0x6F38, 0x7136, 0x5168, 0x7985, 0x7E55, 0x81B3,
- 0x7CCE, 0x564C, 0x5851, 0x5CA8, 0x63AA, 0x66FE, 0x66FD, 0x695A,
- 0x72D9, 0x758F, 0x758E, 0x790E, 0x7956, 0x79DF, 0x7C97, 0x7D20,
- 0x7D44, 0x8607, 0x8A34, 0x963B, 0x9061, 0x9F20, 0x50E7, 0x5275,
- 0x53CC, 0x53E2, 0x5009, 0x55AA, 0x58EE, 0x594F, 0x723D, 0x5B8B,
- 0x5C64, 0x531D, 0x60E3, 0x60F3, 0x635C, 0x6383, 0x633F, 0x63BB,
- 0x64CD, 0x65E9, 0x66F9, 0x5DE3, 0x69CD, 0x69FD, 0x6F15, 0x71E5,
- 0x4E89, 0x75E9, 0x76F8, 0x7A93, 0x7CDF, 0x7DCF, 0x7D9C, 0x8061,
- 0x8349, 0x8358, 0x846C, 0x84BC, 0x85FB, 0x88C5, 0x8D70, 0x9001,
- 0x906D, 0x9397, 0x971C, 0x9A12, 0x50CF, 0x5897, 0x618E, 0x81D3,
- 0x8535, 0x8D08, 0x9020, 0x4FC3, 0x5074, 0x5247, 0x5373, 0x606F,
- 0x6349, 0x675F, 0x6E2C, 0x8DB3, 0x901F, 0x4FD7, 0x5C5E, 0x8CCA,
- 0x65CF, 0x7D9A, 0x5352, 0x8896, 0x5176, 0x63C3, 0x5B58, 0x5B6B,
- 0x5C0A, 0x640D, 0x6751, 0x905C, 0x4ED6, 0x591A, 0x592A, 0x6C70,
- 0x8A51, 0x553E, 0x5815, 0x59A5, 0x60F0, 0x6253, 0x67C1, 0x8235,
- 0x6955, 0x9640, 0x99C4, 0x9A28, 0x4F53, 0x5806, 0x5BFE, 0x8010,
- 0x5CB1, 0x5E2F, 0x5F85, 0x6020, 0x614B, 0x6234, 0x66FF, 0x6CF0,
- 0x6EDE, 0x80CE, 0x817F, 0x82D4, 0x888B, 0x8CB8, 0x9000, 0x902E,
- 0x968A, 0x9EDB, 0x9BDB, 0x4EE3, 0x53F0, 0x5927, 0x7B2C, 0x918D,
- 0x984C, 0x9DF9, 0x6EDD, 0x7027, 0x5353, 0x5544, 0x5B85, 0x6258,
- 0x629E, 0x62D3, 0x6CA2, 0x6FEF, 0x7422, 0x8A17, 0x9438, 0x6FC1,
- 0x8AFE, 0x8338, 0x51E7, 0x86F8, 0x53EA, 0x53E9, 0x4F46, 0x9054,
- 0x8FB0, 0x596A, 0x8131, 0x5DFD, 0x7AEA, 0x8FBF, 0x68DA, 0x8C37,
- 0x72F8, 0x9C48, 0x6A3D, 0x8AB0, 0x4E39, 0x5358, 0x5606, 0x5766,
- 0x62C5, 0x63A2, 0x65E6, 0x6B4E, 0x6DE1, 0x6E5B, 0x70AD, 0x77ED,
- 0x7AEF, 0x7BAA, 0x7DBB, 0x803D, 0x80C6, 0x86CB, 0x8A95, 0x935B,
- 0x56E3, 0x58C7, 0x5F3E, 0x65AD, 0x6696, 0x6A80, 0x6BB5, 0x7537,
- 0x8AC7, 0x5024, 0x77E5, 0x5730, 0x5F1B, 0x6065, 0x667A, 0x6C60,
- 0x75F4, 0x7A1A, 0x7F6E, 0x81F4, 0x8718, 0x9045, 0x99B3, 0x7BC9,
- 0x755C, 0x7AF9, 0x7B51, 0x84C4, 0x9010, 0x79E9, 0x7A92, 0x8336,
- 0x5AE1, 0x7740, 0x4E2D, 0x4EF2, 0x5B99, 0x5FE0, 0x62BD, 0x663C,
- 0x67F1, 0x6CE8, 0x866B, 0x8877, 0x8A3B, 0x914E, 0x92F3, 0x99D0,
- 0x6A17, 0x7026, 0x732A, 0x82E7, 0x8457, 0x8CAF, 0x4E01, 0x5146,
- 0x51CB, 0x558B, 0x5BF5, 0x5E16, 0x5E33, 0x5E81, 0x5F14, 0x5F35,
- 0x5F6B, 0x5FB4, 0x61F2, 0x6311, 0x66A2, 0x671D, 0x6F6E, 0x7252,
- 0x753A, 0x773A, 0x8074, 0x8139, 0x8178, 0x8776, 0x8ABF, 0x8ADC,
- 0x8D85, 0x8DF3, 0x929A, 0x9577, 0x9802, 0x9CE5, 0x52C5, 0x6357,
- 0x76F4, 0x6715, 0x6C88, 0x73CD, 0x8CC3, 0x93AE, 0x9673, 0x6D25,
- 0x589C, 0x690E, 0x69CC, 0x8FFD, 0x939A, 0x75DB, 0x901A, 0x585A,
- 0x6802, 0x63B4, 0x69FB, 0x4F43, 0x6F2C, 0x67D8, 0x8FBB, 0x8526,
- 0x7DB4, 0x9354, 0x693F, 0x6F70, 0x576A, 0x58F7, 0x5B2C, 0x7D2C,
- 0x722A, 0x540A, 0x91E3, 0x9DB4, 0x4EAD, 0x4F4E, 0x505C, 0x5075,
- 0x5243, 0x8C9E, 0x5448, 0x5824, 0x5B9A, 0x5E1D, 0x5E95, 0x5EAD,
- 0x5EF7, 0x5F1F, 0x608C, 0x62B5, 0x633A, 0x63D0, 0x68AF, 0x6C40,
- 0x7887, 0x798E, 0x7A0B, 0x7DE0, 0x8247, 0x8A02, 0x8AE6, 0x8E44,
- 0x9013, 0x90B8, 0x912D, 0x91D8, 0x9F0E, 0x6CE5, 0x6458, 0x64E2,
- 0x6575, 0x6EF4, 0x7684, 0x7B1B, 0x9069, 0x93D1, 0x6EBA, 0x54F2,
- 0x5FB9, 0x64A4, 0x8F4D, 0x8FED, 0x9244, 0x5178, 0x586B, 0x5929,
- 0x5C55, 0x5E97, 0x6DFB, 0x7E8F, 0x751C, 0x8CBC, 0x8EE2, 0x985B,
- 0x70B9, 0x4F1D, 0x6BBF, 0x6FB1, 0x7530, 0x96FB, 0x514E, 0x5410,
- 0x5835, 0x5857, 0x59AC, 0x5C60, 0x5F92, 0x6597, 0x675C, 0x6E21,
- 0x767B, 0x83DF, 0x8CED, 0x9014, 0x90FD, 0x934D, 0x7825, 0x783A,
- 0x52AA, 0x5EA6, 0x571F, 0x5974, 0x6012, 0x5012, 0x515A, 0x51AC,
- 0x51CD, 0x5200, 0x5510, 0x5854, 0x5858, 0x5957, 0x5B95, 0x5CF6,
- 0x5D8B, 0x60BC, 0x6295, 0x642D, 0x6771, 0x6843, 0x68BC, 0x68DF,
- 0x76D7, 0x6DD8, 0x6E6F, 0x6D9B, 0x706F, 0x71C8, 0x5F53, 0x75D8,
- 0x7977, 0x7B49, 0x7B54, 0x7B52, 0x7CD6, 0x7D71, 0x5230, 0x8463,
- 0x8569, 0x85E4, 0x8A0E, 0x8B04, 0x8C46, 0x8E0F, 0x9003, 0x900F,
- 0x9419, 0x9676, 0x982D, 0x9A30, 0x95D8, 0x50CD, 0x52D5, 0x540C,
- 0x5802, 0x5C0E, 0x61A7, 0x649E, 0x6D1E, 0x77B3, 0x7AE5, 0x80F4,
- 0x8404, 0x9053, 0x9285, 0x5CE0, 0x9D07, 0x533F, 0x5F97, 0x5FB3,
- 0x6D9C, 0x7279, 0x7763, 0x79BF, 0x7BE4, 0x6BD2, 0x72EC, 0x8AAD,
- 0x6803, 0x6A61, 0x51F8, 0x7A81, 0x6934, 0x5C4A, 0x9CF6, 0x82EB,
- 0x5BC5, 0x9149, 0x701E, 0x5678, 0x5C6F, 0x60C7, 0x6566, 0x6C8C,
- 0x8C5A, 0x9041, 0x9813, 0x5451, 0x66C7, 0x920D, 0x5948, 0x90A3,
- 0x5185, 0x4E4D, 0x51EA, 0x8599, 0x8B0E, 0x7058, 0x637A, 0x934B,
- 0x6962, 0x99B4, 0x7E04, 0x7577, 0x5357, 0x6960, 0x8EDF, 0x96E3,
- 0x6C5D, 0x4E8C, 0x5C3C, 0x5F10, 0x8FE9, 0x5302, 0x8CD1, 0x8089,
- 0x8679, 0x5EFF, 0x65E5, 0x4E73, 0x5165, 0x5982, 0x5C3F, 0x97EE,
- 0x4EFB, 0x598A, 0x5FCD, 0x8A8D, 0x6FE1, 0x79B0, 0x7962, 0x5BE7,
- 0x8471, 0x732B, 0x71B1, 0x5E74, 0x5FF5, 0x637B, 0x649A, 0x71C3,
- 0x7C98, 0x4E43, 0x5EFC, 0x4E4B, 0x57DC, 0x56A2, 0x60A9, 0x6FC3,
- 0x7D0D, 0x80FD, 0x8133, 0x81BF, 0x8FB2, 0x8997, 0x86A4, 0x5DF4,
- 0x628A, 0x64AD, 0x8987, 0x6777, 0x6CE2, 0x6D3E, 0x7436, 0x7834,
- 0x5A46, 0x7F75, 0x82AD, 0x99AC, 0x4FF3, 0x5EC3, 0x62DD, 0x6392,
- 0x6557, 0x676F, 0x76C3, 0x724C, 0x80CC, 0x80BA, 0x8F29, 0x914D,
- 0x500D, 0x57F9, 0x5A92, 0x6885, 0x6973, 0x7164, 0x72FD, 0x8CB7,
- 0x58F2, 0x8CE0, 0x966A, 0x9019, 0x877F, 0x79E4, 0x77E7, 0x8429,
- 0x4F2F, 0x5265, 0x535A, 0x62CD, 0x67CF, 0x6CCA, 0x767D, 0x7B94,
- 0x7C95, 0x8236, 0x8584, 0x8FEB, 0x66DD, 0x6F20, 0x7206, 0x7E1B,
- 0x83AB, 0x99C1, 0x9EA6, 0x51FD, 0x7BB1, 0x7872, 0x7BB8, 0x8087,
- 0x7B48, 0x6AE8, 0x5E61, 0x808C, 0x7551, 0x7560, 0x516B, 0x9262,
- 0x6E8C, 0x767A, 0x9197, 0x9AEA, 0x4F10, 0x7F70, 0x629C, 0x7B4F,
- 0x95A5, 0x9CE9, 0x567A, 0x5859, 0x86E4, 0x96BC, 0x4F34, 0x5224,
- 0x534A, 0x53CD, 0x53DB, 0x5E06, 0x642C, 0x6591, 0x677F, 0x6C3E,
- 0x6C4E, 0x7248, 0x72AF, 0x73ED, 0x7554, 0x7E41, 0x822C, 0x85E9,
- 0x8CA9, 0x7BC4, 0x91C6, 0x7169, 0x9812, 0x98EF, 0x633D, 0x6669,
- 0x756A, 0x76E4, 0x78D0, 0x8543, 0x86EE, 0x532A, 0x5351, 0x5426,
- 0x5983, 0x5E87, 0x5F7C, 0x60B2, 0x6249, 0x6279, 0x62AB, 0x6590,
- 0x6BD4, 0x6CCC, 0x75B2, 0x76AE, 0x7891, 0x79D8, 0x7DCB, 0x7F77,
- 0x80A5, 0x88AB, 0x8AB9, 0x8CBB, 0x907F, 0x975E, 0x98DB, 0x6A0B,
- 0x7C38, 0x5099, 0x5C3E, 0x5FAE, 0x6787, 0x6BD8, 0x7435, 0x7709,
- 0x7F8E, 0x9F3B, 0x67CA, 0x7A17, 0x5339, 0x758B, 0x9AED, 0x5F66,
- 0x819D, 0x83F1, 0x8098, 0x5F3C, 0x5FC5, 0x7562, 0x7B46, 0x903C,
- 0x6867, 0x59EB, 0x5A9B, 0x7D10, 0x767E, 0x8B2C, 0x4FF5, 0x5F6A,
- 0x6A19, 0x6C37, 0x6F02, 0x74E2, 0x7968, 0x8868, 0x8A55, 0x8C79,
- 0x5EDF, 0x63CF, 0x75C5, 0x79D2, 0x82D7, 0x9328, 0x92F2, 0x849C,
- 0x86ED, 0x9C2D, 0x54C1, 0x5F6C, 0x658C, 0x6D5C, 0x7015, 0x8CA7,
- 0x8CD3, 0x983B, 0x654F, 0x74F6, 0x4E0D, 0x4ED8, 0x57E0, 0x592B,
- 0x5A66, 0x5BCC, 0x51A8, 0x5E03, 0x5E9C, 0x6016, 0x6276, 0x6577,
- 0x65A7, 0x666E, 0x6D6E, 0x7236, 0x7B26, 0x8150, 0x819A, 0x8299,
- 0x8B5C, 0x8CA0, 0x8CE6, 0x8D74, 0x961C, 0x9644, 0x4FAE, 0x64AB,
- 0x6B66, 0x821E, 0x8461, 0x856A, 0x90E8, 0x5C01, 0x6953, 0x98A8,
- 0x847A, 0x8557, 0x4F0F, 0x526F, 0x5FA9, 0x5E45, 0x670D, 0x798F,
- 0x8179, 0x8907, 0x8986, 0x6DF5, 0x5F17, 0x6255, 0x6CB8, 0x4ECF,
- 0x7269, 0x9B92, 0x5206, 0x543B, 0x5674, 0x58B3, 0x61A4, 0x626E,
- 0x711A, 0x596E, 0x7C89, 0x7CDE, 0x7D1B, 0x96F0, 0x6587, 0x805E,
- 0x4E19, 0x4F75, 0x5175, 0x5840, 0x5E63, 0x5E73, 0x5F0A, 0x67C4,
- 0x4E26, 0x853D, 0x9589, 0x965B, 0x7C73, 0x9801, 0x50FB, 0x58C1,
- 0x7656, 0x78A7, 0x5225, 0x77A5, 0x8511, 0x7B86, 0x504F, 0x5909,
- 0x7247, 0x7BC7, 0x7DE8, 0x8FBA, 0x8FD4, 0x904D, 0x4FBF, 0x52C9,
- 0x5A29, 0x5F01, 0x97AD, 0x4FDD, 0x8217, 0x92EA, 0x5703, 0x6355,
- 0x6B69, 0x752B, 0x88DC, 0x8F14, 0x7A42, 0x52DF, 0x5893, 0x6155,
- 0x620A, 0x66AE, 0x6BCD, 0x7C3F, 0x83E9, 0x5023, 0x4FF8, 0x5305,
- 0x5446, 0x5831, 0x5949, 0x5B9D, 0x5CF0, 0x5CEF, 0x5D29, 0x5E96,
- 0x62B1, 0x6367, 0x653E, 0x65B9, 0x670B, 0x6CD5, 0x6CE1, 0x70F9,
- 0x7832, 0x7E2B, 0x80DE, 0x82B3, 0x840C, 0x84EC, 0x8702, 0x8912,
- 0x8A2A, 0x8C4A, 0x90A6, 0x92D2, 0x98FD, 0x9CF3, 0x9D6C, 0x4E4F,
- 0x4EA1, 0x508D, 0x5256, 0x574A, 0x59A8, 0x5E3D, 0x5FD8, 0x5FD9,
- 0x623F, 0x66B4, 0x671B, 0x67D0, 0x68D2, 0x5192, 0x7D21, 0x80AA,
- 0x81A8, 0x8B00, 0x8C8C, 0x8CBF, 0x927E, 0x9632, 0x5420, 0x982C,
- 0x5317, 0x50D5, 0x535C, 0x58A8, 0x64B2, 0x6734, 0x7267, 0x7766,
- 0x7A46, 0x91E6, 0x52C3, 0x6CA1, 0x6B86, 0x5800, 0x5E4C, 0x5954,
- 0x672C, 0x7FFB, 0x51E1, 0x76C6, 0x6469, 0x78E8, 0x9B54, 0x9EBB,
- 0x57CB, 0x59B9, 0x6627, 0x679A, 0x6BCE, 0x54E9, 0x69D9, 0x5E55,
- 0x819C, 0x6795, 0x9BAA, 0x67FE, 0x9C52, 0x685D, 0x4EA6, 0x4FE3,
- 0x53C8, 0x62B9, 0x672B, 0x6CAB, 0x8FC4, 0x4FAD, 0x7E6D, 0x9EBF,
- 0x4E07, 0x6162, 0x6E80, 0x6F2B, 0x8513, 0x5473, 0x672A, 0x9B45,
- 0x5DF3, 0x7B95, 0x5CAC, 0x5BC6, 0x871C, 0x6E4A, 0x84D1, 0x7A14,
- 0x8108, 0x5999, 0x7C8D, 0x6C11, 0x7720, 0x52D9, 0x5922, 0x7121,
- 0x725F, 0x77DB, 0x9727, 0x9D61, 0x690B, 0x5A7F, 0x5A18, 0x51A5,
- 0x540D, 0x547D, 0x660E, 0x76DF, 0x8FF7, 0x9298, 0x9CF4, 0x59EA,
- 0x725D, 0x6EC5, 0x514D, 0x68C9, 0x7DBF, 0x7DEC, 0x9762, 0x9EBA,
- 0x6478, 0x6A21, 0x8302, 0x5984, 0x5B5F, 0x6BDB, 0x731B, 0x76F2,
- 0x7DB2, 0x8017, 0x8499, 0x5132, 0x6728, 0x9ED9, 0x76EE, 0x6762,
- 0x52FF, 0x9905, 0x5C24, 0x623B, 0x7C7E, 0x8CB0, 0x554F, 0x60B6,
- 0x7D0B, 0x9580, 0x5301, 0x4E5F, 0x51B6, 0x591C, 0x723A, 0x8036,
- 0x91CE, 0x5F25, 0x77E2, 0x5384, 0x5F79, 0x7D04, 0x85AC, 0x8A33,
- 0x8E8D, 0x9756, 0x67F3, 0x85AE, 0x9453, 0x6109, 0x6108, 0x6CB9,
- 0x7652, 0x8AED, 0x8F38, 0x552F, 0x4F51, 0x512A, 0x52C7, 0x53CB,
- 0x5BA5, 0x5E7D, 0x60A0, 0x6182, 0x63D6, 0x6709, 0x67DA, 0x6E67,
- 0x6D8C, 0x7336, 0x7337, 0x7531, 0x7950, 0x88D5, 0x8A98, 0x904A,
- 0x9091, 0x90F5, 0x96C4, 0x878D, 0x5915, 0x4E88, 0x4F59, 0x4E0E,
- 0x8A89, 0x8F3F, 0x9810, 0x50AD, 0x5E7C, 0x5996, 0x5BB9, 0x5EB8,
- 0x63DA, 0x63FA, 0x64C1, 0x66DC, 0x694A, 0x69D8, 0x6D0B, 0x6EB6,
- 0x7194, 0x7528, 0x7AAF, 0x7F8A, 0x8000, 0x8449, 0x84C9, 0x8981,
- 0x8B21, 0x8E0A, 0x9065, 0x967D, 0x990A, 0x617E, 0x6291, 0x6B32,
- 0x6C83, 0x6D74, 0x7FCC, 0x7FFC, 0x6DC0, 0x7F85, 0x87BA, 0x88F8,
- 0x6765, 0x83B1, 0x983C, 0x96F7, 0x6D1B, 0x7D61, 0x843D, 0x916A,
- 0x4E71, 0x5375, 0x5D50, 0x6B04, 0x6FEB, 0x85CD, 0x862D, 0x89A7,
- 0x5229, 0x540F, 0x5C65, 0x674E, 0x68A8, 0x7406, 0x7483, 0x75E2,
- 0x88CF, 0x88E1, 0x91CC, 0x96E2, 0x9678, 0x5F8B, 0x7387, 0x7ACB,
- 0x844E, 0x63A0, 0x7565, 0x5289, 0x6D41, 0x6E9C, 0x7409, 0x7559,
- 0x786B, 0x7C92, 0x9686, 0x7ADC, 0x9F8D, 0x4FB6, 0x616E, 0x65C5,
- 0x865C, 0x4E86, 0x4EAE, 0x50DA, 0x4E21, 0x51CC, 0x5BEE, 0x6599,
- 0x6881, 0x6DBC, 0x731F, 0x7642, 0x77AD, 0x7A1C, 0x7CE7, 0x826F,
- 0x8AD2, 0x907C, 0x91CF, 0x9675, 0x9818, 0x529B, 0x7DD1, 0x502B,
- 0x5398, 0x6797, 0x6DCB, 0x71D0, 0x7433, 0x81E8, 0x8F2A, 0x96A3,
- 0x9C57, 0x9E9F, 0x7460, 0x5841, 0x6D99, 0x7D2F, 0x985E, 0x4EE4,
- 0x4F36, 0x4F8B, 0x51B7, 0x52B1, 0x5DBA, 0x601C, 0x73B2, 0x793C,
- 0x82D3, 0x9234, 0x96B7, 0x96F6, 0x970A, 0x9E97, 0x9F62, 0x66A6,
- 0x6B74, 0x5217, 0x52A3, 0x70C8, 0x88C2, 0x5EC9, 0x604B, 0x6190,
- 0x6F23, 0x7149, 0x7C3E, 0x7DF4, 0x806F, 0x84EE, 0x9023, 0x932C,
- 0x5442, 0x9B6F, 0x6AD3, 0x7089, 0x8CC2, 0x8DEF, 0x9732, 0x52B4,
- 0x5A41, 0x5ECA, 0x5F04, 0x6717, 0x697C, 0x6994, 0x6D6A, 0x6F0F,
- 0x7262, 0x72FC, 0x7BED, 0x8001, 0x807E, 0x874B, 0x90CE, 0x516D,
- 0x9E93, 0x7984, 0x808B, 0x9332, 0x8AD6, 0x502D, 0x548C, 0x8A71,
- 0x6B6A, 0x8CC4, 0x8107, 0x60D1, 0x67A0, 0x9DF2, 0x4E99, 0x4E98,
- 0x9C10, 0x8A6B, 0x85C1, 0x8568, 0x6900, 0x6E7E, 0x7897, 0x8155,
- // Padding to ensure size is 4-byte aligned
- 0, 0, 0,
- };
- // Font conversion error
- class font_error : public std::runtime_error
- {
- public:
- explicit font_error(const char* msg) : std::runtime_error(msg) {}
- };
- // Error decompressing a yay0 file
- class yay0_error : public std::runtime_error
- {
- public:
- explicit yay0_error(const char* msg) : std::runtime_error(msg) {}
- };
- // Class which writes bits to the mask vector
- class mask_vector_writer
- {
- public:
- void push_back(bool bit)
- {
- // Increase array size if needed
- if (_next_offset < 0)
- {
- _data.push_back(0);
- _next_offset = 7;
- }
- // Insert bit
- _data.back() |= (bit << _next_offset);
- _next_offset--;
- }
- const std::vector<uint8_t>& data() const
- {
- return _data;
- }
- private:
- std::vector<uint8_t> _data;
- int8_t _next_offset = -1;
- };
- // Class which reads bits from the mask vector
- class mask_vector_reader
- {
- public:
- mask_vector_reader(const std::vector<uint8_t>& input, size_t offset)
- :_input(input), _offset(offset)
- {
- }
- bool pop_front()
- {
- // Read next byte if needed
- if (_next_bit == 8)
- {
- _next_bit = 0;
- _offset++;
- }
- bool value = (_input.at(_offset) << _next_bit) & 0x80;
- _next_bit++;
- return value;
- }
- private:
- const std::vector<uint8_t>& _input;
- size_t _offset;
- uint8_t _next_bit = 0;
- };
- // Simple image container containing height and width
- template <int height_scale>
- class image_generic
- {
- public:
- std::vector<uint8_t> data;
- unsigned width;
- image_generic() = default;
- image_generic(const std::vector<uint8_t>& idata, unsigned iwidth)
- :data(idata), width(iwidth)
- {
- }
- unsigned height() const
- {
- return height_scale * data.size() / width;
- }
- };
- typedef image_generic<1> image8;
- typedef image_generic<4> image2;
- // Wraps a freetype library object + destroys it when done
- class ft_library_wrapper
- {
- public:
- ft_library_wrapper()
- {
- if (FT_Init_FreeType(&_library) != 0)
- throw font_error("error initializing freetype");
- }
- ft_library_wrapper(const ft_library_wrapper&) = delete;
- ft_library_wrapper operator=(const ft_library_wrapper&) = delete;
- ~ft_library_wrapper()
- {
- FT_Done_FreeType(_library);
- }
- operator FT_Library()
- {
- return _library;
- }
- private:
- FT_Library _library;
- };
- // Reads a 16 bit big endian value from a vector
- static uint16_t read_be16(const std::vector<uint8_t>& input, size_t offset)
- {
- return input.at(offset) << 8 |
- input.at(offset + 1);
- }
- // Reads a 32 bit big endian value from a vector
- static uint32_t read_be32(const std::vector<uint8_t>& input, size_t offset)
- {
- return read_be16(input, offset) << 16 |
- read_be16(input, offset + 2);
- }
- // Writes a 16 bit big endian value to a vector
- static void write_be16(std::vector<uint8_t>& output, uint16_t value)
- {
- output.push_back(static_cast<uint8_t>(value >> 8));
- output.push_back(static_cast<uint8_t>(value));
- }
- // Writes a 32 bit big endian value to a vector
- static void write_be32(std::vector<uint8_t>& output, uint32_t value)
- {
- write_be16(output, static_cast<uint16_t>(value >> 16));
- write_be16(output, static_cast<uint16_t>(value));
- }
- // Writes a 16 bit little endian value to a vector
- static void write_le16(std::vector<uint8_t>& output, uint16_t value)
- {
- output.push_back(static_cast<uint8_t>(value));
- output.push_back(static_cast<uint8_t>(value >> 8));
- }
- // Writes a 16 bit little endian value to a vector
- static void write_le32(std::vector<uint8_t>& output, uint32_t value)
- {
- write_le16(output, static_cast<uint16_t>(value));
- write_le16(output, static_cast<uint16_t>(value >> 16));
- }
- // Clamps an integer between two values
- static int clamp(int value, int min, int max)
- {
- if (value < min)
- value = min;
- else if (value > max)
- value = max;
- return value;
- }
- // Compresses a file using the Yay0 format
- static std::vector<uint8_t> yay0_compress(const std::vector<uint8_t>& input)
- {
- const uint16_t MAX_LINK_LEN = 255 + 18;
- size_t input_pos = 0;
- mask_vector_writer masks;
- std::vector<uint8_t> links;
- std::vector<uint8_t> chunks;
- // Start the main loop to generate a single link or chunk
- while (input_pos < input.size())
- {
- uint16_t link_count = 0;
- uint16_t link_offset;
- // Search the previous 4K for the largest series of bytes to use as a link
- for (uint16_t offset = 1; offset <= 0x1000 && offset <= input_pos; offset++)
- {
- uint16_t count = 0;
- bool max_count_reached = false;
- while (input[input_pos - offset + count] == input[input_pos + count])
- {
- count++;
- // Limit the number of characters
- if (count > MAX_LINK_LEN || input_pos + count >= input.size())
- {
- max_count_reached = true;
- break;
- }
- }
- // Handle max link lengths
- if (max_count_reached)
- {
- link_count = count - 1;
- link_offset = offset;
- break;
- }
- // Update best link
- if (count > link_count)
- {
- link_count = count;
- link_offset = offset;
- }
- }
- // Write link or chunk to relevant list
- if (link_count >= 3)
- {
- uint16_t link_count_header = 0;
- if (link_count >= 18)
- chunks.push_back(link_count - 18);
- else
- link_count_header = link_count - 2;
- write_be16(links, link_count_header << 12 | (link_offset - 1));
- masks.push_back(false);
- input_pos += link_count;
- }
- else
- {
- chunks.push_back(input[input_pos]);
- masks.push_back(true);
- input_pos++;
- }
- }
- // Return final array
- std::vector<uint8_t> result = { 'Y', 'a', 'y', '0' };
- write_be32(result, input.size());
- write_be32(result, 16 + masks.data().size());
- write_be32(result, 16 + masks.data().size() + links.size());
- result.insert(result.end(), masks.data().begin(), masks.data().end());
- result.insert(result.end(), links.begin(), links.end());
- result.insert(result.end(), chunks.begin(), chunks.end());
- return result;
- }
- // Decompresses a file using the Yay0 format
- static std::vector<uint8_t> yay0_decompress(const std::vector<uint8_t>& input)
- {
- std::vector<uint8_t> result;
- try
- {
- // Validate header
- if (input.at(0) != 'Y' || input.at(1) != 'a' ||
- input.at(2) != 'y' || input.at(3) != '0')
- {
- throw yay0_error("yay0: not a yay0 file");
- }
- // Extract header information
- uint32_t final_size = read_be32(input, 4);
- uint32_t links_offset = read_be32(input, 8);
- uint32_t chunks_offset = read_be32(input, 12);
- mask_vector_reader masks(input, 16);
- result.reserve(final_size);
- while (result.size() < final_size)
- {
- // Link or a chunk?
- if (masks.pop_front())
- {
- // Write chunk to output
- result.push_back(input.at(chunks_offset));
- chunks_offset++;
- }
- else
- {
- // Examine link contents
- uint16_t link = read_be16(input, links_offset);
- links_offset += 2;
- int count = (link >> 12) + 2;
- if (count == 2)
- {
- // Read count from chunks list
- count = input.at(chunks_offset) + 18;
- chunks_offset++;
- }
- // Replay the link
- unsigned offset = ((link & 0xFFF) + 1);
- if (offset > result.size())
- throw yay0_error("yay0: invalid yay0 file");
- for (int i = 0; i < count; i++)
- result.push_back(result.at(result.size() - offset));
- }
- }
- return result;
- }
- catch (std::out_of_range)
- {
- // Invalid offset somewhere
- throw yay0_error("yay0: invalid yay0 file");
- }
- }
- // Encodes an 8 bit greyscale bitmap as an i2 font image
- static image2 i2encode(const image8& image)
- {
- image2 out;
- const std::vector<uint8_t>& data = image.data;
- unsigned width = image.width;
- // Blocks are 8x8 pixels
- // Each row is 2 bytes wide, 16 bytes per block
- unsigned width_blocks = width / 8;
- unsigned height_blocks = data.size() / (width_blocks * 64);
- out.data.resize(height_blocks * width_blocks * 16);
- out.width = width_blocks * 8;
- // Process each row of blocks, and then each block in the row
- for (unsigned block_row = 0; block_row < height_blocks; block_row++)
- {
- for (unsigned block = 0; block < width_blocks; block++)
- {
- for (unsigned row = 0; row < 8; row++)
- {
- // Move pixel data to the right place and shrink 8-bit data to 2-bit
- unsigned src_row_offset = (block_row * width_blocks * 64) +
- (block * 8) + (row * width_blocks * 8);
- unsigned dst_row_offset = (block_row * width_blocks * 16) +
- (block * 16) + (row * 2);
- out.data[dst_row_offset ] =
- (data[src_row_offset ] & 0xC0) |
- (data[src_row_offset + 1] >> 2 & 0x30) |
- (data[src_row_offset + 2] >> 4 & 0x0C) |
- (data[src_row_offset + 3] >> 6 );
- out.data[dst_row_offset + 1] =
- (data[src_row_offset + 4] & 0xC0) |
- (data[src_row_offset + 5] >> 2 & 0x30) |
- (data[src_row_offset + 6] >> 4 & 0x0C) |
- (data[src_row_offset + 7] >> 6 );
- }
- }
- }
- return out;
- }
- // Decodes an i2 image into a normal 8-bit greyscale bitmap
- static image8 i2decode(const image2& image)
- {
- image8 out;
- const std::vector<uint8_t>& data = image.data;
- unsigned width = image.width;
- // Blocks are 8x8 pixels
- // Each row is 2 bytes wide, 16 bytes per block
- unsigned width_blocks = (width + 7) / 8;
- unsigned height_blocks = data.size() / (width_blocks * 16);
- out.data.resize(height_blocks * width_blocks * 64);
- out.width = width_blocks * 8;
- // Process each row of blocks, and then each block in the row
- for (unsigned block_row = 0; block_row < height_blocks; block_row++)
- {
- for (unsigned block = 0; block < width_blocks; block++)
- {
- for (unsigned row = 0; row < 8; row++)
- {
- // Move pixel data to the right place and expand 2-bit data to 8-bit
- unsigned src_row_offset = (block_row * width_blocks * 16) +
- (block * 16) + (row * 2);
- unsigned dst_row_offset = (block_row * width_blocks * 64) +
- (block * 8) + (row * width_blocks * 8);
- uint8_t src1 = data[src_row_offset];
- uint8_t src2 = data[src_row_offset + 1];
- out.data[dst_row_offset ] = (src1 >> 6 ) * 0x55;
- out.data[dst_row_offset + 1] = (src1 >> 4 & 0x03) * 0x55;
- out.data[dst_row_offset + 2] = (src1 >> 2 & 0x03) * 0x55;
- out.data[dst_row_offset + 3] = (src1 & 0x03) * 0x55;
- out.data[dst_row_offset + 4] = (src2 >> 6 ) * 0x55;
- out.data[dst_row_offset + 5] = (src2 >> 4 & 0x03) * 0x55;
- out.data[dst_row_offset + 6] = (src2 >> 2 & 0x03) * 0x55;
- out.data[dst_row_offset + 7] = (src2 & 0x03) * 0x55;
- }
- }
- }
- return out;
- }
- // Adds an error to the given pixel while clamping it
- static void dither_add_clamp(uint8_t& pixel, int error)
- {
- if (pixel + error < 0)
- pixel = 0;
- else if (pixel + error > 255)
- pixel = 255;
- else
- pixel += error;
- }
- // Dithers the given image (in-place) using the Floyd–Steinberg dithering algorithm
- static void dither_4colour(image8& image)
- {
- const unsigned height = image.height();
- for (unsigned y = 0; y < height; y++)
- {
- for (unsigned x = 0; x < image.width; x++)
- {
- uint8_t old_pixel = image.data[y * image.width + x];
- uint8_t new_pixel = old_pixel & 0xC0;
- int error = old_pixel - new_pixel;
- // Store new pixel value + distribute error to surrounding pixels
- image.data[y * image.width + x] = new_pixel;
- if (x + 1 < image.width)
- dither_add_clamp(image.data[y * image.width + x + 1], error * 7 / 16);
- if (y + 1 < height)
- {
- dither_add_clamp(image.data[(y + 1) * image.width + x], error * 5 / 16);
- if (x > 0)
- dither_add_clamp(image.data[(y + 1) * image.width + x - 1], error * 3 / 16);
- if (x + 1 < image.width)
- dither_add_clamp(image.data[(y + 1) * image.width + x + 1], error / 16);
- }
- }
- }
- }
- // Creates the bmp header from an image
- static std::vector<uint8_t> generate_bmp_header(const image8& img)
- {
- const unsigned HEADER_SIZE = 14 + 40 + (4 * 256);
- std::vector<uint8_t> result;
- // BMP Header
- result.push_back('B');
- result.push_back('M');
- write_le32(result, HEADER_SIZE + img.data.size());
- write_le32(result, 0);
- write_le32(result, HEADER_SIZE);
- // DIB Header
- write_le32(result, 40); // Size of header
- write_le32(result, img.width); // Image width
- write_le32(result, ~img.height() + 1); // Image height (stored negative)
- write_le16(result, 1); // Image planes
- write_le16(result, 8); // Bits per pixel
- write_le32(result, 0); // Compression type
- write_le32(result, 0); // Size of image in bytes
- write_le32(result, 0); // X Pixels per metre
- write_le32(result, 0); // Y Pixels per metre
- write_le32(result, 0); // Colour table size
- write_le32(result, 0); // Colour table required
- // Colour table (RGBA)
- for (unsigned i = 0; i < 256; i++)
- write_be32(result, 0x01010100 * i);
- return result;
- }
- // Converts a Yay0 font to a bitmap
- static std::vector<uint8_t> fnt_to_bmp(const std::vector<uint8_t>& input)
- {
- std::vector<uint8_t> uncompressed_fnt = yay0_decompress(input);
- // Descramble image
- uint32_t start = read_be32(uncompressed_fnt, 0x24);
- image2 i2data;
- i2data.width = read_be16(uncompressed_fnt, 0x1E);
- i2data.data.assign(uncompressed_fnt.begin() + start, uncompressed_fnt.end());
- image8 dest = i2decode(i2data);
- // Write bitmap out
- std::vector<uint8_t> bitmap = generate_bmp_header(dest);
- bitmap.insert(bitmap.end(), dest.data.begin(), dest.data.end());
- return bitmap;
- }
- // Generates a GameCube font file
- static std::vector<uint8_t> generate_fnt(
- font_type type,
- const std::vector<uint8_t>& widths,
- const image2& pixmap)
- {
- std::vector<uint8_t> out;
- write_be16(out, type == font_type::windows_1252 ? 0 : 2);
- write_be16(out, type == font_type::windows_1252 ? 0x0020 : 0x8140);
- write_be16(out, type == font_type::windows_1252 ? 0x00FF : 0x9872);
- write_be16(out, 0x20);
- write_be16(out, FNT_CELL_SIZE);
- write_be16(out, 0x00);
- write_be16(out, FNT_CELL_SIZE);
- write_be16(out, FNT_CELL_SIZE * 7 / 6);
- write_be16(out, FNT_CELL_SIZE);
- write_be16(out, FNT_CELL_SIZE);
- write_be32(out, FNT_PIXMAP_WIDTH * FNT_PIXMAP_WIDTH / 2);
- write_be16(out, 0x00);
- write_be16(out, FNT_CELLS_PER_ROW);
- write_be16(out, FNT_CELLS_PER_ROW);
- write_be16(out, FNT_PIXMAP_WIDTH);
- write_be16(out, FNT_PIXMAP_WIDTH);
- write_be16(out, 0x30);
- write_be32(out, 0x30 + widths.size());
- write_be32(out, 2 * pixmap.data.size());
- write_be32(out, 0x0055AAFF);
- out.insert(out.end(), widths.begin(), widths.end());
- out.insert(out.end(), pixmap.data.begin(), pixmap.data.end());
- return out;
- }
- // Generates the font data arrays from a freetype font
- // font_buf = input font data
- // font_table = list of unicode codepoints appearing in the font
- // font_table_size = number of characters in font_table
- // out_widths = output vector to store advance widths of each character
- // out_pixmap = output vector to store pixmap (unscrambled)
- static void freetype_to_fnt_data(
- const std::vector<uint8_t>& font_buf,
- const uint16_t* font_table,
- unsigned font_table_size,
- std::vector<uint8_t>& out_widths,
- image8& out_pixmap)
- {
- // Initialize freetype
- ft_library_wrapper library;
- // Initialize fontface
- FT_Face face;
- if (FT_New_Memory_Face(library, font_buf.data(), font_buf.size(), 0, &face) != 0)
- throw font_error("error reading font data");
- // Set size to render glyphs at
- if (FT_Set_Pixel_Sizes(face, 0, FNT_RENDER_SIZE) != 0)
- throw font_error("error selecting font size (is the font scalable?)");
- // Get descender size in pixels (negative value)
- const int descender = face->size->metrics.descender >> 6;
- // Resize output vectors
- const unsigned cpr_squared = FNT_CELLS_PER_ROW * FNT_CELLS_PER_ROW;
- const unsigned pages = (font_table_size + cpr_squared - 1) / cpr_squared;
- out_widths.clear();
- out_widths.resize(font_table_size);
- out_pixmap.data.clear();
- out_pixmap.data.resize(FNT_PIXMAP_WIDTH * FNT_PIXMAP_WIDTH * pages);
- out_pixmap.width = FNT_PIXMAP_WIDTH;
- // Render each glyph in the list
- for (unsigned i = 0; i < font_table_size; i++)
- {
- unsigned glyph_index = FT_Get_Char_Index(face, font_table[i]);
- // Skip undefined characters
- if (glyph_index == 0)
- continue;
- // Load glyph data
- if (FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER) != 0)
- throw font_error("error loading glyph");
- // Record width
- out_widths[i] = clamp(face->glyph->metrics.horiAdvance >> 6, 0, FNT_CELL_SIZE);
- // Calculate cell offset within final image
- const unsigned cell_page = i / cpr_squared;
- const unsigned cell_y = (i % cpr_squared) / FNT_CELLS_PER_ROW;
- const unsigned cell_x = (i % cpr_squared) % FNT_CELLS_PER_ROW;
- const int cell_offset =
- cell_page * FNT_PIXMAP_WIDTH * FNT_PIXMAP_WIDTH +
- cell_y * FNT_PIXMAP_WIDTH * FNT_CELL_SIZE +
- cell_x * FNT_CELL_SIZE;
- // Copy glyph image
- const FT_Bitmap* bitmap = &face->glyph->bitmap;
- const int xStart = face->glyph->bitmap_left;
- const int yStart = FNT_CELL_SIZE + descender - face->glyph->bitmap_top;
- const int xMax = xStart + bitmap->width;
- const int yMax = yStart + bitmap->rows;
- for (int y = yStart; y < yMax; y++)
- {
- for (int x = xStart; x < xMax; x++)
- {
- // Clip pixels outsize the cell
- if (y < 0 || x < 0 || x >= FNT_CELL_SIZE || y >= FNT_CELL_SIZE)
- continue;
- // Copy pixel
- int srcOff = (y - yStart) * bitmap->width + (x - xStart);
- int dstOff = cell_offset + y * FNT_PIXMAP_WIDTH + x;
- out_pixmap.data[dstOff] = bitmap->buffer[srcOff];
- }
- }
- }
- }
- // Converts a freetype font to a GameCube compressed font
- static std::vector<uint8_t> freetype_to_fnt(const std::vector<uint8_t>& font_buf, font_type type, bool dither)
- {
- // Get font table from font type
- const uint16_t* font_table;
- unsigned font_table_size;
- if (type == font_type::windows_1252)
- {
- font_table = windows_1252_font_table;
- font_table_size = sizeof(windows_1252_font_table) / 2;
- }
- else
- {
- font_table = shift_jis_font_table;
- font_table_size = sizeof(shift_jis_font_table) / 2;
- }
- // Generate pixmap
- std::vector<uint8_t> widths;
- image8 pixmap;
- freetype_to_fnt_data(font_buf, font_table, font_table_size, widths, pixmap);
- // Dither image
- if (dither)
- dither_4colour(pixmap);
- // Scramble pixmap, generate fnt header and compress
- return yay0_compress(generate_fnt(type, widths, i2encode(pixmap)));
- }
- static void usage()
- {
- std::cerr << "GameCube font tool" << std::endl;
- std::cerr << std::endl;
- std::cerr << "gc-font-tool <mode> <input> <output>" << std::endl;
- std::cerr << " c = compress using yay0" << std::endl;
- std::cerr << " d = decompress a yay0 file" << std::endl;
- std::cerr << " a = generate a windows-1252 gamecube font file from a true type font" << std::endl;
- std::cerr << " s = generate a shift jis gamecube font file from a true type font" << std::endl;
- std::cerr << " b = like a, but do not dither the final image" << std::endl;
- std::cerr << " t = like s, but do not dither the final image" << std::endl;
- std::cerr << " v = generate a bitmap showing the contents of a gamecube font file" << std::endl;
- std::cerr << " input and output may be files or - for stdin/stdout" << std::endl;
- }
- // Reads an entire file into a vector
- static std::vector<uint8_t> read_file(const std::string& filename)
- {
- std::ifstream in_file;
- std::istream* input;
- // Open stream
- if (filename == "-")
- {
- std::cin.exceptions(std::ios::failbit);
- input = &std::cin;
- }
- else
- {
- in_file.exceptions(std::ios::failbit);
- in_file.open(filename, std::ios::in | std::ios::binary);
- input = &in_file;
- }
- return std::vector<uint8_t>(std::istreambuf_iterator<char>(*input),
- std::istreambuf_iterator<char>());
- }
- // Writes a byte vector to a file
- static void write_file(const std::string& filename, const std::vector<uint8_t> data)
- {
- std::ofstream out_file;
- std::ostream* output;
- // Open stream
- if (filename == "-")
- {
- std::cout.exceptions(std::ios::failbit);
- output = &std::cout;
- }
- else
- {
- out_file.exceptions(std::ios::failbit);
- out_file.open(filename, std::ios::out | std::ios::binary);
- output = &out_file;
- }
- std::copy(data.begin(), data.end(),
- std::ostreambuf_iterator<char>(*output));
- }
- int main(int argc, char* argv[])
- {
- // Get arguments
- if (argc != 4)
- {
- usage();
- return 1;
- }
- try
- {
- // Read input file
- std::vector<uint8_t> input = read_file(argv[2]);
- // Do operation
- const std::string mode = argv[1];
- char mode_char = 0;
- if (mode.length() == 2 && mode[0] == '-')
- mode_char = mode[1];
- else if (mode.length() == 1)
- mode_char = mode[0];
- std::vector<uint8_t> result;
- switch (mode_char)
- {
- case 'c': result = yay0_compress(input); break;
- case 'd': result = yay0_decompress(input); break;
- case 'a': result = freetype_to_fnt(input, font_type::windows_1252, true); break;
- case 's': result = freetype_to_fnt(input, font_type::shift_jis, true); break;
- case 'b': result = freetype_to_fnt(input, font_type::windows_1252, false); break;
- case 't': result = freetype_to_fnt(input, font_type::shift_jis, false); break;
- case 'v': result = fnt_to_bmp(input); break;
- default:
- usage();
- return 1;
- }
- // Write output file
- write_file(argv[3], result);
- return 0;
- }
- catch (const std::ios_base::failure& e)
- {
- std::cerr << "gc-font-tool: io error: " << std::strerror(errno) << std::endl;
- return 1;
- }
- catch (const std::runtime_error& e)
- {
- std::cerr << "gc-font-tool: " << e.what() << std::endl;
- return 1;
- }
- }
|