⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fat.c

📁 这项工程将让您把自己的MP3播放器平台
💻 C
📖 第 1 页 / 共 4 页
字号:
  // If the required FAT sector isn't already in memory, then read it...
  ASSERT((lFATSector != 0),("FAT sector cannot be zero!"));
  if (lFATSector != m_lCurFATSector) {
    if (!ReadSector(lFATSector, (PXBYTE) &m_awCurFAT)) {
      DBGOUT(("NextCluster: Error reading FAT sector %ld\n", lFATSector));
      return EOF_CLUSTER;
    }
    //DBGOUT(("NextCluster: Read FAT sector %ld ...\n", lFATSector));
    m_lCurFATSector = lFATSector;
  }

  // The rest is easy!
  return WSWAP(m_awCurFAT[bFATOffset]);
}


//++
//   This routine will set up the current file data (m_?CurFile???) to the beginning
// of the file entry specified.  The code can then read this file, one sector at
// a time, by calling ReadFile().  Note that this code isn't re-entrant, and there
// is only one set of current file data, so only one file can be opened for reading
// at a time.  In an MP3 player, that isn't a problem...
//--
PUBLIC void OpenFile (PXDIRENT pxDirEnt)
{
  LONG lTemp;
  m_wCurFileCluster = WSWAP(pxDirEnt->wFirstCluster);
  m_lCurFileSector = SectorFromCluster(m_wCurFileCluster);
  m_nRelFileSector = -1;
  lTemp = pxDirEnt->lFileSize;  m_lFileBytesLeft = LSWAP(lTemp);
  //DBGOUT(("OpenFile: reading file \"%8.8s.%3.3s\",", &(pxDirEnt->szFileName), &(pxDirEnt->szFileType)));
  //DBGOUT((" starting LBN=%ld, file size=%ld\n", m_lCurFileSector, m_lFileBytesLeft));
}

//++
//   This routine will find the next sector in the currently open file.  If
// all the sectors in the current cluster have been read, then the FAT will
// be consulted to find the next sector in the file.  If there are no more
// clusters (i.e. the FAT entry is EOF_CLUSTER), then FALSE is returned.
// This last condition can't be used as an indication of end-of-file, however,
// because files rarely if ever exactly fill a cluster.  The application must
// keep count of the number of bytes read and use the file size from the
// directory entry to determine EOF instead.
//--
PRIVATE BOOL NextFileSector (void)
{
  //   Note that OpenFile() sets nRelSector to -1, so the first time this
  // routine is called we'll end up reading the first sector in the file...
  if (m_wCurFileCluster == EOF_CLUSTER) return FALSE;
  if (++m_nRelFileSector >= m_bVolClusterSize) {
    m_nRelFileSector = 0;
    m_wCurFileCluster = NextCluster(m_wCurFileCluster);
    if (m_wCurFileCluster == EOF_CLUSTER) return FALSE;
    m_lCurFileSector = SectorFromCluster(m_wCurFileCluster);
  }
  return TRUE;
}

//++
//   This routine reads the currently opened file (remember that there can be
// only one file open at a time!) sector by sector.  The pxBuffer parameter
// should point to a 512 byte buffer, and it will return the number of bytes
// actually read.  Normally this will be 512, however it'll be less when we
// reach the last block in the file.
//--
PUBLIC WORD ReadFile (PXBYTE pxBuffer)
{
  LONG lSector;
  // If there are no bytes left in this file, then we always fail...
  if (m_lFileBytesLeft == 0) return 0;

  // We should never find EOF before the byte count reaches zero!
  VERIFY( (NextFileSector()), ("ReadFile: EOF_CLUSTER found before byte count = 0\n") );

  //   Now we can read the sector.  If this fails for some reason (it shouldn't!)
  // the return zero and fake EOF...
  lSector = m_lCurFileSector + (LONG) (m_nRelFileSector);
  if (!ReadSector(lSector, pxBuffer)) {
    DBGOUT(("ReadFile: error reading sector %ld from current file!\n", lSector));
    return 0;
  }

  //   We've read another sector, so decrement the number of bytes left in the
  // file accordingly.  If the number of bytes left is currently less than 512,
  // then we've only read a partial sector (the last sector of the file wasn't
  // full) and we have to zero the bytes left and return the appropriate count.
  if (m_lFileBytesLeft >= IDE_SECTOR_SIZE) {
    m_lFileBytesLeft -= IDE_SECTOR_SIZE;  return IDE_SECTOR_SIZE;
  } else {
    LONG lTemp = m_lFileBytesLeft;  m_lFileBytesLeft = 0;
    return lTemp;
  }
}

//++
//   This routine will read the last cbBuffer bytes from the end of the currently
// opened file.  Ordinarily you'd do an lseek() and then a read(), but, of course,
// we have no lseek() here.  This is a rather esoteric function, but the purpose
// is obvious - it's used to read ID3 tags!
//
//   The bad thing about a FAT file system is that there's no way to find the last
// cluster in a file except by following the entire cluster chain from the start. 
// Unfortunately, there's just no way to make this efficient.  With FAT16 a typical
// 512Mb CompactFlash card will have 8K byte sectors (16K byte for a 1Gb card) and
// at that rate, a typical 2 or 3Mb MP3 file will contain 300 to 400 clusters.  With
// hundreds of clusters involved, finding the end of the file can take a long time.
//
//   Notice that we need a temporary disk buffer for reading sectors from the MP3
// file.  We pull one off the free buffer list, but we're careful to always return
// it before leaving!
//--
PUBLIC BOOL ReadFileEnd (PXBYTE pxBuffer, WORD cbBuffer) STACKSLOCS
{
  WORD wCount;  LONG lClusterSize, lSizeLimit;  PIBCB pBCB;
  ALLOCATE_BUFFER(pBCB);
  if (pBCB == NULL) return FALSE;

  //   First, we want to get as close as we can to the end of the file with
  // out actually passing the ID3 tag.  Remember that there's a possibility
  // that the ID3 tag might be split across the last two sectors in the file,
  // and if that happens there's an even smaller possibility that the last
  // two sectors might be in different clusters!  But we know that as long as
  // there are at least the cluster size plus the tag size bytes left in the
  // file, there's no way we could have passed it.
  //
  //   The lSizeLimit variable is just an optimization because the compiler
  // isn't smart enough to factor out the calculation from the while loop.
  // Remember that on an 8051, LONGs are quadruple precision arithmetic!
  lClusterSize = (LONG) m_bVolClusterSize * (LONG) IDE_SECTOR_SIZE;
  lSizeLimit = lClusterSize + cbBuffer;
  while (m_lFileBytesLeft >= lSizeLimit) {
    m_wCurFileCluster = NextCluster(m_wCurFileCluster);
    ASSERT( (m_wCurFileCluster != EOF_CLUSTER), ("ReadFileEnd: Premature EOF cluster\n") );
    m_lFileBytesLeft -= (LONG) lClusterSize;
  }
  //  Be sure that the rest of the m_CurFile block, especially the current
  // sector information, is valid before we proceed.  Otherwise ReadFile()
  // will crash and burn horribly...
  m_nRelFileSector = -1;
  m_lCurFileSector = SectorFromCluster(m_wCurFileCluster);

  //   Now find the last (or the second to the last, if the tag is split) sector
  // in the file.  This loop is even slower than the last one, but unlike the
  // last one, which can execute hundreds of times, this one never executes more
  // than fifteen times (assuming 8K clusters).
  while (m_lFileBytesLeft >= (IDE_SECTOR_SIZE+cbBuffer)) {
    VERIFY ( (NextFileSector()), ("ReadFileEnd: Premature EOF sector\n") );
    m_lFileBytesLeft -= IDE_SECTOR_SIZE;
  }

  // Ok, we're there.  Read at least the first part of the tag into the buffer.
  wCount = ReadFile(pBCB->pbBuffer);
  ASSERT( (wCount > 0), ("ReadFileEnd: Failed to read last chunk in file\n") );
  if (wCount == 0) {RELEASE_BUFFER(pBCB);  return FALSE;}

  //   If that last ReadFile() reached the end of the file, then we know
  // that we have the ID3 tag in the buffer now.  All we need to do is find
  // it and copy it to the ID3 tag buffer.  However, if there are still bytes
  // left in the file then we know we have only part of the tag and we must
  // do another ReadFile() to get the rest.
  if (m_lFileBytesLeft == 0) {
    // The easy case - we got the whole tag in one sector...
    ASSERT( (wCount >= cbBuffer), ("ReadFileEnd: wCount < cbBuffer\n") );
    memcpy(pxBuffer, pBCB->pbBuffer+(wCount-cbBuffer), cbBuffer);
  } else {
    //   This tag is split across the last two sectors in the file.  Figure out
    // how many bytes (of the tag) we got in this sector and extract those first.
    WORD wFragmentSize;
    //DBGOUT(("ReadFileEnd: fragmented, lBytesLeft=%ld\n", m_lFileBytesLeft));
    ASSERT( (m_lFileBytesLeft < cbBuffer), ("ReadFileEnd: lBytesLeft >= cbBuffer\n") );
    wFragmentSize = cbBuffer - m_lFileBytesLeft;
    memcpy(pxBuffer, pBCB->pbBuffer+IDE_SECTOR_SIZE-wFragmentSize, wFragmentSize);
    //   And then do another read to get the rest.  Remember that since the
    // ID3 tag is the last thing in the file, ALL the bytes returned by this
    // second ReadFile() must be part of the tag. 
    wCount = ReadFile(pBCB->pbBuffer);
    ASSERT( (wCount > 0), ("ReadFileEnd: Failed to read part 2\n") );
    ASSERT( (m_lFileBytesLeft == 0), ("ReadFileEnd: Second read didn't finish file\n") );
    memcpy(pxBuffer+wFragmentSize, pBCB->pbBuffer, wCount);
  }

  // We can give up the temporary buffer now ....
  RELEASE_BUFFER(pBCB);
  return TRUE;
}

//++
//   This routine exists only for completeness in abstracting the file system
// layer.  In this particular implementation, it doesn't do much.
//--
PUBLIC void CloseFile (void)
{
  m_wCurFileCluster = 0;  m_nRelFileSector = 0;
  m_lCurFileSector = m_lFileBytesLeft = 0;
  //DBGOUT(("CloseFile: ...\n"));
}


//++
//   This routine reads the current compact flash card to see if it contains
// a valid FAT16 file system and, if it does, it sets up the volume data
// globals with information we'll need to access this volume in the future.
// If the current CF card DOESN'T contain a FAT16 file system, then this
// function returns FALSE...
//--
PUBLIC BOOL InitializeFAT (void)
{
  //   Initialize all the local data structures.  Notice that this code is a
  // little careless because it simply initializes both m_pCurDirBCB and
  // m_pCurFATBCB to NULL.  It's important (critical!) that both these be
  // initialized, but if InitializeFAT() were ever to be called more than
  // once (say, if we actually supported hot swapping CF cards) then this
  // would cause a big time memory leak since we'd just be throwing away
  // any buffer that had been previously allocated.  At the moment, though,
  // InitializeFAT() is only ever called once, so this isn't a problem.
  memset(g_szSystemType, 0, SYSTEM_TYPE_LENGTH);
  memset(g_szVolumeLabel, 0, VOLUME_LABEL_LENGTH);
  g_wTotalMP3Files = 0;
  // Reset all the m_?VolData* variables ...
  m_lVolFATOffset = m_lVolRootOffset =  m_lVolDataOffset = 0;
  m_lVolFATSize = m_lVolRootSize = 0;  m_bVolClusterSize = 0;
  // Reset all the m_?CurDir* variables ...
  m_lCurDirSector = 0;  m_pCurDirBCB = NULL;
  m_bCurDirEntry = DIRECTORY_ENTRIES_PER_SECTOR;
  // Reset all the m_?CurFAT* variables ...
  m_lCurFATSector = 0;  memset(m_awCurFAT, 0, sizeof(m_awCurFAT));
  // Reset all the current file variables...
  m_wCurFileCluster = 0;  m_nRelFileSector = 0;
  m_lCurFileSector = m_lFileBytesLeft = 0;

  //  The next step is to find the volume boot sector (aka VBS).  Experimentally
  // is seems like Windows formats any removable media device, regardless of the
  // size, as if it were a big floppy disk.  This means that the VBS goes in
  // sector zero of the device.  However, there's nothing that prevents someone
  // from running FDISK on a compact flash drive, and will write a Master Boot
  // Record (aka MBR) to sector zero instead.  In this case the MBR contains a
  // partition table, the partition table points to the first sector of each
  // logical volume, and THAT sector then contains the VBS (there's a separate
  // VBS for every partition).
  if (!ReadVBS(ReadMBR())) return FALSE;
  DBGOUT(("Found file system type \"%s\" ...\n", g_szSystemType));

  return TRUE;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -