1 /*----------------------------------------------------------------------------/ 
   2 /  Petit FatFs - FAT file system module  R0.02a                (C)ChaN, 2010 
   3 /-----------------------------------------------------------------------------/ 
   4 / Petit FatFs module is an open source software to implement FAT file system to 
   5 / small embedded systems. This is a free software and is opened for education, 
   6 / research and commercial developments under license policy of following trems. 
   8 /  Copyright (C) 2010, ChaN, all right reserved. 
  10 / * The Petit FatFs module is a free software and there is NO WARRANTY. 
  11 / * No restriction on use. You can use, modify and redistribute it for 
  12 /   personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY. 
  13 / * Redistributions of source code must retain the above copyright notice. 
  15 /-----------------------------------------------------------------------------/ 
  16 / Jun 15,'09  R0.01a  First release. (Branched from FatFs R0.07b.) 
  18 / Dec 14,'09  R0.02   Added multiple code page support. 
  19 /                     Added write funciton. 
  20 /                     Changed stream read mode interface. 
  21 / Dec 07,'10  R0.02a  Added some configuration options. 
  22 /                     Fixed fails to open objects with DBCS character. 
  23 /----------------------------------------------------------------------------*/ 
  25 #include "pff.h"                /* Petit FatFs configurations and declarations */ 
  26 #include "diskio.h"             /* Declarations of low level disk I/O functions */ 
  30 /*-------------------------------------------------------------------------- 
  32    Module Private Definitions 
  34 ---------------------------------------------------------------------------*/ 
  38 #define LD_CLUST(dir)   (((DWORD)LD_WORD(dir+DIR_FstClusHI)<<16) | LD_WORD(dir+DIR_FstClusLO)) 
  40 #define LD_CLUST(dir)   LD_WORD(dir+DIR_FstClusLO) 
  44 /*--------------------------------------------------------*/ 
  45 /* DBCS code ranges and SBCS extend char conversion table */ 
  47 #if _CODE_PAGE == 932   /* Japanese Shift-JIS */ 
  48 #define _DF1S   0x81    /* DBC 1st byte range 1 start */ 
  49 #define _DF1E   0x9F    /* DBC 1st byte range 1 end */ 
  50 #define _DF2S   0xE0    /* DBC 1st byte range 2 start */ 
  51 #define _DF2E   0xFC    /* DBC 1st byte range 2 end */ 
  52 #define _DS1S   0x40    /* DBC 2nd byte range 1 start */ 
  53 #define _DS1E   0x7E    /* DBC 2nd byte range 1 end */ 
  54 #define _DS2S   0x80    /* DBC 2nd byte range 2 start */ 
  55 #define _DS2E   0xFC    /* DBC 2nd byte range 2 end */ 
  57 #elif _CODE_PAGE == 936 /* Simplified Chinese GBK */ 
  65 #elif _CODE_PAGE == 949 /* Korean */ 
  75 #elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */ 
  83 #elif _CODE_PAGE == 437 /* U.S. (OEM) */ 
  85 #define _EXCVT {0x80,0x9A,0x90,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, \ 
  86                                 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
  87                                 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, \ 
  88                                 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} 
  90 #elif _CODE_PAGE == 720 /* Arabic (OEM) */ 
  92 #define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
  93                                 0xA0,0xA1,0xA2,0xA3,0xA4,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, \ 
  94                                 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, \ 
  95                                 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} 
  97 #elif _CODE_PAGE == 737 /* Greek (OEM) */ 
  99 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ 
 100                                 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
 101                                 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, \ 
 102                                 0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 
 104 #elif _CODE_PAGE == 775 /* Baltic (OEM) */ 
 106 #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 
 107                                 0xA0,0xA1,0xE0,0xA3,0xA3,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, \ 
 108                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 
 109                                 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 
 111 #elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ 
 113 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 
 114                                 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
 115                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,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, \ 
 116                                 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 
 118 #elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ 
 120 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ 
 121                                 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 
 122                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 
 123                                 0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} 
 125 #elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ 
 127 #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ 
 128                                 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 
 129                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 
 130                                 0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} 
 132 #elif _CODE_PAGE == 857 /* Turkish (OEM) */ 
 134 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ 
 135                                 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
 136                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,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, \ 
 137                                 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 
 139 #elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ 
 141 #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ 
 142                                 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
 143                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 
 144                                 0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 
 146 #elif _CODE_PAGE == 862 /* Hebrew (OEM) */ 
 148 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
 149                                 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
 150                                 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, \ 
 151                                 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} 
 153 #elif _CODE_PAGE == 866 /* Russian (OEM) */ 
 155 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
 156                                 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 
 157                                 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, \ 
 158                                 0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 
 160 #elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ 
 162 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
 163                                 0xA0,0xA1,0xA2,0xA3,0xA4,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, \ 
 164                                 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, \ 
 165                                 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} 
 167 #elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ 
 169 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ 
 170                                 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ 
 171                                 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, \ 
 172                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} 
 174 #elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ 
 176 #define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ 
 177                                 0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ 
 178                                 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, \ 
 179                                 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} 
 181 #elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ 
 183 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ 
 184                                 0xA0,0x21,0xA2,0xA3,0xA4,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, \ 
 185                                 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, \ 
 186                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 
 188 #elif _CODE_PAGE == 1253 /* Greek (Windows) */ 
 190 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
 191                                 0xA0,0xA1,0xA2,0xA3,0xA4,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, \ 
 192                                 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,0xA2,0xB8,0xB9,0xBA, \ 
 193                                 0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} 
 195 #elif _CODE_PAGE == 1254 /* Turkish (Windows) */ 
 197 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ 
 198                                 0xA0,0x21,0xA2,0xA3,0xA4,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, \ 
 199                                 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, \ 
 200                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 
 202 #elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ 
 204 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
 205                                 0xA0,0x21,0xA2,0xA3,0xA4,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, \ 
 206                                 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, \ 
 207                                 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} 
 209 #elif _CODE_PAGE == 1256 /* Arabic (Windows) */ 
 211 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \ 
 212                                 0xA0,0xA1,0xA2,0xA3,0xA4,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, \ 
 213                                 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, \ 
 214                                 0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF} 
 216 #elif _CODE_PAGE == 1257 /* Baltic (Windows) */ 
 218 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 
 219                                 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \ 
 220                                 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, \ 
 221                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} 
 223 #elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */ 
 225 #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \ 
 226                                 0xA0,0x21,0xA2,0xA3,0xA4,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, \ 
 227                                 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, \ 
 228                                 0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F} 
 230 #elif _CODE_PAGE == 1   /* ASCII (for only non-LFN cfg) */ 
 234 #error Unknown code page 
 240 /* Character code support macros */ 
 242 #define IsUpper(c)      (((c)>='A')&&((c)<='Z')) 
 243 #define IsLower(c)      (((c)>='a')&&((c)<='z')) 
 245 #if _DF1S               /* DBCS configuration */ 
 247 #ifdef _DF2S    /* Two 1st byte areas */ 
 248 #define IsDBCS1(c)      (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E)) 
 249 #else                   /* One 1st byte area */ 
 250 #define IsDBCS1(c)      ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) 
 253 #ifdef _DS3S    /* Three 2nd byte areas */ 
 254 #define IsDBCS2(c)      (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E)) 
 255 #else                   /* Two 2nd byte areas */ 
 256 #define IsDBCS2(c)      (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E)) 
 259 #else                   /* SBCS configuration */ 
 267 /* FatFs refers the members in the FAT structures with byte offset instead 
 268 / of structure member because there are incompatibility of the packing option 
 269 / between various compilers. */ 
 273 #define BPB_BytsPerSec          11 
 274 #define BPB_SecPerClus          13 
 275 #define BPB_RsvdSecCnt          14 
 276 #define BPB_NumFATs                     16 
 277 #define BPB_RootEntCnt          17 
 278 #define BPB_TotSec16            19 
 280 #define BPB_FATSz16                     22 
 281 #define BPB_SecPerTrk           24 
 282 #define BPB_NumHeads            26 
 283 #define BPB_HiddSec                     28 
 284 #define BPB_TotSec32            32 
 288 #define BS_BootSig                      38 
 291 #define BS_FilSysType           54 
 293 #define BPB_FATSz32                     36 
 294 #define BPB_ExtFlags            40 
 296 #define BPB_RootClus            44 
 297 #define BPB_FSInfo                      48 
 298 #define BPB_BkBootSec           50 
 299 #define BS_DrvNum32                     64 
 300 #define BS_BootSig32            66 
 301 #define BS_VolID32                      67 
 302 #define BS_VolLab32                     71 
 303 #define BS_FilSysType32         82 
 305 #define MBR_Table                       446 
 310 #define DIR_CrtTime                     14 
 311 #define DIR_CrtDate                     16 
 312 #define DIR_FstClusHI           20 
 313 #define DIR_WrtTime                     22 
 314 #define DIR_WrtDate                     24 
 315 #define DIR_FstClusLO           26 
 316 #define DIR_FileSize            28 
 320 /*-------------------------------------------------------------------------- 
 324 ---------------------------------------------------------------------------*/ 
 328 FATFS 
*FatFs
;   /* Pointer to the file system object (logical drive) */ 
 333 void mem_set (void* dst
, int val
, int cnt
) { 
 334         char *d 
= (char*)dst
; 
 335         while (cnt
--) *d
++ = (char)val
; 
 338 /* Compare memory to memory */ 
 340 int mem_cmp (const void* dst
, const void* src
, int cnt
) { 
 341         const char *d 
= (const char *)dst
, *s 
= (const char *)src
; 
 343         while (cnt
-- && (r 
= *d
++ - *s
++) == 0) ; 
 349 /*-----------------------------------------------------------------------*/ 
 350 /* FAT access - Read value of a FAT entry                                */ 
 351 /*-----------------------------------------------------------------------*/ 
 354 CLUST 
get_fat ( /* 1:IO error, Else:Cluster status */ 
 355         CLUST clst      
/* Cluster# to get the link information */ 
 363         if (clst 
< 2 || clst 
>= fs
->n_fatent
)   /* Range check */ 
 366         switch (fs
->fs_type
) { 
 369                 bc 
= (WORD
)clst
; bc 
+= bc 
/ 2; 
 370                 ofs 
= bc 
% 512; bc 
/= 512; 
 372                         if (disk_readp(buf
, fs
->fatbase 
+ bc
, ofs
, 2)) break; 
 374                         if (disk_readp(buf
, fs
->fatbase 
+ bc
, 511, 1)) break; 
 375                         if (disk_readp(buf
+1, fs
->fatbase 
+ bc 
+ 1, 0, 1)) break; 
 378                 return (clst 
& 1) ? 
(wc 
>> 4) : (wc 
& 0xFFF); 
 381                 if (disk_readp(buf
, fs
->fatbase 
+ clst 
/ 256, (WORD
)(((WORD
)clst 
% 256) * 2), 2)) break; 
 385                 if (disk_readp(buf
, fs
->fatbase 
+ clst 
/ 128, (WORD
)(((WORD
)clst 
% 128) * 4), 4)) break; 
 386                 return LD_DWORD(buf
) & 0x0FFFFFFF; 
 390         return 1;       /* An error occured at the disk I/O layer */ 
 396 /*-----------------------------------------------------------------------*/ 
 397 /* Get sector# from cluster#                                             */ 
 398 /*-----------------------------------------------------------------------*/ 
 401 DWORD 
clust2sect (      /* !=0: Sector number, 0: Failed - invalid cluster# */ 
 402         CLUST clst              
/* Cluster# to be converted */ 
 409         if (clst 
>= (fs
->n_fatent 
- 2)) return 0;               /* Invalid cluster# */ 
 410         return (DWORD
)clst 
* fs
->csize 
+ fs
->database
; 
 416 /*-----------------------------------------------------------------------*/ 
 417 /* Directory handling - Rewind directory index                           */ 
 418 /*-----------------------------------------------------------------------*/ 
 422         DIR *dj                 
/* Pointer to directory object */ 
 431         if (clst 
== 1 || clst 
>= fs
->n_fatent
)  /* Check start cluster range */ 
 433         if (_FS_FAT32 
&& !clst 
&& fs
->fs_type 
== FS_FAT32
)      /* Replace cluster# 0 with root cluster# if in FAT32 */ 
 434                 clst 
= (CLUST
)fs
->dirbase
; 
 435         dj
->clust 
= clst
;                                               /* Current cluster */ 
 436         dj
->sect 
= clst ? 
clust2sect(clst
) : fs
->dirbase
;       /* Current sector */ 
 438         return FR_OK
;   /* Seek succeeded */ 
 444 /*-----------------------------------------------------------------------*/ 
 445 /* Directory handling - Move directory index next                        */ 
 446 /*-----------------------------------------------------------------------*/ 
 449 FRESULT 
dir_next (      /* FR_OK:Succeeded, FR_NO_FILE:End of table */ 
 450         DIR *dj                 
/* Pointer to directory object */ 
 459         if (!i 
|| !dj
->sect
)    /* Report EOT when index has reached 65535 */ 
 462         if (!(i 
% 16)) {                /* Sector changed? */ 
 463                 dj
->sect
++;                     /* Next sector */ 
 465                 if (dj
->clust 
== 0) {   /* Static table */ 
 466                         if (i 
>= fs
->n_rootdir
) /* Report EOT when end of table */ 
 469                 else {                                  /* Dynamic table */ 
 470                         if (((i 
/ 16) & (fs
->csize
-1)) == 0) {  /* Cluster changed? */ 
 471                                 clst 
= get_fat(dj
->clust
);              /* Get next cluster */ 
 472                                 if (clst 
<= 1) return FR_DISK_ERR
; 
 473                                 if (clst 
>= fs
->n_fatent
)               /* When it reached end of dynamic table */ 
 474                                         return FR_NO_FILE
;                      /* Report EOT */ 
 475                                 dj
->clust 
= clst
;                               /* Initialize data for new cluster */ 
 476                                 dj
->sect 
= clust2sect(clst
); 
 489 /*-----------------------------------------------------------------------*/ 
 490 /* Directory handling - Find an object in the directory                  */ 
 491 /*-----------------------------------------------------------------------*/ 
 495         DIR *dj
,                /* Pointer to the directory object linked to the file name */ 
 496         BYTE 
*dir               
/* 32-byte working buffer */ 
 503         res 
= dir_rewind(dj
);                   /* Rewind directory object */ 
 504         if (res 
!= FR_OK
) return res
; 
 507                 res 
= disk_readp(dir
, dj
->sect
, (WORD
)((dj
->index 
% 16) * 32), 32)      /* Read an entry */ 
 508                         ? FR_DISK_ERR 
: FR_OK
; 
 509                 if (res 
!= FR_OK
) break; 
 510                 c 
= dir
[DIR_Name
];      /* First character */ 
 511                 if (c 
== 0) { res 
= FR_NO_FILE
; break; }        /* Reached to end of table */ 
 512                 if (!(dir
[DIR_Attr
] & AM_VOL
) && !mem_cmp(dir
, dj
->fn
, 11)) /* Is it a valid entry? */ 
 514                 res 
= dir_next(dj
);                                     /* Next entry */ 
 515         } while (res 
== FR_OK
); 
 523 /*-----------------------------------------------------------------------*/ 
 524 /* Read an object from the directory                                     */ 
 525 /*-----------------------------------------------------------------------*/ 
 529         DIR *dj
,                /* Pointer to the directory object to store read object name */ 
 530         BYTE 
*dir               
/* 32-byte working buffer */ 
 539                 res 
= disk_readp(dir
, dj
->sect
, (WORD
)((dj
->index 
% 16) * 32), 32)      /* Read an entry */ 
 540                         ? FR_DISK_ERR 
: FR_OK
; 
 541                 if (res 
!= FR_OK
) break; 
 543                 if (c 
== 0) { res 
= FR_NO_FILE
; break; }        /* Reached to end of table */ 
 544                 a 
= dir
[DIR_Attr
] & AM_MASK
; 
 545                 if (c 
!= 0xE5 && c 
!= '.' && !(a 
& AM_VOL
))     /* Is it a valid entry? */ 
 547                 res 
= dir_next(dj
);                     /* Next entry */ 
 548                 if (res 
!= FR_OK
) break; 
 551         if (res 
!= FR_OK
) dj
->sect 
= 0; 
 559 /*-----------------------------------------------------------------------*/ 
 560 /* Pick a segment and create the object name in directory form           */ 
 561 /*-----------------------------------------------------------------------*/ 
 564         static const BYTE cvt
[] = _EXCVT
; 
 568 FRESULT 
create_name ( 
 569         DIR *dj
,                        /* Pointer to the directory object */ 
 570         const char **path       
/* Pointer to pointer to the segment in the path string */ 
 573         BYTE c
, d
, ni
, si
, i
, *sfn
; 
 576         /* Create file name in directory form */ 
 578         mem_set(sfn
, ' ', 11); 
 583                 if (c 
<= ' ' || c 
== '/') break;        /* Break on end of segment */ 
 584                 if (c 
== '.' || i 
>= ni
) { 
 585                         if (ni 
!= 8 || c 
!= '.') break; 
 590                 if (c 
>= 0x80)                                  /* To upper extended char (SBCS) */ 
 593                 if (IsDBCS1(c
) && i 
< ni 
- 1) { /* DBC 1st byte? */ 
 594                         d 
= p
[si
++];                            /* Get 2nd byte */ 
 597                 } else {                                                /* Single byte code */ 
 598                         if (IsLower(c
)) c 
-= 0x20;      /* toupper */ 
 602         *path 
= &p
[si
];                                         /* Rerurn pointer to the next segment */ 
 604         sfn
[11] = (c 
<= ' ') ? 
1 : 0;           /* Set last segment flag if end of path */ 
 612 /*-----------------------------------------------------------------------*/ 
 613 /* Get file information from directory entry                             */ 
 614 /*-----------------------------------------------------------------------*/ 
 617 void get_fileinfo (             /* No return code */ 
 618         DIR *dj
,                        /* Pointer to the directory object */ 
 619         BYTE 
*dir
,                      /* 32-byte working buffer */ 
 620         FILINFO 
*fno            
/* Pointer to store the file information */ 
 629                 for (i 
= 0; i 
< 8; i
++) {       /* Copy file name body */ 
 632                         if (c 
== 0x05) c 
= 0xE5; 
 635                 if (dir
[8] != ' ') {            /* Copy file name extension */ 
 637                         for (i 
= 8; i 
< 11; i
++) { 
 643                 fno
->fattrib 
= dir
[DIR_Attr
];                           /* Attribute */ 
 644                 fno
->fsize 
= LD_DWORD(dir
+DIR_FileSize
);        /* Size */ 
 645                 fno
->fdate 
= LD_WORD(dir
+DIR_WrtDate
);          /* Date */ 
 646                 fno
->ftime 
= LD_WORD(dir
+DIR_WrtTime
);          /* Time */ 
 650 #endif /* _USE_DIR */ 
 654 /*-----------------------------------------------------------------------*/ 
 655 /* Follow a file path                                                    */ 
 656 /*-----------------------------------------------------------------------*/ 
 659 FRESULT 
follow_path (   /* FR_OK(0): successful, !=0: error code */ 
 660         DIR *dj
,                        /* Directory object to return last directory and found object */ 
 661         BYTE 
*dir
,                      /* 32-byte working buffer */ 
 662         const char *path        
/* Full-path string to find a file or directory */ 
 668         while (*path 
== ' ') path
++;            /* Skip leading spaces */ 
 669         if (*path 
== '/') path
++;                       /* Strip heading separator */ 
 670         dj
->sclust 
= 0;                                         /* Set start directory (always root dir) */ 
 672         if ((BYTE
)*path 
<= ' ') {                       /* Null path means the root directory */ 
 673                 res 
= dir_rewind(dj
); 
 676         } else {                                                        /* Follow path */ 
 678                         res 
= create_name(dj
, &path
);   /* Get a segment */ 
 679                         if (res 
!= FR_OK
) break; 
 680                         res 
= dir_find(dj
, dir
);                /* Find it */ 
 681                         if (res 
!= FR_OK
) {                             /* Could not find the object */ 
 682                                 if (res 
== FR_NO_FILE 
&& !*(dj
->fn
+11)) 
 686                         if (*(dj
->fn
+11)) break;                /* Last segment match. Function completed. */ 
 687                         if (!(dir
[DIR_Attr
] & AM_DIR
)) { /* Cannot follow because it is a file */ 
 688                                 res 
= FR_NO_PATH
; break; 
 690                         dj
->sclust 
= LD_CLUST(dir
); 
 700 /*-----------------------------------------------------------------------*/ 
 701 /* Check a sector if it is an FAT boot record                            */ 
 702 /*-----------------------------------------------------------------------*/ 
 705 BYTE 
check_fs ( /* 0:The FAT boot record, 1:Valid boot record but not an FAT, 2:Not a boot record, 3:Error */ 
 706         BYTE 
*buf
,      /* Working buffer */ 
 707         DWORD sect      
/* Sector# (lba) to check if it is an FAT boot record or not */ 
 710         if (disk_readp(buf
, sect
, 510, 2))              /* Read the boot sector */ 
 712         if (LD_WORD(buf
) != 0xAA55)                             /* Check record signature */ 
 715         if (!disk_readp(buf
, sect
, BS_FilSysType
, 2) && LD_WORD(buf
) == 0x4146) /* Check FAT12/16 */ 
 717         if (_FS_FAT32 
&& !disk_readp(buf
, sect
, BS_FilSysType32
, 2) && LD_WORD(buf
) == 0x4146)  /* Check FAT32 */ 
 725 /*-------------------------------------------------------------------------- 
 729 --------------------------------------------------------------------------*/ 
 733 /*-----------------------------------------------------------------------*/ 
 734 /* Mount/Unmount a Locical Drive                                         */ 
 735 /*-----------------------------------------------------------------------*/ 
 738         FATFS 
*fs               
/* Pointer to new file system object (NULL: Unmount) */ 
 742         DWORD bsect
, fsize
, tsect
, mclst
; 
 746         if (!fs
) return FR_OK
;                          /* Unregister fs object */ 
 748         if (disk_initialize() & STA_NOINIT
)     /* Check if the drive is ready or not */ 
 751         /* Search FAT partition on the drive */ 
 753         fmt 
= check_fs(buf
, bsect
);                     /* Check sector 0 as an SFD format */ 
 754         if (fmt 
== 1) {                                         /* Not an FAT boot record, it may be FDISK format */ 
 755                 /* Check a partition listed in top of the partition table */ 
 756                 if (disk_readp(buf
, bsect
, MBR_Table
, 16)) {    /* 1st partition entry */ 
 759                         if (buf
[4]) {                                   /* Is the partition existing? */ 
 760                                 bsect 
= LD_DWORD(&buf
[8]);      /* Partition offset in LBA */ 
 761                                 fmt 
= check_fs(buf
, bsect
);     /* Check the partition */ 
 765         if (fmt 
== 3) return FR_DISK_ERR
; 
 766         if (fmt
) return FR_NO_FILESYSTEM
;       /* No valid FAT patition is found */ 
 768         /* Initialize the file system object */ 
 769         if (disk_readp(buf
, bsect
, 13, sizeof(buf
))) return FR_DISK_ERR
; 
 771         fsize 
= LD_WORD(buf
+BPB_FATSz16
-13);                            /* Number of sectors per FAT */ 
 772         if (!fsize
) fsize 
= LD_DWORD(buf
+BPB_FATSz32
-13); 
 774         fsize 
*= buf
[BPB_NumFATs
-13];                                           /* Number of sectors in FAT area */ 
 775         fs
->fatbase 
= bsect 
+ LD_WORD(buf
+BPB_RsvdSecCnt
-13); /* FAT start sector (lba) */ 
 776         fs
->csize 
= buf
[BPB_SecPerClus
-13];                                     /* Number of sectors per cluster */ 
 777         fs
->n_rootdir 
= LD_WORD(buf
+BPB_RootEntCnt
-13);         /* Nmuber of root directory entries */ 
 778         tsect 
= LD_WORD(buf
+BPB_TotSec16
-13);                           /* Number of sectors on the file system */ 
 779         if (!tsect
) tsect 
= LD_DWORD(buf
+BPB_TotSec32
-13); 
 780         mclst 
= (tsect                                          
/* Last cluster# + 1 */ 
 781                 - LD_WORD(buf
+BPB_RsvdSecCnt
-13) - fsize 
- fs
->n_rootdir 
/ 16 
 783         fs
->n_fatent 
= (CLUST
)mclst
; 
 785         fmt 
= FS_FAT16
;                                                 /* Determine the FAT sub type */ 
 786         if (mclst 
< 0xFF7)                                              /* Number of clusters < 0xFF5 */ 
 790                 return FR_NO_FILESYSTEM
; 
 792         if (mclst 
>= 0xFFF7)                                    /* Number of clusters >= 0xFFF5 */ 
 796                 return FR_NO_FILESYSTEM
; 
 799         fs
->fs_type 
= fmt
;              /* FAT sub-type */ 
 800         if (_FS_FAT32 
&& fmt 
== FS_FAT32
) 
 801                 fs
->dirbase 
= LD_DWORD(buf
+(BPB_RootClus
-13));  /* Root directory start cluster */ 
 803                 fs
->dirbase 
= fs
->fatbase 
+ fsize
;                              /* Root directory start sector (lba) */ 
 804         fs
->database 
= fs
->fatbase 
+ fsize 
+ fs
->n_rootdir 
/ 16;        /* Data start sector (lba) */ 
 815 /*-----------------------------------------------------------------------*/ 
 816 /* Open or Create a File                                                 */ 
 817 /*-----------------------------------------------------------------------*/ 
 820         const char *path        
/* Pointer to the file name */ 
 825         BYTE sp
[12], dir
[32]; 
 829         if (!fs
)                                                /* Check file system */ 
 830                 return FR_NOT_ENABLED
; 
 834         res 
= follow_path(&dj
, dir
, path
);      /* Follow the file path */ 
 835         if (res 
!= FR_OK
) return res
;           /* Follow failed */ 
 836         if (!dir
[0] || (dir
[DIR_Attr
] & AM_DIR
))        /* It is a directory */ 
 839         fs
->org_clust 
= LD_CLUST(dir
);                  /* File start cluster */ 
 840         fs
->fsize 
= LD_DWORD(dir
+DIR_FileSize
); /* File size */ 
 841         fs
->fptr 
= 0;                                           /* File pointer */ 
 842         fs
->flag 
= FA_OPENED
; 
 850 /*-----------------------------------------------------------------------*/ 
 852 /*-----------------------------------------------------------------------*/ 
 856         void* buff
,             /* Pointer to the read buffer (NULL:Forward data to the stream)*/ 
 857         WORD btr
,               /* Number of bytes to read */ 
 858         WORD
* br                
/* Pointer to number of bytes read */ 
 865         BYTE cs
, *rbuff 
= buff
; 
 870         if (!fs
) return FR_NOT_ENABLED
;         /* Check file system */ 
 871         if (!(fs
->flag 
& FA_OPENED
))            /* Check if opened */ 
 872                 return FR_NOT_OPENED
; 
 874         remain 
= fs
->fsize 
- fs
->fptr
; 
 875         if (btr 
> remain
) btr 
= (WORD
)remain
;                   /* Truncate btr by remaining bytes */ 
 877         while (btr
)     {                                                                       /* Repeat until all data transferred */ 
 878                 if ((fs
->fptr 
% 512) == 0) {                            /* On the sector boundary? */ 
 879                         cs 
= (BYTE
)(fs
->fptr 
/ 512 & (fs
->csize 
- 1));  /* Sector offset in the cluster */ 
 880                         if (!cs
) {                                                              /* On the cluster boundary? */ 
 881                                 clst 
= (fs
->fptr 
== 0) ?                        
/* On the top of the file? */ 
 882                                         fs
->org_clust 
: get_fat(fs
->curr_clust
); 
 883                                 if (clst 
<= 1) goto fr_abort
; 
 884                                 fs
->curr_clust 
= clst
;                          /* Update current cluster */ 
 886                         sect 
= clust2sect(fs
->curr_clust
);              /* Get current sector */ 
 887                         if (!sect
) goto fr_abort
; 
 888                         fs
->dsect 
= sect 
+ cs
; 
 890                 rcnt 
= (WORD
)(512 - (fs
->fptr 
% 512));          /* Get partial sector data from sector buffer */ 
 891                 if (rcnt 
> btr
) rcnt 
= btr
; 
 892                 dr 
= disk_readp(!buff ? 
0 : rbuff
, fs
->dsect
, (WORD
)(fs
->fptr 
% 512), rcnt
); 
 893                 if (dr
) goto fr_abort
; 
 894                 fs
->fptr 
+= rcnt
; rbuff 
+= rcnt
;                        /* Update pointers and counters */ 
 895                 btr 
-= rcnt
; *br 
+= rcnt
; 
 908 /*-----------------------------------------------------------------------*/ 
 910 /*-----------------------------------------------------------------------*/ 
 914         const void* buff
,       /* Pointer to the data to be written */ 
 915         WORD btw
,                       /* Number of bytes to write (0:Finalize the current write operation) */ 
 916         WORD
* bw                        
/* Pointer to number of bytes written */ 
 921         const BYTE 
*p 
= buff
; 
 928         if (!fs
) return FR_NOT_ENABLED
;         /* Check file system */ 
 929         if (!(fs
->flag 
& FA_OPENED
))            /* Check if opened */ 
 930                 return FR_NOT_OPENED
; 
 932         if (!btw
) {             /* Finalize request */ 
 933                 if ((fs
->flag 
& FA__WIP
) && disk_writep(0, 0)) goto fw_abort
; 
 934                 fs
->flag 
&= ~FA__WIP
; 
 936         } else {                /* Write data request */ 
 937                 if (!(fs
->flag 
& FA__WIP
))              /* Round-down fptr to the sector boundary */ 
 938                         fs
->fptr 
&= 0xFFFFFE00; 
 940         remain 
= fs
->fsize 
- fs
->fptr
; 
 941         if (btw 
> remain
) btw 
= (WORD
)remain
;                   /* Truncate btw by remaining bytes */ 
 943         while (btw
)     {                                                                       /* Repeat until all data transferred */ 
 944                 if (((WORD
)fs
->fptr 
% 512) == 0) {                      /* On the sector boundary? */ 
 945                         cs 
= (BYTE
)(fs
->fptr 
/ 512 & (fs
->csize 
- 1));  /* Sector offset in the cluster */ 
 946                         if (!cs
) {                                                              /* On the cluster boundary? */ 
 947                                 clst 
= (fs
->fptr 
== 0) ?                        
/* On the top of the file? */ 
 948                                         fs
->org_clust 
: get_fat(fs
->curr_clust
); 
 949                                 if (clst 
<= 1) goto fw_abort
; 
 950                                 fs
->curr_clust 
= clst
;                          /* Update current cluster */ 
 952                         sect 
= clust2sect(fs
->curr_clust
);              /* Get current sector */ 
 953                         if (!sect
) goto fw_abort
; 
 954                         fs
->dsect 
= sect 
+ cs
; 
 955                         if (disk_writep(0, fs
->dsect
)) goto fw_abort
;   /* Initiate a sector write operation */ 
 958                 wcnt 
= 512 - ((WORD
)fs
->fptr 
% 512);            /* Number of bytes to write to the sector */ 
 959                 if (wcnt 
> btw
) wcnt 
= btw
; 
 960                 if (disk_writep(p
, wcnt
)) goto fw_abort
;        /* Send data to the sector */ 
 961                 fs
->fptr 
+= wcnt
; p 
+= wcnt
;                            /* Update pointers and counters */ 
 962                 btw 
-= wcnt
; *bw 
+= wcnt
; 
 963                 if (((WORD
)fs
->fptr 
% 512) == 0) { 
 964                         if (disk_writep(0, 0)) goto fw_abort
;   /* Finalize the currtent secter write operation */ 
 965                         fs
->flag 
&= ~FA__WIP
; 
 979 /*-----------------------------------------------------------------------*/ 
 980 /* Seek File R/W Pointer                                                 */ 
 981 /*-----------------------------------------------------------------------*/ 
 985         DWORD ofs               
/* File pointer from top of file */ 
 989         DWORD bcs
, sect
, ifptr
; 
 993         if (!fs
) return FR_NOT_ENABLED
;         /* Check file system */ 
 994         if (!(fs
->flag 
& FA_OPENED
))            /* Check if opened */ 
 995                         return FR_NOT_OPENED
; 
 997         if (ofs 
> fs
->fsize
) ofs 
= fs
->fsize
;   /* Clip offset with the file size */ 
1001                 bcs 
= (DWORD
)fs
->csize 
* 512;   /* Cluster size (byte) */ 
1003                         (ofs 
- 1) / bcs 
>= (ifptr 
- 1) / bcs
) { /* When seek to same or following cluster, */ 
1004                         fs
->fptr 
= (ifptr 
- 1) & ~(bcs 
- 1);    /* start from the current cluster */ 
1006                         clst 
= fs
->curr_clust
; 
1007                 } else {                                                        /* When seek to back cluster, */ 
1008                         clst 
= fs
->org_clust
;                   /* start from the first cluster */ 
1009                         fs
->curr_clust 
= clst
; 
1011                 while (ofs 
> bcs
) {                             /* Cluster following loop */ 
1012                         clst 
= get_fat(clst
);           /* Follow cluster chain */ 
1013                         if (clst 
<= 1 || clst 
>= fs
->n_fatent
) goto fe_abort
; 
1014                         fs
->curr_clust 
= clst
; 
1019                 sect 
= clust2sect(clst
);                /* Current sector */ 
1020                 if (!sect
) goto fe_abort
; 
1021                 fs
->dsect 
= sect 
+ (fs
->fptr 
/ 512 & (fs
->csize 
- 1)); 
1034 /*-----------------------------------------------------------------------*/ 
1035 /* Create a Directroy Object                                             */ 
1036 /*-----------------------------------------------------------------------*/ 
1039 FRESULT 
pf_opendir ( 
1040         DIR *dj
,                        /* Pointer to directory object to create */ 
1041         const char *path        
/* Pointer to the directory path */ 
1045         BYTE sp
[12], dir
[32]; 
1049         if (!fs
) {                              /* Check file system */ 
1050                 res 
= FR_NOT_ENABLED
; 
1053                 res 
= follow_path(dj
, dir
, path
);               /* Follow the path to the directory */ 
1054                 if (res 
== FR_OK
) {                                             /* Follow completed */ 
1055                         if (dir
[0]) {                                           /* It is not the root dir */ 
1056                                 if (dir
[DIR_Attr
] & AM_DIR
)             /* The object is a directory */ 
1057                                         dj
->sclust 
= LD_CLUST(dir
); 
1058                                 else                                                    /* The object is not a directory */ 
1062                                 res 
= dir_rewind(dj
);                   /* Rewind dir */ 
1064                 if (res 
== FR_NO_FILE
) res 
= FR_NO_PATH
; 
1073 /*-----------------------------------------------------------------------*/ 
1074 /* Read Directory Entry in Sequense                                      */ 
1075 /*-----------------------------------------------------------------------*/ 
1077 FRESULT 
pf_readdir ( 
1078         DIR *dj
,                        /* Pointer to the open directory object */ 
1079         FILINFO 
*fno            
/* Pointer to file information to return */ 
1083         BYTE sp
[12], dir
[32]; 
1087         if (!fs
) {                              /* Check file system */ 
1088                 res 
= FR_NOT_ENABLED
; 
1092                         res 
= dir_rewind(dj
); 
1094                         res 
= dir_read(dj
, dir
); 
1095                         if (res 
== FR_NO_FILE
) { 
1099                         if (res 
== FR_OK
) {                             /* A valid entry is found */ 
1100                                 get_fileinfo(dj
, dir
, fno
);     /* Get the object information */ 
1101                                 res 
= dir_next(dj
);                     /* Increment index for next */ 
1102                                 if (res 
== FR_NO_FILE
) { 
1113 #endif /* _USE_DIR */