Description: Be friendly for other open source projects: work with WINE style namemangling. Patch 3382938 from Andre_H (modified). Origin: upstream, http://sourceforge.net/p/dosbox/code-0/3743/ Author: Peter Veenstra Last-Update: 2011-08-30 --- a/src/dos/drive_cache.cpp +++ b/src/dos/drive_cache.cpp @@ -370,6 +370,60 @@ return false; } +#define WINE_DRIVE_SUPPORT 1 +#if WINE_DRIVE_SUPPORT +//Changes to interact with WINE by supporting their namemangling. +//The code is rather slow, because orglist is unordered, so it needs to be avoided if possible. +//Hence the tests in GetLongFileName + + +// From the Wine project +static Bits wine_hash_short_file_name( char* name, char* buffer ) +{ + static const char hash_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"; + static const char invalid_chars[] = { '*','?','<','>','|','"','+','=',',',';','[',']',' ','\345','~','.',0 }; + char* p; + char* ext; + char* end = name + strlen(name); + char* dst; + unsigned short hash; + int i; + + // Compute the hash code of the file name + for (p = name, hash = 0xbeef; p < end - 1; p++) + hash = (hash<<3) ^ (hash>>5) ^ tolower(*p) ^ (tolower(p[1]) << 8); + hash = (hash<<3) ^ (hash>>5) ^ tolower(*p); // Last character + + + // Find last dot for start of the extension + for (p = name + 1, ext = NULL; p < end - 1; p++) if (*p == '.') ext = p; + + // Copy first 4 chars, replacing invalid chars with '_' + for (i = 4, p = name, dst = buffer; i > 0; i--, p++) + { + if (p == end || p == ext) break; + *dst++ = (*p < 0 || strchr( invalid_chars, *p ) != NULL) ? '_' : toupper(*p); + } + // Pad to 5 chars with '~' + while (i-- >= 0) *dst++ = '~'; + + // Insert hash code converted to 3 ASCII chars + *dst++ = hash_chars[(hash >> 10) & 0x1f]; + *dst++ = hash_chars[(hash >> 5) & 0x1f]; + *dst++ = hash_chars[hash & 0x1f]; + + // Copy the first 3 chars of the extension (if any) + if (ext) + { + *dst++ = '.'; + for (i = 3, ext++; (i > 0) && ext < end; i--, ext++) + *dst++ = (*ext < 0 || strchr( invalid_chars, *ext ) != NULL) ? '_' : toupper(*ext); + } + + return dst - buffer; +} +#endif + Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) { std::vector::size_type filelist_size = curDir->fileList.size(); if (GCC_UNLIKELY(filelist_size<=0)) return -1; @@ -390,6 +444,20 @@ return mid; }; } +#ifdef WINE_DRIVE_SUPPORT + if (strlen(shortName) < 8 || shortName[4] != '~' || shortName[5] == '.' || shortName[6] == '.' || shortName[7] == '.') return -1; // not available + // else it's most likely a Wine style short name ABCD~###, # = not dot (length at least 8) + // The above test is rather strict as the following loop can be really slow if filelist_size is large. + char buff[CROSS_LEN]; + for (Bits i = 0; i < filelist_size; i++) { + res = wine_hash_short_file_name(curDir->fileList[i]->orgname,buff); + if (!strncmp(shortName,buff,res)) + { // Found + strcpy(shortName,curDir->fileList[i]->orgname); + return i; + }; + } +#endif // not available return -1; }