/* 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