/* FatLib Library * Copyright (C) 2012 by William Greiman * * This file is part of the FatLib Library * * This Library 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 3 of the License, or * (at your option) any later version. * * This Library 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 the FatLib Library. If not, see * . */ #ifndef DOXYGEN_SHOULD_SKIP_THIS #include "FatFile.h" bool FatFile::findSfn(uint8_t sfn[11], uint16_t* index) { uint16_t free = 0XFFFF; uint16_t idx; dir_t* dir; if (!isDir()) { DBG_FAIL_MACRO; goto fail; } rewind(); while (m_curPosition < m_fileSize) { idx = m_curPosition/32; if ((0XF & idx) == 0) { dir = readDirCache(); if (!dir) { DBG_FAIL_MACRO; goto fail; } } else { m_curPosition += 32; dir++; } // done if last entry if (dir->name[0] == DIR_NAME_FREE || dir->name[0] == DIR_NAME_DELETED) { if (free == 0XFFFF) free = idx; if (dir->name[0] == DIR_NAME_FREE) goto fail; } else if (DIR_IS_FILE_OR_SUBDIR(dir)) { if (!memcmp(sfn, dir->name, 11)) { *index = idx; return true; } } } fail: *index = free; return false; } //------------------------------------------------------------------------------ bool FatFile::createLfn(FatFile* dirFile, uint16_t bgnIndex, char* name, uint8_t oflag) { return false; } //------------------------------------------------------------------------------ bool FatFile::findLfn(const char* name, uint16_t *bgnIndex, uint16_t* endIndex) { bool fill; bool haveLong = false; uint8_t ndir; uint8_t test; uint16_t lfnBgn; uint16_t curIndex = 0XFFFF; uint16_t freeIndex = 0XFFFF; uint8_t freeCount = 0; uint8_t freeNeed; dir_t* dir; size_t len; bool is83; bool foundFree = false; const char* ptr; uint8_t name83[11]; if (!isDir()) { DBG_FAIL_MACRO; goto fail; } is83 = make83Name(name, name83, &ptr); for (len = 0; name[len] !=0 && name[len] != '/'; len++) {} // Assume LFN. freeNeed = (len + 12)/13 + 1; rewind(); while (1) { curIndex = m_curPosition/32; if (m_curPosition == m_fileSize) { DBG_FAIL_MACRO; goto fail; } // read entry into cache dir = readDirCache(); if (!dir) { DBG_FAIL_MACRO; goto fail; } #if 1 if (dir->name[0] == DIR_NAME_DELETED) { if (!foundFree) { if (freeIndex == 0XFFFF) { freeIndex = curIndex; freeCount = 0; } if (++freeCount == freeNeed) { foundFree = true; } } continue; } else { if (!foundFree) freeIndex = 0XFFFF; } #endif if (dir->name[0] == DIR_NAME_FREE) { DBG_FAIL_MACRO; goto fail; } // skip empty slot or '.' or '..' if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') { haveLong = false; continue; } if (DIR_IS_LONG_NAME(dir)) { ldir_t *ldir = reinterpret_cast(dir); if (!haveLong) { if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) continue; ndir = ldir->ord & ~LDIR_ORD_LAST_LONG_ENTRY; if (ndir < 1 || ndir > 20) continue; test = ldir->chksum; haveLong = true; lfnBgn = curIndex; fill = true; } else if (ldir->ord != --ndir || test != ldir->chksum) { haveLong = false; continue; } size_t nOff = 13*(ndir -1); for (int i = 12; i >= 0; i--) { uint16_t u = lfnChar(ldir, i); if (fill) { if (u == 0 || u == 0XFFFF) { continue; } if (len != (nOff + i +1)) { haveLong = false; break; } fill = false; } if (u > 255 || toupper(u) != toupper(name[nOff + i])) { haveLong = false; break; } } } else if (DIR_IS_FILE_OR_SUBDIR(dir)) { if (haveLong) { uint8_t sum = 0; for (uint8_t i = 0; i < 11; i++) { sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir->name[i]; } if (sum != test || ndir != 1) { haveLong = false; } } if (haveLong) goto done; if (is83 && !memcmp(dir->name, name83, sizeof(name83))) { goto done; } } else { haveLong = false; } } done: *bgnIndex = haveLong ? lfnBgn : curIndex; *endIndex = curIndex; return true; fail: *bgnIndex = foundFree ? freeIndex : curIndex; return false; } //------------------------------------------------------------------------------ int FatFile::openNextLFN(FatFile* dirFile, char* name, size_t size, uint8_t oflag) { bool fill; bool haveLong = false; size_t lfnIn; uint8_t ndir; uint8_t test; dir_t* dir; uint16_t index; int rtn; // Check for valid directory and file is not open. if (!dirFile->isDir() || isOpen() || size < 13) { DBG_FAIL_MACRO; goto fail; } while (1) { // Check for EOF. if (dirFile->curPosition() == dirFile->fileSize()) goto done; index = dirFile->curPosition()/32; // read entry into cache dir = dirFile->readDirCache(); if (!dir) { DBG_FAIL_MACRO; goto fail; } // done if last entry if (dir->name[0] == DIR_NAME_FREE) { DBG_FAIL_MACRO; return 0; } // skip empty slot or '.' or '..' if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') { haveLong = false; continue; } if (DIR_IS_LONG_NAME(dir)) { ldir_t *ldir = reinterpret_cast(dir); if (!haveLong) { if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) continue; ndir = ldir->ord & ~LDIR_ORD_LAST_LONG_ENTRY; if (ndir < 1 || ndir > 20) continue; test = ldir->chksum; haveLong = true; rtn = 0; fill = true; lfnIn = 13*ndir; } else if (ldir->ord != --ndir || test != ldir->chksum) { haveLong = false; continue; } for (int i = 12; i >= 0; i--) { uint16_t u = lfnChar(ldir, i); if (fill) { if (rtn == 0 && u != 0 && u != 0XFFFF) rtn = lfnIn; if (u == 0 || u == 0XFFFF || lfnIn >= size) { lfnIn--; continue; } name[lfnIn] = 0; fill = false; } if (lfnIn == 0 || u > 255) { haveLong = false; break; } name[--lfnIn] = u; } } else if (DIR_IS_FILE_OR_SUBDIR(dir)) { if (haveLong) { uint8_t sum = 0; for (uint8_t i = 0; i < 11; i++) { sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + dir->name[i]; } if (sum != test || ndir != 1) { haveLong = false; } } if (!haveLong) { rtn = dirName(dir, name); if (dir->reservedNT) { uint8_t lowerTest = 0X08; for (char *ptr = name; *ptr; ptr++) { if (*ptr == '.') { lowerTest = 0X10; continue; } if (dir->reservedNT & lowerTest) { *ptr = tolower(*ptr); } } } } if (!openCachedEntry(dirFile, index, oflag)) { DBG_FAIL_MACRO; goto fail; } return rtn; } else { haveLong = false; } } done: return 0; fail: return -1; } #endif // DOXYGEN_SHOULD_SKIP_THIS