/** * Copyright (c) 2011-2022 Bill Greiman * This file is part of the SdFat library for SD memory cards. * * MIT License * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #define DBG_FILE "ExFatName.cpp" #include "../common/DebugMacros.h" #include "../common/FsUtf.h" #include "../common/upcase.h" #include "ExFatLib.h" //------------------------------------------------------------------------------ static char toUpper(char c) { return 'a' <= c && c <= 'z' ? c - 'a' + 'A' : c; } //------------------------------------------------------------------------------ inline uint16_t exFatHash(char c, uint16_t hash) { uint8_t u = toUpper(c); hash = ((hash << 15) | (hash >> 1)) + u; hash = ((hash << 15) | (hash >> 1)); return hash; } //------------------------------------------------------------------------------ inline uint16_t exFatHash(uint16_t u, uint16_t hash) { uint16_t c = toUpcase(u); hash = ((hash << 15) | (hash >> 1)) + (c & 0XFF); hash = ((hash << 15) | (hash >> 1)) + (c >> 8); return hash; } //------------------------------------------------------------------------------ bool ExFatFile::cmpName(const DirName_t* dirName, ExName_t* fname) { for (uint8_t i = 0; i < 15; i++) { uint16_t u = getLe16(dirName->unicode + 2 * i); if (fname->atEnd()) { return u == 0; } #if USE_UTF8_LONG_NAMES uint16_t cp = fname->get16(); if (toUpcase(cp) != toUpcase(u)) { return false; } #else // USE_UTF8_LONG_NAMES char c = fname->getch(); if (u >= 0x7F || toUpper(c) != toUpper(u)) { return false; } #endif // USE_UTF8_LONG_NAMES } return true; } //------------------------------------------------------------------------------ size_t ExFatFile::getName7(char* name, size_t count) { DirName_t* dn; size_t n = 0; if (!isOpen()) { DBG_FAIL_MACRO; goto fail; } for (uint8_t is = 2; is <= m_setCount; is++) { dn = reinterpret_cast(dirCache(is, FsCache::CACHE_FOR_READ)); if (!dn || dn->type != EXFAT_TYPE_NAME) { DBG_FAIL_MACRO; goto fail; } for (uint8_t in = 0; in < 15; in++) { uint16_t c = getLe16(dn->unicode + 2 * in); if (c == 0) { goto done; } if ((n + 1) >= count) { DBG_FAIL_MACRO; goto fail; } name[n++] = c < 0X7F ? c : '?'; } } done: name[n] = 0; return n; fail: *name = 0; return 0; } //------------------------------------------------------------------------------ size_t ExFatFile::getName8(char* name, size_t count) { char* end = name + count; char* str = name; char* ptr; DirName_t* dn; uint16_t hs = 0; uint32_t cp; if (!isOpen()) { DBG_FAIL_MACRO; goto fail; } for (uint8_t is = 2; is <= m_setCount; is++) { dn = reinterpret_cast(dirCache(is, FsCache::CACHE_FOR_READ)); if (!dn || dn->type != EXFAT_TYPE_NAME) { DBG_FAIL_MACRO; goto fail; } for (uint8_t in = 0; in < 15; in++) { uint16_t c = getLe16(dn->unicode + 2 * in); if (hs) { if (!FsUtf::isLowSurrogate(c)) { DBG_FAIL_MACRO; goto fail; } cp = FsUtf::u16ToCp(hs, c); hs = 0; } else if (!FsUtf::isSurrogate(c)) { if (c == 0) { goto done; } cp = c; } else if (FsUtf::isHighSurrogate(c)) { hs = c; continue; } else { DBG_FAIL_MACRO; goto fail; } // Save space for zero byte. ptr = FsUtf::cpToMb(cp, str, end - 1); if (!ptr) { DBG_FAIL_MACRO; goto fail; } str = ptr; } } done: *str = '\0'; return str - name; fail: *name = 0; return 0; } //------------------------------------------------------------------------------ bool ExFatFile::hashName(ExName_t* fname) { uint16_t hash = 0; fname->reset(); #if USE_UTF8_LONG_NAMES fname->nameLength = 0; while (!fname->atEnd()) { uint16_t u = fname->get16(); if (u == 0XFFFF) { DBG_FAIL_MACRO; goto fail; } hash = exFatHash(u, hash); fname->nameLength++; } #else // USE_UTF8_LONG_NAMES while (!fname->atEnd()) { // Convert to byte for smaller exFatHash. char c = fname->getch(); hash = exFatHash(c, hash); } fname->nameLength = fname->end - fname->begin; #endif // USE_UTF8_LONG_NAMES fname->nameHash = hash; if (!fname->nameLength || fname->nameLength > EXFAT_MAX_NAME_LENGTH) { DBG_FAIL_MACRO; goto fail; } return true; fail: return false; }