Be friendly for other open source projects: work with WINE style namemangling. Patch 3382938 from Andre_H (modified).
Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@3743
This commit is contained in:
parent
9df334048f
commit
b40ab65dcb
1 changed files with 68 additions and 0 deletions
|
@ -376,6 +376,60 @@ bool DOS_Drive_Cache::RemoveTrailingDot(char* shortname) {
|
|||
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<CFileInfo*>::size_type filelist_size = curDir->fileList.size();
|
||||
if (GCC_UNLIKELY(filelist_size<=0)) return -1;
|
||||
|
@ -396,6 +450,20 @@ Bits DOS_Drive_Cache::GetLongName(CFileInfo* curDir, char* shortName) {
|
|||
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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue