+#include "msdos.h"
+
+static const unsigned char cvt[] = {
+
+ 0x80, 0x9A, 0x45, 0x41, 0x8E, 0x41, 0x8F,
+ 0x80, 0x45, 0x45, 0x45, 0x49, 0x49, 0x49,
+ 0x8E, 0x8F, 0x90, 0x92, 0x92, 0x4F, 0x99,
+ 0x4F, 0x55, 0x55, 0x59, 0x99, 0x9A, 0x9B,
+ 0x9C, 0x9D, 0x9E, 0x9F, 0x41, 0x49, 0x4F,
+ 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
+ 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,
+ 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
+ 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
+ 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5,
+ 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC,
+ 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3,
+ 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
+ 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1,
+ 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8,
+ 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF,
+ 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6,
+ 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD,
+ 0xFE, 0xFF
+
+};
+
+static const unsigned short uc437[] = { /* CP437(U.S.) to Unicode conversion table */
+
+ 0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4,
+ 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB,
+ 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4,
+ 0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4,
+ 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF,
+ 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5,
+ 0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3,
+ 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
+ 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC,
+ 0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592,
+ 0x2593, 0x2502, 0x2524, 0x2561, 0x2562,
+ 0x2556, 0x2555, 0x2563, 0x2551, 0x2557,
+ 0x255D, 0x255C, 0x255B, 0x2510, 0x2514,
+ 0x2534, 0x252C, 0x251C, 0x2500, 0x253C,
+ 0x255E, 0x255F, 0x255A, 0x2554, 0x2569,
+ 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
+ 0x2568, 0x2564, 0x2565, 0x2559, 0x2558,
+ 0x2552, 0x2553, 0x256B, 0x256A, 0x2518,
+ 0x250C, 0x2588, 0x2584, 0x258C, 0x2590,
+ 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0,
+ 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6,
+ 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6,
+ 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265,
+ 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
+ 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F,
+ 0x00B2, 0x25A0, 0x00A0
+
+};
+
+static unsigned short uni2oem (unsigned int uni, short cp) {
+
+ const unsigned short *p = uc437;
+ unsigned short c = 0;
+
+ if (uni < 0x80) {
+ c = (unsigned short) uni;
+ } else {
+
+ (void) cp;
+
+ if (uni < 0x10000) {
+
+ for (c = 0; c < 0x80 && uni != p[c]; c++) {
+ ;
+ }
+
+ c = (c + 0x80) & 0xff;
+
+ }
+
+ }
+
+ return c;
+
+}
+
+static unsigned short oem2uni (unsigned short oem, short cp) {
+
+ const unsigned short *p = uc437;
+ unsigned short c = 0;
+
+ if (oem < 0x80) {
+ c = oem;
+ } else {
+
+ (void) cp;
+
+ if (oem < 0x100) {
+ c = p[oem - 0x80];
+ }
+
+ }
+
+ return c;
+
+}
+
+static unsigned int tchar2uni (const char **str) {
+
+ const char *p = *str;
+ unsigned int uc;
+
+ unsigned short wc = (unsigned char) *p++;
+
+ if (wc != 0) {
+
+ if ((wc = oem2uni (wc, 437)) == 0) {
+ return 0xffffffff;
+ }
+
+ }
+
+ uc = wc;
+
+ *str = p;
+ return uc;
+
+};
+
+static int chk_chr (const char *str, int chr) {
+
+ while (*str && *str != chr) {
+ str++;
+ }
+
+ return *str;
+
+}
+
+int create_name (struct fat_dirent *dp, const char *path) {
+
+ unsigned char b, cf;
+ unsigned short wc;
+
+ const char *p = path;
+ unsigned int di = 0, uc, i, ni, si;
+
+ for (;;) {
+
+ uc = tchar2uni (&p);
+
+ if (uc == 0xffffffff) {
+ return -1;
+ }
+
+ if (uc >= 0x10000) {
+ dp->lfn[di++] = (unsigned short) (uc >> 16);
+ }
+
+ wc = (unsigned short) uc;
+
+ if (wc < ' ' || wc == '/' || wc == '\\') {
+ break;
+ }
+
+ if (wc < 0x80 && chk_chr ("\"*:<>\?|\x7F", wc)) {
+ return -1;
+ }
+
+ if (di >= LFN_MAX) {
+ return -1;
+ }
+
+ dp->lfn[di++] = wc;
+
+ }
+
+ while (*p == '/' || *p == '\\') {
+ p++;
+ }
+
+ cf = (wc < ' ') ? 4 : 0;
+
+ while (di) {
+
+ wc = dp->lfn[di - 1];
+
+ if (wc != ' ' && wc != '.') {
+ break;
+ }
+
+ di--;
+
+ }
+
+ dp->lfn[di] = 0;
+
+ if (di == 0) {
+ return -1;
+ }
+
+ for (si = 0; dp->lfn[si] == ' '; si++) {
+ ;
+ }
+
+ if (si > 0 || dp->lfn[si] == '.') {
+ cf |= 3;
+ }
+
+ while (di > 0 && dp->lfn[di - 1] != '.') {
+ di--;
+ }
+
+ memset (dp->fn, ' ', 11);
+ i = b = 0; ni = 8;
+
+ for (;;) {
+
+ wc = dp->lfn[si++];
+
+ if (wc == 0) {
+ break;
+ }
+
+ if (wc == ' ' || (wc == '.' && si != di)) {
+
+ cf |= 3;
+ continue;
+
+ }
+
+ if (i >= ni || si == di) {
+
+ if (ni == 11) {
+
+ cf |= 3;
+ break;
+
+ }
+
+ if (si != di) {
+ cf |= 3;
+ }
+
+ if (si > di) {
+ break;
+ }
+
+ si = di;
+
+ i = 8;
+ ni = 11;
+
+ b <<= 2;
+ continue;
+
+ }
+
+ if (wc >= 0x80) {
+
+ cf |= 2;
+
+ if ((wc = uni2oem (wc, 437)) & 0x80) {
+ wc = cvt[wc & 0x7f];
+ }
+
+ }
+
+ if (wc >= 0x100) {
+
+ if (i >= ni - 1) {
+
+ cf |= 3;
+
+ i = ni;
+ continue;
+
+ }
+
+ dp->fn[i++] = (unsigned char) (wc >> 8);
+
+ } else {
+
+ if (wc == 0 || chk_chr ("+,;=[]", wc)) {
+ wc = '_'; cf |= 3;
+ } else {
+
+ if (isupper ((int) wc)) {
+ b |= 2;
+ }
+
+ if (islower ((int) wc)) {
+ b |= 1; wc -= 0x20;
+ }
+
+ }
+
+ }
+
+ dp->fn[i++] = (unsigned char) wc;
+
+ }
+
+ if (dp->fn[0] == 0xe5) {
+ dp->fn[0] = 0x05;
+ }
+
+ if (ni == 8) {
+ b <<= 2;
+ }
+
+ if ((b & 0x0c) == 0x0c || (b & 0x03) == 0x03) {
+ cf |= 2;
+ }
+
+ if (!(cf & 2)) {
+
+ if (b & 0x01) {
+ cf |= 0x10;
+ }
+
+ if (b & 0x04) {
+ cf |= 0x08;
+ }
+
+ }
+
+ dp->fn[11] = cf;
+ return 0;
+
+}
+
+void gen_numname (unsigned char *dst, const unsigned char *src, const unsigned short *lfn, unsigned int seq) {
+
+ unsigned char ns[8], c;
+ unsigned int i, j;
+
+ unsigned short wc;
+ unsigned int sr;
+
+ memcpy (dst, src, 11);
+
+ if (seq > 5) {
+
+ sr = seq;
+
+ while (*lfn) {
+
+ wc = *lfn++;
+
+ for (i = 0; i < 16; i++) {
+
+ sr = (sr << 1) + (wc & 1);
+ wc >>= 1;
+
+ if (sr & 0x10000) {
+ sr ^= 0x11021;
+ }
+
+ }
+
+ }
+
+ seq = sr;
+
+ }
+
+ i = 7;
+
+ do {
+
+ c = ((seq % 16) + '0');
+
+ if (c > '9') {
+ c += 7;
+ }
+
+ ns[i--] = c;
+ seq /= 16;
+
+ } while (seq);
+
+ ns[i] = '~';
+
+ for (j = 0; j < i && dst[j] != ' '; j++) {
+
+ if (j == i - 1) {
+ break;
+ }
+
+ }
+
+ do {
+ dst[j++] = (i < 8) ? ns[i++] : ' ';
+ } while (j < 8);
+
+}
+
+
+static const unsigned char lfn_ofs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 };
+
+unsigned int wtoupper (unsigned int uni) {
+
+ static const unsigned short cvt1[] = { /* Compressed up conversion table for U+0000 - U+0FFF */
+
+ /* Basic Latin */
+ 0x0061, 0x031A,
+
+ /* Latin-1 Supplement */
+ 0x00E0, 0x0317, 0x00F8, 0x0307,
+ 0x00FF, 0x0001, 0x0178,
+
+ /* Latin Extended-A */
+ 0x0100, 0x0130, 0x0132, 0x0106,
+ 0x0139, 0x0110, 0x014A, 0x012E,
+ 0x0179, 0x0106,
+
+ /* Latin Extended-B */
+ 0x0180, 0x004D, 0x0243, 0x0181,
+ 0x0182, 0x0182, 0x0184, 0x0184,
+ 0x0186, 0x0187, 0x0187, 0x0189,
+ 0x018A, 0x018B, 0x018B, 0x018D,
+ 0x018E, 0x018F, 0x0190, 0x0191,
+ 0x0191, 0x0193, 0x0194, 0x01F6,
+ 0x0196, 0x0197, 0x0198, 0x0198,
+ 0x023D, 0x019B, 0x019C, 0x019D,
+ 0x0220, 0x019F, 0x01A0, 0x01A0,
+ 0x01A2, 0x01A2, 0x01A4, 0x01A4,
+ 0x01A6, 0x01A7, 0x01A7, 0x01A9,
+ 0x01AA, 0x01AB, 0x01AC, 0x01AC,
+ 0x01AE, 0x01AF, 0x01AF, 0x01B1,
+ 0x01B2, 0x01B3, 0x01B3, 0x01B5,
+ 0x01B5, 0x01B7, 0x01B8, 0x01B8,
+ 0x01BA, 0x01BB, 0x01BC, 0x01BC,
+ 0x01BE, 0x01F7, 0x01C0, 0x01C1,
+ 0x01C2, 0x01C3, 0x01C4, 0x01C5,
+ 0x01C4, 0x01C7, 0x01C8, 0x01C7,
+ 0x01CA, 0x01CB, 0x01CA, 0x01CD,
+ 0x0110, 0x01DD, 0x0001, 0x018E,
+ 0x01DE, 0x0112, 0x01F3, 0x0003,
+ 0x01F1, 0x01F4, 0x01F4, 0x01F8,
+ 0x0128, 0x0222, 0x0112, 0x023A,
+ 0x0009, 0x2C65, 0x023B, 0x023B,
+ 0x023D, 0x2C66, 0x023F, 0x0240,
+ 0x0241, 0x0241, 0x0246, 0x010A,
+
+ /* IPA Extensions */
+ 0x0253, 0x0040, 0x0181, 0x0186,
+ 0x0255, 0x0189, 0x018A, 0x0258,
+ 0x018F, 0x025A, 0x0190, 0x025C,
+ 0x025D, 0x025E, 0x025F, 0x0193,
+ 0x0261, 0x0262, 0x0194, 0x0264,
+ 0x0265, 0x0266, 0x0267, 0x0197,
+ 0x0196, 0x026A, 0x2C62, 0x026C,
+ 0x026D, 0x026E, 0x019C, 0x0270,
+ 0x0271, 0x019D, 0x0273, 0x0274,
+ 0x019F, 0x0276, 0x0277, 0x0278,
+ 0x0279, 0x027A, 0x027B, 0x027C,
+ 0x2C64, 0x027E, 0x027F, 0x01A6,
+ 0x0281, 0x0282, 0x01A9, 0x0284,
+ 0x0285, 0x0286, 0x0287, 0x01AE,
+ 0x0244, 0x01B1, 0x01B2, 0x0245,
+ 0x028D, 0x028E, 0x028F, 0x0290,
+ 0x0291, 0x01B7,
+
+ /* Greek, Coptic */
+ 0x037B, 0x0003, 0x03FD, 0x03FE,
+ 0x03FF, 0x03AC, 0x0004, 0x0386,
+ 0x0388, 0x0389, 0x038A, 0x03B1,
+ 0x0311, 0x03C2, 0x0002, 0x03A3,
+ 0x03A3, 0x03C4, 0x0308, 0x03CC,
+ 0x0003, 0x038C, 0x038E, 0x038F,
+ 0x03D8, 0x0118, 0x03F2, 0x000A,
+ 0x03F9, 0x03F3, 0x03F4, 0x03F5,
+ 0x03F6, 0x03F7, 0x03F7, 0x03F9,
+ 0x03FA, 0x03FA,
+
+ /* Cyrillic */
+ 0x0430, 0x0320, 0x0450, 0x0710,
+ 0x0460, 0x0122, 0x048A, 0x0136,
+ 0x04C1, 0x010E, 0x04CF, 0x0001,
+ 0x04C0, 0x04D0, 0x0144,
+
+ /* Armenian */
+ 0x0561, 0x0426,
+
+ /* EOT */
+ 0x0000
+
+ };
+
+ static const unsigned short cvt2[] = { /* Compressed up conversion table for U+1000 - U+FFFF */
+
+ /* Phonetic Extensions */
+ 0x1D7D, 0x0001, 0x2C63,
+
+ /* Latin Extended Additional */
+ 0x1E00, 0x0196,
+ 0x1EA0, 0x015A,
+
+ /* Greek Extended */
+ 0x1F00, 0x0608, 0x1F10, 0x0606,
+ 0x1F20, 0x0608, 0x1F30, 0x0608,
+ 0x1F40, 0x0606, 0x1F51, 0x0007,
+ 0x1F59, 0x1F52, 0x1F5B, 0x1F54,
+ 0x1F5D, 0x1F56, 0x1F5F, 0x1F60,
+ 0x0608, 0x1F70, 0x000E, 0x1FBA,
+ 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA,
+ 0x1FCB, 0x1FDA, 0x1FDB, 0x1FF8,
+ 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA,
+ 0x1FFB, 0x1F80, 0x0608, 0x1F90,
+ 0x0608, 0x1FA0, 0x0608, 0x1FB0,
+ 0x0004, 0x1FB8, 0x1FB9, 0x1FB2,
+ 0x1FBC, 0x1FCC, 0x0001, 0x1FC3,
+ 0x1FD0, 0x0602, 0x1FE0, 0x0602,
+ 0x1FE5, 0x0001, 0x1FEC, 0x1FF3,
+ 0x0001, 0x1FFC,
+
+ /* Letterlike Symbols */
+ 0x214E, 0x0001, 0x2132,
+
+ /* Number forms */
+ 0x2170, 0x0210, 0x2184, 0x0001,
+ 0x2183,
+
+ /* Enclosed Alphanumerics */
+ 0x24D0, 0x051A, 0x2C30, 0x042F,
+
+ /* Latin Extended-C */
+ 0x2C60, 0x0102, 0x2C67, 0x0106,
+ 0x2C75, 0x0102,
+
+ /* Coptic */
+ 0x2C80, 0x0164,
+
+ /* Georgian Supplement */
+ 0x2D00, 0x0826,
+
+ /* Full-width */
+ 0xFF41, 0x031A,
+
+ /* EOT */
+ 0x0000
+
+ };
+
+ const unsigned short *p;
+ unsigned short uc, bc, nc, cmd;
+
+ if (uni < 0x10000) {
+
+ uc = (unsigned short) uni;
+ p = uc < 0x1000 ? cvt1 : cvt2;
+
+ for (;;) {
+
+ bc = *p++;
+
+ if (bc == 0 || uc < bc) {
+ break;
+ }
+
+ nc = *p++; cmd = nc >> 8; nc &= 0xFF;
+
+ if (uc < bc + nc) {
+
+ switch (cmd) {
+
+ case 0:
+
+ uc = p[uc - bc];
+ break;
+
+ case 1:
+
+ uc -= (uc - bc) & 1;
+ break;
+
+ case 2:
+
+ uc -= 16;
+ break;
+
+ case 3:
+
+ uc -= 32;
+ break;
+
+ case 4:
+
+ uc -= 48;
+ break;
+
+ case 5:
+
+ uc -= 26;
+ break;
+
+ case 6:
+
+ uc += 8;
+ break;
+
+ case 7:
+
+ uc -= 80;
+ break;
+
+ case 8:
+
+ uc -= 0x1C60;
+ break;
+
+ }
+
+ break;
+
+ }
+
+ if (cmd == 0) {
+ p += nc;
+ }
+
+ }
+
+ uni = uc;
+
+ }
+
+ return uni;
+
+}
+
+static unsigned short ld_word (const unsigned char *ptr) {
+ return ((unsigned short) ptr[0]) | (((unsigned short) ptr[1]) << 8);
+}
+
+int cmp_lfn (const unsigned short *lfnbuf, unsigned char *dir) {
+
+ unsigned short wc, uc;
+ unsigned int i, s;
+
+ if (ld_word (dir + 26) != 0) {
+ return 0;
+ }
+
+ i = ((*dir & 0x3f) - 1) * 13;
+
+ for (wc = 1, s = 0; s < 13; s++) {
+
+ uc = ld_word (dir + lfn_ofs[s]);
+
+ if (wc != 0) {
+
+ if (i >= LFN_MAX || wtoupper (uc) != wtoupper (lfnbuf[i++])) {
+ return 0;
+ }
+
+ wc = uc;
+
+ } else {
+
+ if (uc != 0xffff) {
+ return 0;
+ }
+
+ }
+
+ }
+
+ if ((*dir & 0x40) && wc && lfnbuf[i]) {
+ return 0;
+ }
+
+ return 1;
+
+}
+
+unsigned char sum_sfn (unsigned char *dir) {
+
+ unsigned char sum = 0;
+ unsigned int n = 11;
+
+ do {
+ sum = (sum >> 1) + (sum << 7) + *dir++;
+ } while (--n);
+
+ return sum;
+
+}
+