/* 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 #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); }