📄 fat.c
字号:
short sFcbNameLen;
u8 ucSum;
ucSum = 0;
for (sFcbNameLen=11; sFcbNameLen!=0; sFcbNameLen--) // NOTE: The operation is an unsigned char rotate right
{
ucSum = ((ucSum & 1) ? 0x80 : 0) + (ucSum >> 1) + *pFcbName++;
}
*uSum = ucSum;
}
// The Basis-Name Generation Algorithm
// void BasisNameGeneration(void)
// {
// 1. The UNICODE name passed to the file system is converted to upper case.
// 2. The upper cased UNICODE name is converted to OEM.
// if (the uppercased UNICODE glyph does not exist as an OEM glyph in the OEM code page)
// or (the OEM glyph is invalid in an 8.3 name)
// {
// Replace the glyph to an OEM '_' (underscore) character.
// Set a "lossy conversion" flag.
// }
// 3. Strip all leading and embedded spaces from the long name.
// 4. Strip all leading periods from the long name.
// 5. While (not at end of the long name)
// and (char is not a period)
// and (total chars copied < 8)
// {
// Copy characters into primary portion of the basis name
// }
// 6. Insert a dot at the end of the primary components of the basis-name
// iff the basis name has an extension after the last period in the name.
// 7. Scan for the last embedded period in the long name.
// If (the last embedded period was found)
// {
// While (not at end of the long name)
// and (total chars copied < 3)
// {
// Copy characters into extension portion of the basis name
// }
// }
// }
/**********************************************************/
/* Generate a short name with a long file name */
/**********************************************************/
void FAT_GenerateSNameFromLName(short *s, char *p, int* nFlag, SDHC* sCh) // implementation of BasisNameGeneration()
{
char c[2][9];
int i, n, j[2]={0, 0}, nExt=0, nLossyFlag=0;
while (*s)
{
short k = *s++;
if (k>=0x61&&k<=0x7a)
k -= 0x20; // UNICODE name convert to Upper case. (k>=a && k<=z)
if ((k&0x7f)!=k) //if k is minus
{
k = '_'; nLossyFlag = 1;
} // if not ascii, replace it with '_' and lossy flag is set.
if (k=='+' || k==',' || k==':' || k=='=' || k=='[' || k==']')
{ // if invalid, do as the above.
k = '_'; nLossyFlag = 1;
}
if (k==' ')
{
nLossyFlag = 1;
continue;
} // Strip all the spaces.
if (k=='.'&&j[0]==0)
{
nLossyFlag = 1;
continue;
} // Strip all the periods in the name.
if (k!='.'&&nExt>1)
{
for (n=0; (n<j[1])&&(j[0]+n<8); n++)
c[0][j[0]+n] = c[1][n]; // copy char into primary portion of the basis name
j[0]+= n; //j[o]=8
j[1] = 0;
nExt = 1;
}
if (k!='.'&&j[nExt]<8)
{
c[nExt][j[nExt]++] = (char)k;
continue;
}
else if (k=='.')
{
if (nExt) nLossyFlag = 1;
nExt++;
continue;
}
else
nLossyFlag = 1;
}
for (i=j[0]; i<8; i++)
c[0][i] = ' ';
c[0][8] = 0; // Primary portion
strcpy(p, c[0]);
for (i=j[1]; i<3; i++)
c[1][i] = ' ';
c[1][3] = 0; // Extension portion
strcat(p, c[1]);
*nFlag = nLossyFlag;
}
// The Numeric-Tail Generation Algorithm (p.31)
// void NumericTailGeneration(void)
// {
// if (a "lossy conversion" was not flagged)
// and (the long name fits within the 8.3 naming conventions)
// and (the basis-name does not collide with any existing short name)
// {
// The short name is only the basis-name without the numeric tail.
// }
// else
// {
// Insert a numeric-tail "~n" to the end of the primary name
// such that the value of the "~n" is chosen so that the name
// thus formed does not collide with any existing short name
// and that the primary name does not exceed eight characters in nLength.
// }
// Validating the contents of a directory
// if (((m_ucLDirAttr & ATTR_LONG_NAME_MASK) == (ATTR_LONG_NAME)) && (m_ucLDirOrd != 0xE5))
// {
// Found an active long name sub-component. //
// }
// if (((m_ucLDirAttr & ATTR_LONG_NAME_MASK) != (ATTR_LONG_NAME)) && (m_ucLDirOrd != 0xE5))
// {
// if ((DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == 0x00) {
// Found a file. //
// } else if ((DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == ATTR_DIRECTORY) {
// Found a directory. //
// } else if ((DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == ATTR_VOLUME_ID) {
// Found a volume label. //
// } else {
// Found an invalid directory entry. //
// }
// }
// } End of NumericTailGeneration()
/**********************************************************/
/* Append a numeric tail for short file name */
/**********************************************************/
void FAT_GenerateNumericTail(char *p, int n, SDHC* sCh) //Implementation of NumericTailGeneration()
{
char c[8];
int i, k, m=n, nDigitNum=1;
// invalid numeric tail //
if (n<1 || n>999999 || p ==NULL)
return;
// get nDigitNum //
while (m>=10)
{
m /= 10; nDigitNum++;
}
// get tail in char //
k = nDigitNum;
c[k+1]=0;
do
{
m=n%10; n/=10; c[k--]=m+'0';
}
while (n>=10);
c[0] = '~';
// insert //
for (k=0; k<8; k++)
if (p[k]==' ')
break;
if (k+nDigitNum<8)
{
for (i=0; i<nDigitNum; i++)
p[k+i] = c[i];
}
else
{
for (i=0; i<nDigitNum; i++)
p[8-nDigitNum+i] = c[i];
}
}
void FAT_ReadSector(u8 *dest, int lba, int nblocks, SDHC* sCh)
{
Assert(dest);
Assert(nblocks);
SDHC_ReadBlocks(lba, nblocks, (u32)dest, sCh);
}
void FAT_WriteSector(u8 *src, int lba, int nblocks, SDHC* sCh)
{
Assert(src);
Assert(nblocks);
SDHC_WriteBlocks(lba, nblocks, (u32)src, sCh);
}
/******************************************************************/
/* From cluster to physical sector number. */
/******************************************************************/
void FAT_FromClusterToLba(int cluster, int* nLba, SDHC* sCh)
{
if (cluster < 2)
{
*nLba = oFat.m_nPosRoot;
return; /// 7.20 need
}
*nLba = oFat.m_nFirstDataSector + (cluster-2)*oFat.m_ucBpbSecPerClus + SDCARD_OFFSET_SECTOR;
}
/*******************************************************************/
/* collect a long file name in unicode format from directory entry */
/*******************************************************************/
void FAT_CollectLFileName(short *s, u8 *p, int* nLfname, SDHC* sCh)
{
static int nLength;
int i, j, nPosi, nHead, nOrder, ucNerror=0;
L:
if (ucNerror)
{
Assert(0);
if (nHead) oFat.m_nOrphanCount++;
oFat.m_nNthEntry = 0;
*nLfname = -1;
}
nHead = ((p[0]&0x40)==0x40);
if (nHead && oFat.m_nNthEntry>1)
{
ucNerror = 1; goto L;
}
else if (!nHead && oFat.m_nNthEntry<=1)
{
ucNerror = 2; goto L;
}
nOrder = p[0]&(~0x40);
if (nOrder==0||nOrder==0xe5)
{
ucNerror = 3; goto L;
}
if (nHead && oFat.m_nNthEntry<=1)
oFat.m_nNthEntry = nOrder;
else if (oFat.m_nNthEntry == nOrder+1)
oFat.m_nNthEntry = nOrder;
else
{
ucNerror = 4; goto L;
}
Assert(oFat.m_nNthEntry>0);
nPosi = 13*(oFat.m_nNthEntry-1);
for (i = 0; i < 5; i++) // 1-5
s[nPosi+i] = LSB_GET_2BYTES(p+1+i*2);
for (i = 0; i < 6; i++) // 6-11
s[nPosi+5+i] = LSB_GET_2BYTES(p+14+i*2);
for (i = 0; i < 2; i++) // 12-13
s[nPosi+11+i] = LSB_GET_2BYTES(p+28+i*2);
if (nHead)
{
nLength = nPosi+13;
for (i=0; i<13; i++)
if (s[nPosi+i]==0)
{
nLength = nPosi+i;
break;
}
for (j=i+1; j<13; j++)
if (s[nPosi+j]!=-1)
{
ucNerror = 5; goto L;
}
}
if (oFat.m_nNthEntry==1)
{
if (!nLength)
{
ucNerror = 6; goto L;
}
*nLfname = nLength;
}
else
*nLfname = 0;
}
/**********************************************************/
/* Pass out to directory entry from a long file name */
/**********************************************************/
void FAT_PassoutLFileName(short *s, u8* cFname, int nOrder, int* nDirecEntry, SDHC* sCh)
{
// char cSfname[SF_NAME_LENGTH+1];
short *nPosi = s+13*(nOrder-1), sTmp[13];
int i, k=0, nHead=nOrder, nMaxOrder;
int nUniChr;
int nLen;
FAT_GetUnicodeStrLen(s, &nUniChr, sCh);
nLen = nUniChr;
nMaxOrder = (nLen+12)/13;
if (nLen<=0 || nOrder<=0 || nOrder>nMaxOrder)
*nDirecEntry = 0;
if (nOrder == nMaxOrder)
{
nHead |= 0x40; k = nLen%13;
}
if (nHead==0xe5) nHead++;
oFat.m_ucFileEntryHead[0] = nHead;
oFat.m_ucFileEntryHead[11] = ATTR_LONG_NAME;
oFat.m_ucFileEntryHead[12] = 0;
FAT_ComputeChkSum(cFname, &oFat.m_ucFileEntryHead[13], sCh);
LSB_SET_2BYTES(oFat.m_ucFileEntryHead+26, 0);
if (k)
for (i=0; i<13; i++)
sTmp[i] = ((i<k)?(*(nPosi+i)):((i==k)?0:0xffff));
else
for (i=0; i<13; i++)
sTmp[i] = *(nPosi+i);
for (i = 0; i < 5; i++) // 1-5 */
LSB_SET_2BYTES(oFat.m_ucFileEntryHead+1+i*2, *(sTmp+i));
for (i = 0; i < 6; i++) // 6-11 */
LSB_SET_2BYTES(oFat.m_ucFileEntryHead+14+i*2, *(sTmp+5+i));
for (i = 0; i < 2; i++) // 12-13 */
LSB_SET_2BYTES(oFat.m_ucFileEntryHead+28+i*2, *(sTmp+11+i));
*nDirecEntry = 1;
}
//***********************************************************************/
/* Check if p is a short name entry to know previous entry is a orphan */
/************************************************************************/
void FAT_CheckOrphan(u8 *p, int* nOrphan, SDHC* sCh)
{
if (p[0]==FREE_ENTRY_TAG0)
*nOrphan = 1;
if (p[0]==TERM_ENTRY_TAG0)
*nOrphan = 1;
if ((p[11]&ATTR_LONG_NAME)==ATTR_LONG_NAME)
*nOrphan = 1;
if ((p[11]&ATTR_VOLUME_ID)==ATTR_VOLUME_ID)
*nOrphan = 1;
*nOrphan = 0;
}
/***********************************************************/
/* Fat32 short file name conversion from outside to inside */
/***********************************************************/
void FAT_FormatSFileName(u8 *fname, char *name, int* nSfnameconv, SDHC* sCh)
{
char *p=name;
int j=0, nFoundSeparator=0, nFoundSpace=0;
if (p==NULL || *p==0)
*nSfnameconv = -1;
else if (*p == PATH_NAME_CHAR_SEPARATOR)
{
fname[j++] = *p++;
if (*p == PATH_NAME_CHAR_SEPARATOR)
{
fname[j++] = *p++;
}
if ((*p != PATH_NAME_CHAR_DELIMITER) && (*p != PATH_NAME_CHAR_END))
{
*nSfnameconv = -2;
}
fname[j] = PATH_NAME_CHAR_END;
*nSfnameconv = 0;
}
while (*p)
{
if (!PATH_NAME_CHAR_VALID(*p)) // invalid char
{
*nSfnameconv = -3;
}
else if (*p==' ')
{
nFoundSpace = 1;
fname[j++]=*p++;
}
else if (*p==PATH_NAME_CHAR_SEPARATOR)
{
if (nFoundSeparator) // 2 or more
*nSfnameconv = -4;
else if (!j) // no base name
*nSfnameconv = -5;
nFoundSeparator = 1;
while (j<SF_BASE_LENGTH)
fname[j++]=' '; // 8 character max
p++;
}
else if ((*p==PATH_NAME_CHAR_DELIMITER)||(*p==PATH_NAME_CHAR_END))
{
if (!j)
*nSfnameconv = -5; // no base name
else
while (j<SF_NAME_LENGTH)
fname[j++]=' '; // 8+3
}
else
{
if (j==SF_BASE_LENGTH)
nFoundSpace = 0;
else if (nFoundSpace)
*nSfnameconv = -6;
fname[j++] = *p++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -