2005-09-08 00:09:32 +00:00
|
|
|
/* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
2004-05-31 19:33:59 +00:00
|
|
|
* FILE: lib/rtl/dos8dot3.c
|
|
|
|
* PURPOSE: Short name (8.3 name) functions
|
|
|
|
* PROGRAMMER: Eric Kohl
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
2005-07-26 08:39:07 +00:00
|
|
|
#include <rtl.h>
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* CONSTANTS *****************************************************************/
|
|
|
|
|
2011-09-16 20:53:16 +00:00
|
|
|
const PCHAR RtlpShortIllegals = ";+=[],\"*\\<>/?:|";
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
|
|
|
static BOOLEAN
|
|
|
|
RtlpIsShortIllegal(CHAR Char)
|
|
|
|
{
|
|
|
|
return strchr(RtlpShortIllegals, Char) ? TRUE : FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static USHORT
|
|
|
|
RtlpGetCheckSum(PUNICODE_STRING Name)
|
|
|
|
{
|
|
|
|
USHORT Hash = 0;
|
|
|
|
ULONG Length;
|
|
|
|
PWCHAR c;
|
|
|
|
|
|
|
|
Length = Name->Length / sizeof(WCHAR);
|
|
|
|
c = Name->Buffer;
|
|
|
|
while(Length--)
|
|
|
|
{
|
|
|
|
Hash = (Hash + (*c << 4) + (*c >> 4)) * 11;
|
|
|
|
c++;
|
|
|
|
}
|
|
|
|
return Hash;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ULONG
|
|
|
|
RtlpGetIndexLength(ULONG Index)
|
|
|
|
{
|
|
|
|
ULONG Length = 0;
|
|
|
|
while (Index)
|
|
|
|
{
|
|
|
|
Index /= 10;
|
|
|
|
Length++;
|
|
|
|
}
|
|
|
|
return Length ? Length : 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
|
|
|
*/
|
2005-10-19 17:03:38 +00:00
|
|
|
VOID NTAPI
|
2004-05-31 19:33:59 +00:00
|
|
|
RtlGenerate8dot3Name(IN PUNICODE_STRING Name,
|
|
|
|
IN BOOLEAN AllowExtendedCharacters,
|
|
|
|
IN OUT PGENERATE_NAME_CONTEXT Context,
|
|
|
|
OUT PUNICODE_STRING Name8dot3)
|
|
|
|
{
|
|
|
|
ULONG Count;
|
|
|
|
WCHAR NameBuffer[8];
|
|
|
|
WCHAR ExtBuffer[4];
|
|
|
|
ULONG StrLength;
|
|
|
|
ULONG NameLength;
|
|
|
|
ULONG ExtLength;
|
|
|
|
ULONG CopyLength;
|
|
|
|
ULONG DotPos;
|
|
|
|
ULONG i, j;
|
|
|
|
ULONG IndexLength;
|
|
|
|
ULONG CurrentIndex;
|
|
|
|
USHORT Checksum;
|
|
|
|
CHAR c;
|
|
|
|
|
|
|
|
StrLength = Name->Length / sizeof(WCHAR);
|
2005-12-08 23:44:31 +00:00
|
|
|
DPRINT("StrLength: %lu\n", StrLength);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
/* Find last dot in Name */
|
2009-02-25 22:30:17 +00:00
|
|
|
DotPos = StrLength;
|
2004-05-31 19:33:59 +00:00
|
|
|
for (i = 0; i < StrLength; i++)
|
|
|
|
{
|
|
|
|
if (Name->Buffer[i] == L'.')
|
|
|
|
{
|
|
|
|
DotPos = i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-12-08 23:44:31 +00:00
|
|
|
DPRINT("DotPos: %lu\n", DotPos);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
/* Copy name (6 valid characters max) */
|
|
|
|
for (i = 0, NameLength = 0; NameLength < 6 && i < DotPos; i++)
|
|
|
|
{
|
|
|
|
c = 0;
|
|
|
|
RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
|
|
|
|
if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
|
|
|
|
{
|
|
|
|
NameBuffer[NameLength++] = L'_';
|
|
|
|
}
|
2011-09-16 20:53:16 +00:00
|
|
|
else if (c != '.' && c != ' ')
|
2004-05-31 19:33:59 +00:00
|
|
|
{
|
|
|
|
NameBuffer[NameLength++] = (WCHAR)c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINT("NameBuffer: '%.08S'\n", NameBuffer);
|
2005-12-08 23:44:31 +00:00
|
|
|
DPRINT("NameLength: %lu\n", NameLength);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
/* Copy extension (4 valid characters max) */
|
|
|
|
if (DotPos < StrLength)
|
|
|
|
{
|
|
|
|
for (i = DotPos, ExtLength = 0; ExtLength < 4 && i < StrLength; i++)
|
|
|
|
{
|
|
|
|
c = 0;
|
|
|
|
RtlUpcaseUnicodeToOemN(&c, sizeof(CHAR), &Count, &Name->Buffer[i], sizeof(WCHAR));
|
2011-09-20 17:33:51 +00:00
|
|
|
if (Count != 1 || c == 0 || RtlpIsShortIllegal(c))
|
2004-05-31 19:33:59 +00:00
|
|
|
{
|
|
|
|
ExtBuffer[ExtLength++] = L'_';
|
|
|
|
}
|
2011-09-16 20:53:16 +00:00
|
|
|
else if (c != ' ')
|
2004-05-31 19:33:59 +00:00
|
|
|
{
|
|
|
|
ExtBuffer[ExtLength++] = c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ExtLength = 0;
|
|
|
|
}
|
|
|
|
DPRINT("ExtBuffer: '%.04S'\n", ExtBuffer);
|
2005-12-08 23:44:31 +00:00
|
|
|
DPRINT("ExtLength: %lu\n", ExtLength);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
/* Determine next index */
|
|
|
|
IndexLength = RtlpGetIndexLength(Context->LastIndexValue);
|
|
|
|
if (Context->CheckSumInserted)
|
|
|
|
{
|
|
|
|
CopyLength = min(NameLength, 8 - 4 - 1 - IndexLength);
|
|
|
|
Checksum = RtlpGetCheckSum(Name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CopyLength = min(NameLength, 8 - 1 - IndexLength);
|
|
|
|
Checksum = 0;
|
|
|
|
}
|
|
|
|
|
2005-12-08 23:44:31 +00:00
|
|
|
DPRINT("CopyLength: %lu\n", CopyLength);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
if ((Context->NameLength == CopyLength) &&
|
|
|
|
(wcsncmp(Context->NameBuffer, NameBuffer, CopyLength) == 0) &&
|
|
|
|
(Context->ExtensionLength == ExtLength) &&
|
|
|
|
(wcsncmp(Context->ExtensionBuffer, ExtBuffer, ExtLength) == 0) &&
|
|
|
|
(Checksum == Context->Checksum) &&
|
|
|
|
(Context->LastIndexValue < 999))
|
|
|
|
{
|
|
|
|
Context->LastIndexValue++;
|
|
|
|
if (Context->CheckSumInserted == FALSE &&
|
|
|
|
Context->LastIndexValue > 9)
|
|
|
|
{
|
|
|
|
Context->CheckSumInserted = TRUE;
|
|
|
|
Context->LastIndexValue = 1;
|
|
|
|
Context->Checksum = RtlpGetCheckSum(Name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Context->LastIndexValue = 1;
|
|
|
|
Context->CheckSumInserted = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
IndexLength = RtlpGetIndexLength(Context->LastIndexValue);
|
|
|
|
|
2005-12-08 23:44:31 +00:00
|
|
|
DPRINT("CurrentIndex: %lu, IndexLength %lu\n", Context->LastIndexValue, IndexLength);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
if (Context->CheckSumInserted)
|
|
|
|
{
|
|
|
|
CopyLength = min(NameLength, 8 - 4 - 1 - IndexLength);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CopyLength = min(NameLength, 8 - 1 - IndexLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build the short name */
|
|
|
|
memcpy(Name8dot3->Buffer, NameBuffer, CopyLength * sizeof(WCHAR));
|
|
|
|
j = CopyLength;
|
|
|
|
if (Context->CheckSumInserted)
|
|
|
|
{
|
|
|
|
j += 3;
|
|
|
|
Checksum = Context->Checksum;
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
Name8dot3->Buffer[j--] = (Checksum % 16) > 9 ? (Checksum % 16) + L'A' - 10 : (Checksum % 16) + L'0';
|
|
|
|
Checksum /= 16;
|
|
|
|
}
|
|
|
|
j = CopyLength + 4;
|
|
|
|
}
|
|
|
|
Name8dot3->Buffer[j++] = L'~';
|
|
|
|
j += IndexLength - 1;
|
|
|
|
CurrentIndex = Context->LastIndexValue;
|
|
|
|
for (i = 0; i < IndexLength; i++)
|
|
|
|
{
|
|
|
|
Name8dot3->Buffer[j--] = (CurrentIndex % 10) + L'0';
|
|
|
|
CurrentIndex /= 10;
|
|
|
|
}
|
|
|
|
j += IndexLength + 1;
|
|
|
|
|
|
|
|
memcpy(Name8dot3->Buffer + j, ExtBuffer, ExtLength * sizeof(WCHAR));
|
2011-09-20 17:33:51 +00:00
|
|
|
Name8dot3->Length = (USHORT)(j + ExtLength) * sizeof(WCHAR);
|
2004-05-31 19:33:59 +00:00
|
|
|
|
|
|
|
DPRINT("Name8dot3: '%wZ'\n", Name8dot3);
|
|
|
|
|
|
|
|
/* Update context */
|
2011-09-20 17:33:51 +00:00
|
|
|
Context->NameLength = (UCHAR)CopyLength;
|
2004-05-31 19:33:59 +00:00
|
|
|
Context->ExtensionLength = ExtLength;
|
|
|
|
memcpy(Context->NameBuffer, NameBuffer, CopyLength * sizeof(WCHAR));
|
|
|
|
memcpy(Context->ExtensionBuffer, ExtBuffer, ExtLength * sizeof(WCHAR));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* @implemented
|
2013-02-16 18:46:36 +00:00
|
|
|
* Note: the function does not conform to the annotations.
|
|
|
|
* SpacesFound is not always set!
|
2004-05-31 19:33:59 +00:00
|
|
|
*/
|
2013-02-16 18:46:36 +00:00
|
|
|
_IRQL_requires_max_(PASSIVE_LEVEL)
|
|
|
|
_Must_inspect_result_
|
|
|
|
NTSYSAPI
|
2006-01-03 21:34:19 +00:00
|
|
|
BOOLEAN
|
|
|
|
NTAPI
|
2013-02-16 18:46:36 +00:00
|
|
|
RtlIsNameLegalDOS8Dot3 (
|
|
|
|
_In_ PCUNICODE_STRING Name,
|
|
|
|
_Inout_opt_ POEM_STRING OemName,
|
|
|
|
_Out_opt_ PBOOLEAN NameContainsSpaces)
|
2004-05-31 19:33:59 +00:00
|
|
|
{
|
2007-09-17 19:51:32 +00:00
|
|
|
static const char Illegal[] = "*?<>|\"+=,;[]:/\\\345";
|
|
|
|
int Dot = -1;
|
|
|
|
int i;
|
|
|
|
char Buffer[12];
|
|
|
|
OEM_STRING OemString;
|
|
|
|
BOOLEAN GotSpace = FALSE;
|
2013-02-16 17:21:34 +00:00
|
|
|
NTSTATUS Status;
|
|
|
|
|
2013-02-16 18:46:36 +00:00
|
|
|
if (!OemName)
|
2007-09-17 19:51:32 +00:00
|
|
|
{
|
|
|
|
OemString.Length = sizeof(Buffer);
|
|
|
|
OemString.MaximumLength = sizeof(Buffer);
|
|
|
|
OemString.Buffer = Buffer;
|
2013-02-16 18:46:36 +00:00
|
|
|
OemName = &OemString;
|
2007-09-17 19:51:32 +00:00
|
|
|
}
|
2013-02-16 17:21:34 +00:00
|
|
|
|
2013-02-16 18:46:36 +00:00
|
|
|
Status = RtlUpcaseUnicodeStringToCountedOemString(OemName, Name, FALSE);
|
2013-02-16 17:21:34 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2007-09-17 19:51:32 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2013-02-16 18:46:36 +00:00
|
|
|
if ((OemName->Length > 12) || (OemName->Buffer == NULL)) return FALSE;
|
2007-09-17 19:51:32 +00:00
|
|
|
|
|
|
|
/* a starting . is invalid, except for . and .. */
|
2013-02-16 18:46:36 +00:00
|
|
|
if (OemName->Buffer[0] == '.')
|
2007-09-17 19:51:32 +00:00
|
|
|
{
|
2013-02-16 18:46:36 +00:00
|
|
|
if (OemName->Length != 1 && (OemName->Length != 2 || OemName->Buffer[1] != '.')) return FALSE;
|
|
|
|
if (NameContainsSpaces) *NameContainsSpaces = FALSE;
|
2007-09-17 19:51:32 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-02-16 18:46:36 +00:00
|
|
|
for (i = 0; i < OemName->Length; i++)
|
2007-09-17 19:51:32 +00:00
|
|
|
{
|
2013-02-16 18:46:36 +00:00
|
|
|
switch (OemName->Buffer[i])
|
2007-09-17 19:51:32 +00:00
|
|
|
{
|
|
|
|
case ' ':
|
|
|
|
/* leading/trailing spaces not allowed */
|
2013-02-16 18:46:36 +00:00
|
|
|
if (!i || i == OemName->Length-1 || OemName->Buffer[i+1] == '.') return FALSE;
|
2007-09-17 19:51:32 +00:00
|
|
|
GotSpace = TRUE;
|
|
|
|
break;
|
|
|
|
case '.':
|
|
|
|
if (Dot != -1) return FALSE;
|
|
|
|
Dot = i;
|
|
|
|
break;
|
|
|
|
default:
|
2013-02-16 18:46:36 +00:00
|
|
|
if (strchr(Illegal, OemName->Buffer[i])) return FALSE;
|
2007-09-17 19:51:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* check file part is shorter than 8, extension shorter than 3
|
|
|
|
* dot cannot be last in string
|
|
|
|
*/
|
|
|
|
if (Dot == -1)
|
|
|
|
{
|
2013-02-16 18:46:36 +00:00
|
|
|
if (OemName->Length > 8) return FALSE;
|
2007-09-17 19:51:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-02-16 18:46:36 +00:00
|
|
|
if (Dot > 8 || (OemName->Length - Dot > 4) || Dot == OemName->Length - 1) return FALSE;
|
2007-09-17 19:51:32 +00:00
|
|
|
}
|
2013-02-16 18:46:36 +00:00
|
|
|
if (NameContainsSpaces) *NameContainsSpaces = GotSpace;
|
2007-09-17 19:51:32 +00:00
|
|
|
return TRUE;
|
2004-05-31 19:33:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|