926 lines
22 KiB
C
926 lines
22 KiB
C
/*
|
|
|
|
Copyright (c) 1992 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
macansi.c
|
|
|
|
Abstract:
|
|
|
|
This module contains conversion routines from macintosh ansi to unicode
|
|
and vice versa
|
|
|
|
|
|
Author:
|
|
|
|
Jameel Hyder (microsoft!jameelh)
|
|
|
|
|
|
Revision History:
|
|
10 Jul 1992 Initial Version
|
|
|
|
Notes: Tab stop: 4
|
|
--*/
|
|
|
|
#define _MACANSI_LOCALS
|
|
#define FILENUM FILE_MACANSI
|
|
|
|
#include <afp.h>
|
|
|
|
#define FlagOn(x, y) ((x) & (y))
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( INIT, AfpMacAnsiInit)
|
|
#pragma alloc_text( PAGE, AfpMacAnsiDeInit)
|
|
#pragma alloc_text( PAGE, AfpGetMacCodePage)
|
|
#pragma alloc_text( PAGE, AfpConvertStringToUnicode)
|
|
#pragma alloc_text( PAGE, AfpConvertStringToAnsi)
|
|
#pragma alloc_text( PAGE, AfpConvertStringToMungedUnicode)
|
|
#pragma alloc_text( PAGE, AfpConvertMungedUnicodeToAnsi)
|
|
#pragma alloc_text( PAGE, AfpConvertMacAnsiToHostAnsi)
|
|
#pragma alloc_text( PAGE, AfpConvertHostAnsiToMacAnsi)
|
|
#pragma alloc_text( PAGE, AfpIsLegalShortname)
|
|
#pragma alloc_text( PAGE, AfpIsProperSubstring)
|
|
#endif
|
|
|
|
/*** AfpMacAnsiInit
|
|
*
|
|
* Initialize the code page for macintosh ANSI.
|
|
*/
|
|
NTSTATUS
|
|
AfpMacAnsiInit(
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
int i, SizeAltTbl;
|
|
|
|
// Allocate the table for the alternate unicode characters
|
|
SizeAltTbl = (AFP_INVALID_HIGH - AFP_INITIAL_INVALID_HIGH + 1) * sizeof(WCHAR);
|
|
if ((afpAltUnicodeTable = (PWCHAR)AfpAllocZeroedPagedMemory(SizeAltTbl)) == NULL)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
// Allocate and initialize the table for the reverse mapping table
|
|
SizeAltTbl = (AFP_INVALID_HIGH - AFP_INITIAL_INVALID_HIGH + 1)*sizeof(BYTE);
|
|
if ((afpAltAnsiTable = (PBYTE)AfpAllocZeroedPagedMemory(SizeAltTbl)) == NULL)
|
|
{
|
|
AfpFreeMemory(afpAltUnicodeTable);
|
|
afpAltUnicodeTable = NULL;
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
// Initialize the tables for the alternate unicode characters
|
|
for (i = AFP_INITIAL_INVALID_HIGH + 1; i <= AFP_INVALID_HIGH; i++)
|
|
{
|
|
if (!FsRtlIsAnsiCharacterLegalNtfs((BYTE)i, False))
|
|
{
|
|
afpAltUnicodeTable[i-AFP_INITIAL_INVALID_HIGH] = afpLastAltChar;
|
|
afpAltAnsiTable[afpLastAltChar - (AFP_ALT_UNICODE_BASE + AFP_INITIAL_INVALID_HIGH)] = (BYTE)i;
|
|
afpLastAltChar++;
|
|
}
|
|
}
|
|
|
|
// HACK: Also add in a couple of codes for 'space' and 'period' - they are only
|
|
// used if they are at end. Another one for the 'apple' character
|
|
AfpMungedUnicodeSpace =
|
|
afpAltUnicodeTable[ANSI_SPACE-AFP_INITIAL_INVALID_HIGH] = afpLastAltChar;
|
|
afpAltAnsiTable[afpLastAltChar - (AFP_ALT_UNICODE_BASE + AFP_INITIAL_INVALID_HIGH)] = ANSI_SPACE;
|
|
afpLastAltChar ++;
|
|
|
|
AfpMungedUnicodePeriod =
|
|
afpAltUnicodeTable[ANSI_PERIOD-AFP_INITIAL_INVALID_HIGH] = afpLastAltChar;
|
|
afpAltAnsiTable[afpLastAltChar - (AFP_ALT_UNICODE_BASE + AFP_INITIAL_INVALID_HIGH)] = ANSI_PERIOD;
|
|
afpLastAltChar ++;
|
|
|
|
// This is yet another hack
|
|
afpAppleUnicodeChar = afpLastAltChar;
|
|
afpLastAltChar ++;
|
|
|
|
RtlZeroMemory(&AfpMacCPTableInfo, sizeof(AfpMacCPTableInfo));
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*** AfpMacAnsiDeInit
|
|
*
|
|
* De-initialize the code page for macintosh ANSI.
|
|
*/
|
|
VOID
|
|
AfpMacAnsiDeInit(
|
|
VOID
|
|
)
|
|
{
|
|
PAGED_CODE( );
|
|
|
|
if (AfpTranslationTable != NULL)
|
|
{
|
|
AfpFreeMemory(AfpTranslationTable);
|
|
}
|
|
|
|
if (AfpCasePreserveTranslationTable != NULL)
|
|
{
|
|
AfpFreeMemory(AfpCasePreserveTranslationTable);
|
|
}
|
|
|
|
if (AfpRevTranslationTable != NULL)
|
|
{
|
|
AfpFreeMemory(AfpRevTranslationTable);
|
|
}
|
|
|
|
if (afpAltUnicodeTable != NULL)
|
|
{
|
|
AfpFreeMemory(afpAltUnicodeTable);
|
|
}
|
|
|
|
if (afpAltAnsiTable != NULL)
|
|
{
|
|
AfpFreeMemory(afpAltAnsiTable);
|
|
}
|
|
|
|
if (AfpMacCPBaseAddress != NULL)
|
|
{
|
|
AfpFreeMemory(AfpMacCPBaseAddress);
|
|
}
|
|
}
|
|
|
|
|
|
/*** AfpConvertStringToUnicode
|
|
*
|
|
* Convert a Mac ANSI string to a unicode string.
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpConvertStringToUnicode(
|
|
IN PANSI_STRING pAnsiString,
|
|
OUT PUNICODE_STRING pUnicodeString
|
|
)
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
ULONG ulCast;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
Status = RtlCustomCPToUnicodeN(&AfpMacCPTableInfo,
|
|
pUnicodeString->Buffer,
|
|
pUnicodeString->MaximumLength,
|
|
&ulCast, pAnsiString->Buffer,
|
|
pAnsiString->Length);
|
|
if (NT_SUCCESS(Status))
|
|
pUnicodeString->Length = (USHORT)ulCast;
|
|
else
|
|
{
|
|
AFPLOG_ERROR(AFPSRVMSG_MACANSI2UNICODE, Status, NULL, 0, NULL);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpConvertStringToAnsi
|
|
*
|
|
* Convert a unicode string to a Mac ANSI string.
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpConvertStringToAnsi(
|
|
IN PUNICODE_STRING pUnicodeString,
|
|
OUT PANSI_STRING pAnsiString
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG ulCast;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
Status = RtlUnicodeToCustomCPN(&AfpMacCPTableInfo,
|
|
pAnsiString->Buffer,
|
|
pAnsiString->MaximumLength,
|
|
&ulCast, pUnicodeString->Buffer,
|
|
pUnicodeString->Length);
|
|
if (NT_SUCCESS(Status))
|
|
pAnsiString->Length = (USHORT)ulCast;
|
|
else
|
|
{
|
|
AFPLOG_ERROR(AFPSRVMSG_UNICODE2MACANSI, Status, NULL, 0, NULL);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpConvertStringToMungedUnicode
|
|
*
|
|
* Convert a Mac ANSI string to a unicode string. If there are any characters
|
|
* in the ansi string which are invalid filesystem (NTFS) characters, then
|
|
* map them to alternate unicode characters based on the table.
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpConvertStringToMungedUnicode(
|
|
IN PANSI_STRING pAnsiString,
|
|
OUT PUNICODE_STRING pUnicodeString
|
|
)
|
|
{
|
|
USHORT i, len;
|
|
BYTE c;
|
|
NTSTATUS Status;
|
|
ULONG ulCast;
|
|
PWCHAR pWBuf;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
ASSERT(afpAltUnicodeTable != NULL);
|
|
|
|
Status = RtlCustomCPToUnicodeN(&AfpMacCPTableInfo,
|
|
pUnicodeString->Buffer,
|
|
pUnicodeString->MaximumLength,
|
|
&ulCast,
|
|
pAnsiString->Buffer,
|
|
pAnsiString->Length);
|
|
if (NT_SUCCESS(Status))
|
|
pUnicodeString->Length = (USHORT)ulCast;
|
|
else
|
|
{
|
|
AFPLOG_ERROR(AFPSRVMSG_MACANSI2UNICODE, Status, NULL, 0, NULL);
|
|
return Status;
|
|
}
|
|
|
|
// Walk the ANSI string looking for the invalid characters and map it
|
|
// to the alternate set
|
|
|
|
for (i = 0, len = pAnsiString->Length, pWBuf = pUnicodeString->Buffer;
|
|
i < len;
|
|
i++, pWBuf ++)
|
|
{
|
|
c = pAnsiString->Buffer[i];
|
|
if (c == ANSI_APPLE_CHAR)
|
|
*pWBuf = afpAppleUnicodeChar;
|
|
else if (c < AFP_INITIAL_INVALID_HIGH)
|
|
*pWBuf = c + AFP_ALT_UNICODE_BASE;
|
|
else if (!FsRtlIsAnsiCharacterLegalNtfs(c, False))
|
|
{
|
|
ASSERT (c <= AFP_INVALID_HIGH);
|
|
*pWBuf = afpAltUnicodeTable[c - AFP_INITIAL_INVALID_HIGH];
|
|
}
|
|
/* MSKK eichim, Appended to handle DBCS trailing 0x5c, 03/16/95 */
|
|
#ifdef DBCS
|
|
if (FsRtlIsLeadDbcsCharacter(c))
|
|
i++;
|
|
#endif // DBCS
|
|
}
|
|
|
|
// HACK: Make sure the last character in the name is not a 'space' or a '.'
|
|
c = pAnsiString->Buffer[pAnsiString->Length - 1];
|
|
if ((c == ANSI_SPACE) || (c == ANSI_PERIOD))
|
|
/* MSKK hideyukn, Unicode char length not eqaul to ansi byte length in DBCS, 06/30/95 */
|
|
#ifdef DBCS
|
|
pUnicodeString->Buffer[(pUnicodeString->Length/sizeof(WCHAR)) - 1]
|
|
= afpAltUnicodeTable[c - AFP_INITIAL_INVALID_HIGH];
|
|
#else
|
|
pUnicodeString->Buffer[len - 1] = afpAltUnicodeTable[c - AFP_INITIAL_INVALID_HIGH];
|
|
#endif // DBCS
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/*** AfpConvertMungedUnicodeToAnsi
|
|
*
|
|
* Convert a unicode string with possible alternate unicode characters
|
|
* to Mac Ansi.
|
|
* This is inverse of AfpConvertStringToMungedUnicode().
|
|
*/
|
|
NTSTATUS FASTCALL
|
|
AfpConvertMungedUnicodeToAnsi(
|
|
IN PUNICODE_STRING pUnicodeString,
|
|
OUT PANSI_STRING pAnsiString
|
|
)
|
|
{
|
|
USHORT i, len;
|
|
WCHAR wc;
|
|
NTSTATUS Status;
|
|
ULONG ulCast;
|
|
PBYTE pABuf;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
|
|
Status = RtlUnicodeToCustomCPN(&AfpMacCPTableInfo,
|
|
pAnsiString->Buffer,
|
|
pAnsiString->MaximumLength,
|
|
&ulCast, pUnicodeString->Buffer,
|
|
pUnicodeString->Length);
|
|
if (NT_SUCCESS(Status))
|
|
pAnsiString->Length = (USHORT)ulCast;
|
|
else
|
|
{
|
|
AFPLOG_ERROR(AFPSRVMSG_UNICODE2MACANSI, Status, NULL, 0, NULL);
|
|
}
|
|
|
|
// Walk the Unicode string looking for alternate unicode chars and
|
|
// replacing the ansi equivalents by the real ansi characters.
|
|
for (i = 0, len = pUnicodeString->Length/(USHORT)sizeof(WCHAR), pABuf = pAnsiString->Buffer;
|
|
i < len;
|
|
i++, pABuf++)
|
|
{
|
|
wc = pUnicodeString->Buffer[i];
|
|
if (wc == afpAppleUnicodeChar)
|
|
*pABuf = ANSI_APPLE_CHAR;
|
|
else if ((wc >= AFP_ALT_UNICODE_BASE) && (wc < afpLastAltChar))
|
|
{
|
|
wc -= AFP_ALT_UNICODE_BASE;
|
|
if (wc < AFP_INITIAL_INVALID_HIGH)
|
|
*pABuf = (BYTE)wc;
|
|
else *pABuf = afpAltAnsiTable[wc - AFP_INITIAL_INVALID_HIGH];
|
|
}
|
|
/* MSKK hideyukn, Unicode char length not eqaul to ansi byte length in DBCS, 06/30/95 */
|
|
#ifdef DBCS
|
|
if (FsRtlIsLeadDbcsCharacter(*pABuf))
|
|
pABuf++;
|
|
#endif // DBCS
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/*** AfpConvertMacAnsiToHostAnsi
|
|
*
|
|
* Convert a Mac ansi string to its host counterpart in uppercase OEM codepage.
|
|
* (in place). The name of this routine is misleading as a late bugfix was
|
|
* made to change the codepage used, but the name of the routine didn't change
|
|
* so none of the calling code had to be changed. It should really be called
|
|
* AfpConvertMacAnsiToUpcaseOem. This routine is only called to uppercase
|
|
* mac passwords for logon and changepassword.
|
|
*
|
|
*/
|
|
AFPSTATUS FASTCALL
|
|
AfpConvertMacAnsiToHostAnsi(
|
|
IN OUT PANSI_STRING pAnsiString
|
|
)
|
|
{
|
|
LONG i, Len;
|
|
BYTE *pBuf;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
// ASSERT (AfpTranslationTable != NULL);
|
|
ASSERT (AfpCasePreserveTranslationTable != NULL);
|
|
|
|
Len = pAnsiString->Length;
|
|
pBuf = pAnsiString->Buffer;
|
|
|
|
for (i = 0; i < Len; i++, pBuf++)
|
|
{
|
|
/* MSKK NaotoN Appended to handle DBCS Mac path name 11/10/93 */
|
|
#ifdef DBCS
|
|
if (FsRtlIsLeadDbcsCharacter( *pBuf )) {
|
|
i++ ;
|
|
pBuf++ ;
|
|
}
|
|
else
|
|
#endif // DBCS
|
|
*pBuf = AfpCasePreserveTranslationTable[*pBuf];
|
|
}
|
|
return AFP_ERR_NONE;
|
|
}
|
|
|
|
/*** AfpConvertHostAnsiToMacAnsi
|
|
*
|
|
* Convert a host unicode string to its mac counterpart in place.
|
|
* Only characters <= 0x20 and >= 0x80 are translated.
|
|
*
|
|
* NOTE: This is extremely hacky and intended for translating messages only.
|
|
*/
|
|
VOID FASTCALL
|
|
AfpConvertHostAnsiToMacAnsi(
|
|
IN OUT PANSI_STRING pAnsiString
|
|
)
|
|
{
|
|
LONG i, Len;
|
|
BYTE c, *pBuf;
|
|
|
|
PAGED_CODE( );
|
|
|
|
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
|
|
ASSERT (AfpRevTranslationTable != NULL);
|
|
|
|
Len = pAnsiString->Length;
|
|
pBuf = pAnsiString->Buffer;
|
|
|
|
for (i = 0; i < Len; i++, pBuf++)
|
|
{
|
|
c = *pBuf;
|
|
/* MSKK NaotoN Appended to skip if Kanji 12/17/93 */
|
|
#ifdef DBCS
|
|
if (FsRtlIsLeadDbcsCharacter( c )) {
|
|
i++ ;
|
|
pBuf++ ;
|
|
}
|
|
else
|
|
#endif // DBCS
|
|
if (c < 0x20)
|
|
{
|
|
*pBuf = AfpRevTranslationTable[c];
|
|
}
|
|
else if (c >= 0x80)
|
|
{
|
|
*pBuf = AfpRevTranslationTable[c-(0x80-0x20)];
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** AfpEqualUnicodeString
|
|
*
|
|
* The AfpEqualUnicodeString function compares two counted unicode
|
|
* strings for equality using case SENSITIVE compare. This routine
|
|
* exists because it must be called at DPC level by the volume.c code
|
|
* for comparing 2 non-paged strings, and the RtlEqualUnicodeString
|
|
* routine that we would normally call is pageable code.
|
|
*
|
|
* Note that case INSENSITIVE compare would require accessing
|
|
* paged up-case table info, and therefore could not be done at DPC level.
|
|
*
|
|
* Arguments:
|
|
* String1 - Pointer to the first string.
|
|
* String2 - Pointer to the second string.
|
|
*
|
|
* Return Value:
|
|
* True if String1 equals String2 and False otherwise.
|
|
*
|
|
* Note: This is called at DPC level from volume.c and must not be made
|
|
* a pageable routine.
|
|
*/
|
|
|
|
BOOLEAN FASTCALL
|
|
AfpEqualUnicodeString(
|
|
IN PUNICODE_STRING String1,
|
|
IN PUNICODE_STRING String2
|
|
)
|
|
{
|
|
WCHAR *s1, *s2;
|
|
USHORT n1, n2;
|
|
|
|
n1 = (USHORT)(String1->Length/sizeof(WCHAR));
|
|
n2 = (USHORT)(String2->Length/sizeof(WCHAR));
|
|
|
|
if (n1 != n2)
|
|
{
|
|
return False;
|
|
}
|
|
|
|
s1 = String1->Buffer;
|
|
s2 = String2->Buffer;
|
|
|
|
while (n1--)
|
|
{
|
|
if (*s1++ != *s2++)
|
|
{
|
|
return False;
|
|
}
|
|
}
|
|
|
|
return True;
|
|
}
|
|
|
|
|
|
/*** AfpPrefixUnicodeString
|
|
*
|
|
* The AfpPrefixUnicodeString function determines if the String1
|
|
* counted string parameter is a prefix of the String2 counted string
|
|
* parameter using case SENSITIVE compare. This routine exists because it
|
|
* must be called at DPC level by the volume.c code for comparing
|
|
* two non-paged strings, and the RtlPrefixUnicodeString routine that we
|
|
* would normally call is pageable code.
|
|
*
|
|
* Note that case INSENSITIVE compare would require accessing
|
|
* paged up-case table info, and therefore could not be done at DPC level.
|
|
*
|
|
* Arguments:
|
|
* String1 - Pointer to the first unicode string.
|
|
* String2 - Pointer to the second unicode string.
|
|
*
|
|
* Return Value:
|
|
* True if String1 equals a prefix of String2 and False otherwise.
|
|
*
|
|
* Note: This is called at DPC level from volume.c and must not be made
|
|
* a pageable routine.
|
|
*/
|
|
|
|
BOOLEAN FASTCALL
|
|
AfpPrefixUnicodeString(
|
|
IN PUNICODE_STRING String1,
|
|
IN PUNICODE_STRING String2
|
|
)
|
|
{
|
|
PWSTR s1, s2;
|
|
ULONG n;
|
|
WCHAR c1, c2;
|
|
|
|
if (String2->Length < String1->Length)
|
|
{
|
|
return False;
|
|
}
|
|
|
|
s1 = String1->Buffer;
|
|
s2 = String2->Buffer;
|
|
n = String1->Length/sizeof(WCHAR);
|
|
while (n--)
|
|
{
|
|
c1 = *s1++;
|
|
c2 = *s2++;
|
|
if (c1 != c2)
|
|
{
|
|
return False;
|
|
}
|
|
}
|
|
return True;
|
|
}
|
|
|
|
/*** AfpGetMacCodePage
|
|
*
|
|
* Open the default macintosh codepage, create a section backed by that file,
|
|
* map a view to the section, and initialize the CodePage info structure
|
|
* that is used with the RtlCustomCP routines. Then create the Mac Ansi to
|
|
* Host Ansi mapping table.
|
|
*
|
|
* BEWARE!
|
|
* This routine may only be called ONCE! This will be called from the first
|
|
* admin call to ServerSetInfo. Therefore, there can be NO calls to the
|
|
* macansi routines within this module (except for MacAnsiInit) before that
|
|
* happens.
|
|
*/
|
|
NTSTATUS FASTCALL
|
|
AfpGetMacCodePage(
|
|
IN LPWSTR PathCP
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
FILESYSHANDLE FileHandle;
|
|
UNICODE_STRING uPathCP, devPathCP;
|
|
ULONG viewsize = 0;
|
|
WCHAR UnicodeTable[2*AFP_XLAT_TABLE_SIZE];
|
|
BYTE AnsiTable[2*AFP_XLAT_TABLE_SIZE + 1];
|
|
UNICODE_STRING UnicodeString;
|
|
ANSI_STRING AnsiString;
|
|
LONG i;
|
|
|
|
PAGED_CODE( );
|
|
|
|
FileHandle.fsh_FileHandle = NULL;
|
|
UnicodeString.Length = AFP_XLAT_TABLE_SIZE * sizeof(WCHAR);
|
|
UnicodeString.MaximumLength = (AFP_XLAT_TABLE_SIZE + 1) * sizeof(WCHAR);
|
|
UnicodeString.Buffer = UnicodeTable;
|
|
|
|
RtlInitUnicodeString(&uPathCP, PathCP);
|
|
devPathCP.Length = 0;
|
|
devPathCP.MaximumLength = uPathCP.Length + DosDevices.Length + sizeof(WCHAR);
|
|
if ((devPathCP.Buffer = (PWSTR)AfpAllocPagedMemory(devPathCP.MaximumLength)) == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
AFPLOG_ERROR(AFPSRVMSG_MAC_CODEPAGE, Status, NULL, 0, NULL);
|
|
return Status;
|
|
}
|
|
AfpCopyUnicodeString(&devPathCP, &DosDevices);
|
|
RtlAppendUnicodeStringToString(&devPathCP, &uPathCP);
|
|
|
|
do
|
|
{
|
|
FORKSIZE liCPlen;
|
|
LONG lCPlen, sizeread=0;
|
|
|
|
Status = AfpIoOpen(NULL,
|
|
AFP_STREAM_DATA,
|
|
FILEIO_OPEN_FILE,
|
|
&devPathCP,
|
|
FILEIO_ACCESS_READ,
|
|
FILEIO_DENY_NONE,
|
|
False,
|
|
&FileHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
if (!NT_SUCCESS(Status = AfpIoQuerySize(&FileHandle,
|
|
&liCPlen)))
|
|
break;
|
|
|
|
// NOTE: This assumes the codepage file will never be so big that
|
|
// the high bit of the LowPart of the size will be set
|
|
lCPlen = (LONG)liCPlen.LowPart;
|
|
if ((AfpMacCPBaseAddress = (PUSHORT)AfpAllocPagedMemory(lCPlen)) == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
Status = AfpIoRead(&FileHandle,
|
|
&LIZero,
|
|
lCPlen,
|
|
&sizeread,
|
|
(PBYTE)AfpMacCPBaseAddress);
|
|
AfpIoClose(&FileHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
if (sizeread != lCPlen)
|
|
{
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
|
|
RtlInitCodePageTable(AfpMacCPBaseAddress, &AfpMacCPTableInfo);
|
|
|
|
// Initialize mac ANSI to host upcase Oem translation table
|
|
// Start by allocating memory for the table and filling it up.
|
|
|
|
/* HitoshiT modify following line to keep Unicode translation table. 5/18/94 */
|
|
#ifdef DBCS
|
|
if ((AfpTranslationTable = AfpAllocPagedMemory(2*AFP_XLAT_TABLE_SIZE*sizeof(USHORT) + 1)) == NULL)
|
|
#else
|
|
if ((AfpTranslationTable = AfpAllocPagedMemory(2*AFP_XLAT_TABLE_SIZE + 1)) == NULL)
|
|
#endif // DBCS
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
// Initialize mac ANSI to host Oem translation table
|
|
// Start by allocating memory for the table and filling it up.
|
|
|
|
#ifdef DBCS
|
|
if ((AfpCasePreserveTranslationTable = AfpAllocPagedMemory(2*AFP_XLAT_TABLE_SIZE*sizeof(USHORT) + 1)) == NULL)
|
|
#else
|
|
if ((AfpCasePreserveTranslationTable = AfpAllocPagedMemory(2*AFP_XLAT_TABLE_SIZE + 1)) == NULL)
|
|
#endif // DBCS
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < 2*AFP_XLAT_TABLE_SIZE; i++)
|
|
AnsiTable[i] = (BYTE)i;
|
|
|
|
// Now translate this from Mac ANSI to unicode
|
|
AnsiString.Length = 2*AFP_XLAT_TABLE_SIZE;
|
|
AnsiString.MaximumLength = 2*AFP_XLAT_TABLE_SIZE + 1;
|
|
AnsiString.Buffer = AnsiTable;
|
|
|
|
UnicodeString.Length = 0;
|
|
UnicodeString.MaximumLength = sizeof(UnicodeTable);
|
|
UnicodeString.Buffer = UnicodeTable;
|
|
|
|
Status = AfpConvertStringToUnicode(&AnsiString, &UnicodeString);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
// Now convert the entire table to uppercase host Oem Codepage
|
|
AnsiString.Length = 0;
|
|
/* HitoshiT modify following line to keep Unicode translation table 5/18/94 */
|
|
#ifdef DBCS
|
|
AnsiString.MaximumLength = 2*AFP_XLAT_TABLE_SIZE * sizeof(USHORT) + 1;
|
|
#else
|
|
AnsiString.MaximumLength = 2*AFP_XLAT_TABLE_SIZE + 1;
|
|
#endif // DBCS
|
|
AnsiString.Buffer = AfpTranslationTable;
|
|
|
|
Status = RtlUpcaseUnicodeStringToOemString(&AnsiString, &UnicodeString, False);
|
|
// Bug 342062
|
|
// Bug introduced due to RtlpDidUnicodeToOemWork check
|
|
// introduced in RtlUpcaseUnicodeStringToOemString
|
|
// We have characters which will be mapped to default characters
|
|
// and hence we should ignore STATUS_UNMAPPABLE_CHARACTER
|
|
if ((!NT_SUCCESS(Status))&&(Status!=STATUS_UNMAPPABLE_CHARACTER))
|
|
break;
|
|
|
|
// Now convert the entire table to host Oem Codepage
|
|
AnsiString.Length = 0;
|
|
#ifdef DBCS
|
|
AnsiString.MaximumLength = 2*AFP_XLAT_TABLE_SIZE * sizeof(USHORT) + 1;
|
|
#else
|
|
AnsiString.MaximumLength = 2*AFP_XLAT_TABLE_SIZE + 1;
|
|
#endif // DBCS
|
|
AnsiString.Buffer = AfpCasePreserveTranslationTable;
|
|
|
|
Status = RtlUnicodeStringToOemString(&AnsiString, &UnicodeString, False);
|
|
|
|
if ((!NT_SUCCESS(Status))&&(Status!=STATUS_UNMAPPABLE_CHARACTER))
|
|
break;
|
|
|
|
// Initialize host ANSI to mac ANSI translation table
|
|
// Start by allocating memory for the table and filling it up.
|
|
if ((AfpRevTranslationTable = AfpAllocPagedMemory(AFP_REV_XLAT_TABLE_SIZE + 1)) == NULL)
|
|
{
|
|
Status = STATUS_NO_MEMORY;
|
|
break;
|
|
}
|
|
|
|
for (i = 0; i < 0x20; i++)
|
|
AfpRevTranslationTable[i] = (BYTE)i;
|
|
|
|
for (i = 0x80; i < 256; i++)
|
|
AfpRevTranslationTable[i-(0x80-0x20)] = (BYTE)i;
|
|
|
|
// Get rid of the line feed char
|
|
AfpRevTranslationTable[0x0A] = 0;
|
|
|
|
// Now translate host ANSI to unicode
|
|
AnsiString.Length = AFP_REV_XLAT_TABLE_SIZE;
|
|
AnsiString.MaximumLength = AFP_REV_XLAT_TABLE_SIZE + 1;
|
|
AnsiString.Buffer = AfpRevTranslationTable;
|
|
|
|
UnicodeString.Length = 0;
|
|
|
|
Status = RtlAnsiStringToUnicodeString(&UnicodeString, &AnsiString, False);
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
// and then translate from unicode to Mac ANSI
|
|
Status = AfpConvertStringToAnsi(&UnicodeString, &AnsiString);
|
|
|
|
} while (False);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
AFPLOG_ERROR(AFPSRVMSG_MAC_CODEPAGE, Status, NULL, 0, NULL);
|
|
if (AfpMacCPBaseAddress != NULL)
|
|
{
|
|
AfpFreeMemory(AfpMacCPBaseAddress);
|
|
AfpMacCPBaseAddress = NULL;
|
|
}
|
|
|
|
if (FileHandle.fsh_FileHandle != NULL)
|
|
{
|
|
AfpIoClose(&FileHandle);
|
|
}
|
|
|
|
if (AfpTranslationTable != NULL)
|
|
{
|
|
AfpFreeMemory(AfpTranslationTable);
|
|
AfpTranslationTable = NULL;
|
|
}
|
|
|
|
if (AfpCasePreserveTranslationTable != NULL)
|
|
{
|
|
AfpFreeMemory(AfpCasePreserveTranslationTable);
|
|
AfpCasePreserveTranslationTable = NULL;
|
|
}
|
|
|
|
if (AfpRevTranslationTable != NULL)
|
|
{
|
|
AfpFreeMemory(AfpRevTranslationTable);
|
|
AfpRevTranslationTable = NULL;
|
|
}
|
|
}
|
|
|
|
AfpFreeMemory(devPathCP.Buffer);
|
|
return Status;
|
|
}
|
|
|
|
/*** AfpIsLegalShortname
|
|
*
|
|
* Does a mac shortname conform to FAT 8.3 naming conventions?
|
|
*
|
|
*/
|
|
BOOLEAN FASTCALL
|
|
AfpIsLegalShortname(
|
|
IN PANSI_STRING pShortName // Mac ANSI string
|
|
)
|
|
{
|
|
return(FsRtlIsFatDbcsLegal(*pShortName, False, False, False));
|
|
|
|
}
|
|
|
|
/*** AfpIsProperSubstring
|
|
*
|
|
* This routine looks for the substring pSubString in pString. Both
|
|
* strings are in unicode, the comparison is done case insensitive
|
|
* (i.e. ignoring case). This is used by the AfpCatSearch code.
|
|
*
|
|
*/
|
|
BOOLEAN FASTCALL
|
|
AfpIsProperSubstring(
|
|
IN PUNICODE_STRING pString,
|
|
IN PUNICODE_STRING pSubString
|
|
)
|
|
{
|
|
WCHAR *s1, *s2, *ts1;
|
|
USHORT l1, l2, tl1;
|
|
WCHAR buf1[AFP_LONGNAME_LEN], buf2[AFP_LONGNAME_LEN];
|
|
UNICODE_STRING u1, u2;
|
|
|
|
PAGED_CODE( );
|
|
|
|
// see if this is a no-op?
|
|
if (pSubString->Length > pString->Length)
|
|
return False;
|
|
|
|
AfpSetEmptyUnicodeString(&u1, sizeof(buf1), buf1);
|
|
AfpSetEmptyUnicodeString(&u2, sizeof(buf2), buf2);
|
|
if (!NT_SUCCESS(RtlUpcaseUnicodeString(&u1, pString, False)) ||
|
|
!NT_SUCCESS(RtlUpcaseUnicodeString(&u2, pSubString, False)))
|
|
return False;
|
|
|
|
l1 = u1.Length/sizeof(WCHAR);
|
|
s1 = u1.Buffer;
|
|
|
|
do
|
|
{
|
|
l2 = u2.Length/sizeof(WCHAR);
|
|
s2 = u2.Buffer;
|
|
if (l2 > l1)
|
|
return False;
|
|
|
|
// look for the next occurrence of the first char of s2 in string s1
|
|
while (l1)
|
|
{
|
|
if (*s2 == *s1)
|
|
break;
|
|
|
|
s1++;
|
|
l1--;
|
|
}
|
|
|
|
if (l1 < l2)
|
|
return False;
|
|
if (l2 == 1)
|
|
return True;
|
|
|
|
l1--; l2--;
|
|
s1++; s2++;
|
|
|
|
ts1 = s1;
|
|
tl1 = l1;
|
|
|
|
while (l2)
|
|
{
|
|
// Look for substring s2 from current position in s1
|
|
if (*s2 != *ts1)
|
|
break;
|
|
|
|
tl1--; l2--;
|
|
ts1++; s2++;
|
|
}
|
|
|
|
if (l2 == 0)
|
|
return True;
|
|
|
|
} while (True);
|
|
|
|
// Should never get here
|
|
KeBugCheck(0);
|
|
}
|
|
|
|
/*** AfpStrChr
|
|
*
|
|
* DBCS sensitive strchr()
|
|
*
|
|
*/
|
|
PCHAR
|
|
AfpStrChr(
|
|
IN PBYTE String,
|
|
IN DWORD StringLen,
|
|
IN BYTE Char
|
|
)
|
|
{
|
|
DWORD BytesRemaining;
|
|
|
|
|
|
BytesRemaining = StringLen;
|
|
|
|
while (BytesRemaining > 0)
|
|
{
|
|
|
|
/* MSKK hideyukn, strchr() does not work with DBCS, 08/07/95 */
|
|
#ifdef DBCS
|
|
if (FsRtlIsLeadDbcsCharacter(*String))
|
|
{
|
|
String += 2;
|
|
continue;
|
|
}
|
|
#endif /* DBCS */
|
|
|
|
if (*String == Char)
|
|
{
|
|
return(String);
|
|
}
|
|
|
|
String++;
|
|
BytesRemaining--;
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|