📄 file.c
字号:
/*
* DSPdap-bootloader - DSP based Digital Audio Player, Bootloader
* Copyright (C) 2004-2007 Roger Quadros <rogerquads @ yahoo . com>
* http://dspdap.sourceforge.net
*
* 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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Id: file.c,v 1.2 2007/06/03 08:54:03 Roger Exp $
*/
#include "file.h"
#include "CF.h"
#include "FAT32.h"
//Removes spaces after extension or last word and stores the string in 'dest'
void RemoveTrailingSpaces(const char* source, char *dest)
{
int i;
int lastNonSpacePos;
// Find total string length of source string
lastNonSpacePos = strlen(source);
// Find last position in string which is not a space
while (lastNonSpacePos != 0)
{
if (source[--lastNonSpacePos] != ' ')
break;
}
//if lastNonSpacePos == 0 means entire string was filled with space
//or string was null.
if(lastNonSpacePos == 0)
{
i = 0; //to make dest a null string.
}
else
{
// Copy from beginning of string upto last nonspace character
for (i = 0; i <= lastNonSpacePos; i++)
dest[i]=source[i];
}
dest[i] = '\0';
}
int strcmpNocase(const char* str1, const char* str2)
{
int len;
char c1, c2;
len = strlen(str1);
if(len != strlen(str2))
{
//lengths don't match
return 1; //not equal
}
while(len > 0)
{
c1 = *str1++;
c2 = *str2++;
if(c1 >= 'A' && c1 <= 'Z')
{
c1 += 'a' - 'A';
}
if(c2 >= 'A' && c2 <= 'Z')
{
c2 += 'a' - 'A';
}
if(c1 != c2)
{
//not equal
return 1;
}
len--;
}
//equal
return 0;
}
//Compare two filenames to see if they match
//NOTE: This function truncates the original strings if they have any
//trailing spaces.
int CompareFileNames(char* name1, char* name2)
{
// Crop both strings for any trailing spaces
RemoveTrailingSpaces(name1, name1); //destination same as source
RemoveTrailingSpaces(name2, name2); //destination same as source
// Compare both strings and return 1 if they match
if (strcmpNocase(name1, name2) != 0)
{
return 1; //filenames not equal
}
else
return 0; //filenames equal
}
//converts a packed SFN file name entry into a normal file name
void Get8_3Filename(char* sfn, char* filename)
{
int i,j, extEnd;
//get first no space in filename backwards
for(i=7; i>=0; i--)
{
if(sfn[i] != ' ')
break;
}
i++; //now i points to space
//get first no space in extension backwards
for(j=10; j>=8; j--)
{
if(sfn[j] != ' ')
break;
}
extEnd = j;
//copy valid filename
for(j=0; j<i; j++)
{
filename[j] = sfn[j];
}
if(extEnd < 8)
{
//no extension
filename[j] = 0;
}
else
{
filename[j++] = '.';
//copy valid extension
for(i=8; i<=extEnd; j++, i++)
{
filename[j] = sfn[i];
}
filename[j] = 0;
}
}
//searches the given directory for the given file/directory name
//and returns the FAT32 record of the file/directory if a match is found
//returns non zero if sub directory/file of given name was not found
int GetMatchingRecord(UI32 dirCluster, char* nameToFind, DIR_ENTRY *pDirEntry)
{
FILE fDir;
static UI16 dirBuffer[256]; //512 bytes
int recordIdx = 0;
UI16* recordPtr;
UI8 attribute;
int i;
fDir.feof = 0; //mark not end of file
fDir.startCluster = dirCluster;
fDir.currentCluster = dirCluster;
fDir.currentSectorInCluster = 0; //1st sector in cluster
fDir.byteNum = 0; //1st byte
fDir.fileSize = 0xFFFFFFFF; //set max. possible size
while(1)
{
if(fread_sector(&fDir, dirBuffer, &i) != 0)
{
//Either EOF or error
return -2;
}
//start searching in the sector for the given directory entry
//there are 16 FAT32 records (32 bytes) in 1 sector (512 bytes)
for(recordIdx = 0; recordIdx < 16; recordIdx++)
{
//get pointer to 1 FAT32 record at recordIdx
recordPtr = &dirBuffer[recordIdx*16]; //*16 since 1 record is 32 bytes (i.e. 16 words)
switch(Get8BitWord(recordPtr, 0))
{
case 0:
//directory ended, stop searching
return -3;
case 0xE5:
//directory entry is free so skip this entry and go to next
continue; //continue for loop next iteration.
//can add invalid name checks here.
default:
//found a FAT32 record.. check if it is a valid entry
//get attribute byte
attribute = Get8BitWord(recordPtr, 11);
if( (attribute & ATTR_LFN_MSK) == ATTR_LFN)
{
//long name entry.
//do nothing
}
else if(attribute & ATTR_VOLID)
{
//volume ID so ignore
}
else
{
//This is a Short name entry
GetDirEntryFromBuffer(recordPtr, pDirEntry);
//if file entry (i.e. SFN) then convert 8.3 packed name to normal filename
if( (pDirEntry->Attr & ATTR_DIR) == 0)
{
//it is a file
Get8_3Filename((char *)pDirEntry->Name, (char *)pDirEntry->Name);
}
//check if the given name matches the name in record
if(CompareFileNames((char*)pDirEntry->Name, nameToFind) == 0)
{
//found a matching entry...save it in output argument
return 0;
}
}
}
}
}
}
FILE file; //static allocation.. should be made dynamic when multiple file support required.
//opens a file handle to the file in the given path.
//NOTE: Multiple file open not yet supported.
FILE *fopen(char* fileName)
{
UI32 dirCluster;
DIR_ENTRY dirEntry;
FILE *fp;
fp = &file;
fp->feof = 0; //mark not end of file
fp->currentSectorInCluster = 0; //1st sector in cluster
fp->byteNum = 0; //1st byte
fp->bufferedWords = 0; //read buffer empty
fp->bufferIdx = 0; //point to start of buffer
//Get the root directory start cluster
dirCluster = FAT32.root_begin_cluster;
if(dirCluster == 0xFFFFFFFF)
{
//could not open directory
return 0;
}
else
{
//Get to file record of the required file from the directory
if(GetMatchingRecord(dirCluster, fileName, &dirEntry) != 0)
{
//did not find the required file
return 0;
}
else
{
//update file pointer members
fp->startCluster = dirEntry.FirstCluster;
fp->currentCluster = dirEntry.FirstCluster;
fp->fileSize = dirEntry.FileSize;
}
}
return fp;
}
//reads next sector from the file stream into the given buffer.
int fread_sector(FILE *fp, void* buffer, int* pBytesRead)
{
UI32 LBAtoRead;
if(fp->feof)
{
*pBytesRead = 0;
return -1; //already end of file.
}
// Get LBA of sector to read = cluster start LBA address + sector offset
LBAtoRead = FAT32_GetStartLBAofCluster(fp->currentCluster) + fp->currentSectorInCluster;
//increment sector
fp->currentSectorInCluster++;
*pBytesRead = 512; //will change it if last sector of file.
if(fp->currentSectorInCluster == FAT32.sectors_per_cluster)
{
//all sectors in current cluster exhausted.. find next cluster
//reset parameters
fp->currentSectorInCluster = 0;
//find next cluster
fp->currentCluster = FAT32_FindNextCluster(fp->currentCluster);
if(fp->currentCluster == 0xFFFFFFFF)
{
//got end of file
fp->feof = 1; //mark EOF flag
//bytesRead will be <= 512
*pBytesRead = fp->fileSize - fp->byteNum;
}
}
//read the sector into buffer
if(CF_ReadSector(LBAtoRead, buffer))
return -2; //error reading sector
else
{
fp->byteNum += *pBytesRead;
return 0; //success
}
}
//returns number of words read
int fread(FILE *fp, void* buffer, int wordsToRead)
{
static UI databuf[256]; //data buffer used by fread()
UI* ptr;
int wordsRead = 0;
int bytesRead;
UI word;
ptr = (UI*)buffer;
if(fp->feof && (fp->bufferedWords == 0))
{
return 0; //already end of file.
}
while(wordsRead < wordsToRead)
{
if(fp->bufferedWords == 0)
{
//read buffer empty..so refill it
if(fread_sector(fp, databuf, &bytesRead))
{
//error or EOF
break;
}
fp->bufferedWords = bytesRead/2;
fp->bufferIdx = 0;
}
word = databuf[fp->bufferIdx++];
*ptr++ = (word>>8)&0xFF | (word<<8)&0xFF00; //swap bytes in word
fp->bufferedWords--;
wordsRead++;
}
return wordsRead;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -