4 * Copyright (C) 1996-1998 Marcus Meissner
5 * Copyright (C) 2000 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
35 UINT NlsAnsiCodePage = 1252;
36 BYTE NlsMbCodePageTag = 0;
37 BYTE NlsMbOemCodePageTag = 0;
39 static const union cptable *ansi_table;
40 static const union cptable *oem_table;
42 inline static const union cptable *get_ansi_table(void)
44 if (!ansi_table) ansi_table = cp_get_table( 1252 );
48 inline static const union cptable *get_oem_table(void)
50 if (!oem_table) oem_table = cp_get_table( 437 );
55 /**************************************************************************
56 * __wine_init_codepages (NTDLL.@)
58 * Set the code page once kernel32 is loaded. Should be done differently.
60 void __wine_init_codepages( const union cptable *ansi, const union cptable *oem )
64 NlsAnsiCodePage = ansi->info.codepage;
68 /**************************************************************************
69 * RtlInitAnsiString (NTDLL.@)
71 void WINAPI RtlInitAnsiString( PSTRING target, LPCSTR source)
73 if ((target->Buffer = (LPSTR)source))
75 target->Length = strlen(source);
76 target->MaximumLength = target->Length + 1;
78 else target->Length = target->MaximumLength = 0;
82 /**************************************************************************
83 * RtlInitString (NTDLL.@)
85 void WINAPI RtlInitString( PSTRING target, LPCSTR source )
87 RtlInitAnsiString( target, source );
91 /**************************************************************************
92 * RtlFreeAnsiString (NTDLL.@)
94 void WINAPI RtlFreeAnsiString( PSTRING str )
96 if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
100 /**************************************************************************
101 * RtlFreeOemString (NTDLL.@)
103 void WINAPI RtlFreeOemString( PSTRING str )
105 RtlFreeAnsiString( str );
109 /**************************************************************************
110 * RtlCopyString (NTDLL.@)
112 void WINAPI RtlCopyString( STRING *dst, const STRING *src )
116 unsigned int len = min( src->Length, dst->MaximumLength );
117 memcpy( dst->Buffer, src->Buffer, len );
120 else dst->Length = 0;
124 /**************************************************************************
125 * RtlInitUnicodeString (NTDLL.@)
127 void WINAPI RtlInitUnicodeString( PUNICODE_STRING target, LPCWSTR source )
129 if ((target->Buffer = (LPWSTR)source))
131 target->Length = strlenW(source) * sizeof(WCHAR);
132 target->MaximumLength = target->Length + sizeof(WCHAR);
134 else target->Length = target->MaximumLength = 0;
138 /**************************************************************************
139 * RtlCreateUnicodeString (NTDLL.@)
141 BOOLEAN WINAPI RtlCreateUnicodeString( PUNICODE_STRING target, LPCWSTR src )
143 int len = (strlenW(src) + 1) * sizeof(WCHAR);
144 if (!(target->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return FALSE;
145 memcpy( target->Buffer, src, len );
146 target->MaximumLength = len;
147 target->Length = len - 2;
152 /**************************************************************************
153 * RtlCreateUnicodeStringFromAsciiz (NTDLL.@)
155 BOOLEAN WINAPI RtlCreateUnicodeStringFromAsciiz( PUNICODE_STRING target, LPCSTR src )
158 RtlInitAnsiString( &ansi, src );
159 return !RtlAnsiStringToUnicodeString( target, &ansi, TRUE );
163 /**************************************************************************
164 * RtlFreeUnicodeString (NTDLL.@)
166 void WINAPI RtlFreeUnicodeString( PUNICODE_STRING str )
168 if (str->Buffer) RtlFreeHeap( GetProcessHeap(), 0, str->Buffer );
172 /**************************************************************************
173 * RtlCopyUnicodeString (NTDLL.@)
175 void WINAPI RtlCopyUnicodeString( UNICODE_STRING *dst, const UNICODE_STRING *src )
179 unsigned int len = min( src->Length, dst->MaximumLength );
180 memcpy( dst->Buffer, src->Buffer, len );
182 /* append terminating NULL if enough space */
183 if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
185 else dst->Length = 0;
189 /**************************************************************************
190 * RtlEraseUnicodeString (NTDLL.@)
192 void WINAPI RtlEraseUnicodeString( UNICODE_STRING *str )
196 memset( str->Buffer, 0, str->MaximumLength );
205 /******************************************************************************
206 * RtlCompareString (NTDLL.@)
208 LONG WINAPI RtlCompareString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
214 len = min(s1->Length, s2->Length);
220 while (!ret && len--) ret = toupper(*p1++) - toupper(*p2++);
224 while (!ret && len--) ret = *p1++ - *p2++;
226 if (!ret) ret = s1->Length - s2->Length;
231 /******************************************************************************
232 * RtlCompareUnicodeString (NTDLL.@)
234 LONG WINAPI RtlCompareUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
235 BOOLEAN CaseInsensitive )
241 len = min(s1->Length, s2->Length) / sizeof(WCHAR);
247 while (!ret && len--) ret = toupperW(*p1++) - toupperW(*p2++);
251 while (!ret && len--) ret = *p1++ - *p2++;
253 if (!ret) ret = s1->Length - s2->Length;
258 /**************************************************************************
259 * RtlEqualString (NTDLL.@)
261 BOOLEAN WINAPI RtlEqualString( const STRING *s1, const STRING *s2, BOOLEAN CaseInsensitive )
263 if (s1->Length != s2->Length) return FALSE;
264 return !RtlCompareString( s1, s2, CaseInsensitive );
268 /**************************************************************************
269 * RtlEqualUnicodeString (NTDLL.@)
271 BOOLEAN WINAPI RtlEqualUnicodeString( const UNICODE_STRING *s1, const UNICODE_STRING *s2,
272 BOOLEAN CaseInsensitive )
274 if (s1->Length != s2->Length) return FALSE;
275 return !RtlCompareUnicodeString( s1, s2, CaseInsensitive );
279 /**************************************************************************
280 * RtlPrefixString (NTDLL.@)
282 * Test if s1 is a prefix in s2
284 BOOLEAN WINAPI RtlPrefixString( const STRING *s1, const STRING *s2, BOOLEAN ignore_case )
288 if (s1->Length > s2->Length) return FALSE;
291 for (i = 0; i < s1->Length; i++)
292 if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
296 for (i = 0; i < s1->Length; i++)
297 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
303 /**************************************************************************
304 * RtlPrefixUnicodeString (NTDLL.@)
306 * Test if s1 is a prefix in s2
308 BOOLEAN WINAPI RtlPrefixUnicodeString( const UNICODE_STRING *s1,
309 const UNICODE_STRING *s2,
310 BOOLEAN ignore_case )
314 if (s1->Length > s2->Length) return FALSE;
317 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
318 if (toupper(s1->Buffer[i]) != toupper(s2->Buffer[i])) return FALSE;
322 for (i = 0; i < s1->Length / sizeof(WCHAR); i++)
323 if (s1->Buffer[i] != s2->Buffer[i]) return FALSE;
330 COPY BETWEEN ANSI_STRING or UNICODE_STRING
331 there is no parameter checking, it just crashes
335 /**************************************************************************
336 * RtlAnsiStringToUnicodeString (NTDLL.@)
339 * writes terminating 0
341 NTSTATUS WINAPI RtlAnsiStringToUnicodeString( UNICODE_STRING *uni,
345 DWORD total = RtlAnsiStringToUnicodeSize( ansi );
347 if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
348 uni->Length = total - sizeof(WCHAR);
351 uni->MaximumLength = total;
352 if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
354 else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
356 RtlMultiByteToUnicodeN( uni->Buffer, uni->Length, NULL, ansi->Buffer, ansi->Length );
357 uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
358 return STATUS_SUCCESS;
362 /**************************************************************************
363 * RtlOemStringToUnicodeString (NTDLL.@)
366 * writes terminating 0
367 * if resulting length > 0xffff it returns STATUS_INVALID_PARAMETER_2
369 NTSTATUS WINAPI RtlOemStringToUnicodeString( UNICODE_STRING *uni,
373 DWORD total = RtlOemStringToUnicodeSize( oem );
375 if (total > 0xffff) return STATUS_INVALID_PARAMETER_2;
376 uni->Length = total - sizeof(WCHAR);
379 uni->MaximumLength = total;
380 if (!(uni->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, total ))) return STATUS_NO_MEMORY;
382 else if (total > uni->MaximumLength) return STATUS_BUFFER_OVERFLOW;
384 RtlOemToUnicodeN( uni->Buffer, uni->Length, NULL, oem->Buffer, oem->Length );
385 uni->Buffer[uni->Length / sizeof(WCHAR)] = 0;
386 return STATUS_SUCCESS;
390 /**************************************************************************
391 * RtlUnicodeStringToAnsiString (NTDLL.@)
394 * writes terminating 0
395 * copies a part if the buffer is too small
397 NTSTATUS WINAPI RtlUnicodeStringToAnsiString( STRING *ansi,
398 const UNICODE_STRING *uni,
401 NTSTATUS ret = STATUS_SUCCESS;
402 DWORD len = RtlUnicodeStringToAnsiSize( uni );
404 ansi->Length = len - 1;
407 ansi->MaximumLength = len;
408 if (!(ansi->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
410 else if (ansi->MaximumLength < len)
412 if (!ansi->MaximumLength) return STATUS_BUFFER_OVERFLOW;
413 ansi->Length = ansi->MaximumLength - 1;
414 ret = STATUS_BUFFER_OVERFLOW;
417 RtlUnicodeToMultiByteN( ansi->Buffer, ansi->Length, NULL, uni->Buffer, uni->Length );
418 ansi->Buffer[ansi->Length] = 0;
423 /**************************************************************************
424 * RtlUnicodeStringToOemString (NTDLL.@)
427 * allocates uni->Length+1
428 * writes terminating 0
430 NTSTATUS WINAPI RtlUnicodeStringToOemString( STRING *oem,
431 const UNICODE_STRING *uni,
434 NTSTATUS ret = STATUS_SUCCESS;
435 DWORD len = RtlUnicodeStringToOemSize( uni );
437 oem->Length = len - 1;
440 oem->MaximumLength = len;
441 if (!(oem->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
443 else if (oem->MaximumLength < len)
445 if (!oem->MaximumLength) return STATUS_BUFFER_OVERFLOW;
446 oem->Length = oem->MaximumLength - 1;
447 ret = STATUS_BUFFER_OVERFLOW;
450 RtlUnicodeToOemN( oem->Buffer, oem->Length, NULL, uni->Buffer, uni->Length );
451 oem->Buffer[oem->Length] = 0;
456 /**************************************************************************
457 * RtlMultiByteToUnicodeN (NTDLL.@)
460 * if unistr is too small a part is copied
462 NTSTATUS WINAPI RtlMultiByteToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
463 LPCSTR src, DWORD srclen )
466 int ret = cp_mbstowcs( get_ansi_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
468 *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
469 return STATUS_SUCCESS;
473 /**************************************************************************
474 * RtlOemToUnicodeN (NTDLL.@)
476 NTSTATUS WINAPI RtlOemToUnicodeN( LPWSTR dst, DWORD dstlen, LPDWORD reslen,
477 LPCSTR src, DWORD srclen )
479 int ret = cp_mbstowcs( get_oem_table(), 0, src, srclen, dst, dstlen/sizeof(WCHAR) );
481 *reslen = (ret >= 0) ? ret*sizeof(WCHAR) : dstlen; /* overflow -> we filled up to dstlen */
482 return STATUS_SUCCESS;
486 /**************************************************************************
487 * RtlUnicodeToMultiByteN (NTDLL.@)
489 NTSTATUS WINAPI RtlUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
490 LPCWSTR src, DWORD srclen )
492 int ret = cp_wcstombs( get_ansi_table(), 0, src, srclen / sizeof(WCHAR),
493 dst, dstlen, NULL, NULL );
495 *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
496 return STATUS_SUCCESS;
500 /**************************************************************************
501 * RtlUnicodeToOemN (NTDLL.@)
503 NTSTATUS WINAPI RtlUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
504 LPCWSTR src, DWORD srclen )
506 int ret = cp_wcstombs( get_oem_table(), 0, src, srclen / sizeof(WCHAR),
507 dst, dstlen, NULL, NULL );
509 *reslen = (ret >= 0) ? ret : dstlen; /* overflow -> we filled up to dstlen */
510 return STATUS_SUCCESS;
518 /**************************************************************************
519 * RtlUpperString (NTDLL.@)
521 void WINAPI RtlUpperString( STRING *dst, const STRING *src )
523 unsigned int i, len = min(src->Length, dst->MaximumLength);
525 for (i = 0; i < len; i++) dst->Buffer[i] = toupper(src->Buffer[i]);
530 /**************************************************************************
531 * RtlUpcaseUnicodeString (NTDLL.@)
534 * destination string is never 0-terminated because dest can be equal to src
535 * and src might be not 0-terminated
536 * dest.Length only set when success
538 NTSTATUS WINAPI RtlUpcaseUnicodeString( UNICODE_STRING *dest,
539 const UNICODE_STRING *src,
542 DWORD i, len = src->Length;
546 dest->MaximumLength = len;
547 if (!(dest->Buffer = RtlAllocateHeap( GetProcessHeap(), 0, len ))) return STATUS_NO_MEMORY;
549 else if (len > dest->MaximumLength) return STATUS_BUFFER_OVERFLOW;
551 for (i = 0; i < len/sizeof(WCHAR); i++) dest->Buffer[i] = toupperW(src->Buffer[i]);
553 return STATUS_SUCCESS;
557 /**************************************************************************
558 * RtlUpcaseUnicodeStringToAnsiString (NTDLL.@)
561 * writes terminating 0
563 NTSTATUS WINAPI RtlUpcaseUnicodeStringToAnsiString( STRING *dst,
564 const UNICODE_STRING *src,
568 UNICODE_STRING upcase;
570 if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
572 ret = RtlUnicodeStringToAnsiString( dst, &upcase, doalloc );
573 RtlFreeUnicodeString( &upcase );
579 /**************************************************************************
580 * RtlUpcaseUnicodeStringToOemString (NTDLL.@)
583 * writes terminating 0
585 NTSTATUS WINAPI RtlUpcaseUnicodeStringToOemString( STRING *dst,
586 const UNICODE_STRING *src,
590 UNICODE_STRING upcase;
592 if (!(ret = RtlUpcaseUnicodeString( &upcase, src, TRUE )))
594 ret = RtlUnicodeStringToOemString( dst, &upcase, doalloc );
595 RtlFreeUnicodeString( &upcase );
601 /**************************************************************************
602 * RtlUpcaseUnicodeToMultiByteN (NTDLL.@)
604 NTSTATUS WINAPI RtlUpcaseUnicodeToMultiByteN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
605 LPCWSTR src, DWORD srclen )
611 if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
612 for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
613 ret = RtlUnicodeToMultiByteN( dst, dstlen, reslen, upcase, srclen );
614 RtlFreeHeap( GetProcessHeap(), 0, upcase );
619 /**************************************************************************
620 * RtlUpcaseUnicodeToOemN (NTDLL.@)
622 NTSTATUS WINAPI RtlUpcaseUnicodeToOemN( LPSTR dst, DWORD dstlen, LPDWORD reslen,
623 LPCWSTR src, DWORD srclen )
629 if (!(upcase = RtlAllocateHeap( GetProcessHeap(), 0, srclen ))) return STATUS_NO_MEMORY;
630 for (i = 0; i < srclen/sizeof(WCHAR); i++) upcase[i] = toupperW(src[i]);
631 ret = RtlUnicodeToOemN( dst, dstlen, reslen, upcase, srclen );
632 RtlFreeHeap( GetProcessHeap(), 0, upcase );
641 /**************************************************************************
642 * RtlOemStringToUnicodeSize (NTDLL.@)
643 * RtlxOemStringToUnicodeSize (NTDLL.@)
645 * Return the size in bytes necessary for the Unicode conversion of 'str',
646 * including the terminating NULL.
648 UINT WINAPI RtlOemStringToUnicodeSize( const STRING *str )
650 int ret = cp_mbstowcs( get_oem_table(), 0, str->Buffer, str->Length, NULL, 0 );
651 return (ret + 1) * sizeof(WCHAR);
655 /**************************************************************************
656 * RtlAnsiStringToUnicodeSize (NTDLL.@)
657 * RtlxAnsiStringToUnicodeSize (NTDLL.@)
659 * Return the size in bytes necessary for the Unicode conversion of 'str',
660 * including the terminating NULL.
662 DWORD WINAPI RtlAnsiStringToUnicodeSize( const STRING *str )
665 RtlMultiByteToUnicodeSize( &ret, str->Buffer, str->Length );
666 return ret + sizeof(WCHAR);
670 /**************************************************************************
671 * RtlMultiByteToUnicodeSize (NTDLL.@)
673 * Compute the size in bytes necessary for the Unicode conversion of 'str',
674 * without the terminating NULL.
676 NTSTATUS WINAPI RtlMultiByteToUnicodeSize( DWORD *size, LPCSTR str, UINT len )
678 *size = cp_mbstowcs( get_ansi_table(), 0, str, len, NULL, 0 ) * sizeof(WCHAR);
679 return STATUS_SUCCESS;
683 /**************************************************************************
684 * RtlUnicodeToMultiByteSize (NTDLL.@)
686 * Compute the size necessary for the multibyte conversion of 'str',
687 * without the terminating NULL.
689 NTSTATUS WINAPI RtlUnicodeToMultiByteSize( DWORD *size, LPCWSTR str, UINT len )
691 *size = cp_wcstombs( get_ansi_table(), 0, str, len / sizeof(WCHAR), NULL, 0, NULL, NULL );
692 return STATUS_SUCCESS;
696 /**************************************************************************
697 * RtlUnicodeStringToAnsiSize (NTDLL.@)
698 * RtlxUnicodeStringToAnsiSize (NTDLL.@)
700 * Return the size in bytes necessary for the Ansi conversion of 'str',
701 * including the terminating NULL.
703 DWORD WINAPI RtlUnicodeStringToAnsiSize( const UNICODE_STRING *str )
706 RtlUnicodeToMultiByteSize( &ret, str->Buffer, str->Length );
711 /**************************************************************************
712 * RtlUnicodeStringToOemSize (NTDLL.@)
713 * RtlxUnicodeStringToOemSize (NTDLL.@)
715 * Return the size in bytes necessary for the OEM conversion of 'str',
716 * including the terminating NULL.
718 DWORD WINAPI RtlUnicodeStringToOemSize( const UNICODE_STRING *str )
720 return cp_wcstombs( get_oem_table(), 0, str->Buffer, str->Length / sizeof(WCHAR),
721 NULL, 0, NULL, NULL ) + 1;
725 /**************************************************************************
726 * RtlAppendStringToString (NTDLL.@)
728 NTSTATUS WINAPI RtlAppendStringToString( STRING *dst, const STRING *src )
730 unsigned int len = src->Length + dst->Length;
731 if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
732 memcpy( dst->Buffer + dst->Length, src->Buffer, src->Length );
734 return STATUS_SUCCESS;
738 /**************************************************************************
739 * RtlAppendAsciizToString (NTDLL.@)
741 NTSTATUS WINAPI RtlAppendAsciizToString( STRING *dst, LPCSTR src )
745 unsigned int srclen = strlen(src);
746 unsigned int total = srclen + dst->Length;
747 if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
748 memcpy( dst->Buffer + dst->Length, src, srclen );
751 return STATUS_SUCCESS;
755 /**************************************************************************
756 * RtlAppendUnicodeToString (NTDLL.@)
758 NTSTATUS WINAPI RtlAppendUnicodeToString( UNICODE_STRING *dst, LPCWSTR src )
762 unsigned int srclen = strlenW(src) * sizeof(WCHAR);
763 unsigned int total = srclen + dst->Length;
764 if (total > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
765 memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src, srclen );
767 /* append terminating NULL if enough space */
768 if (total < dst->MaximumLength) dst->Buffer[total / sizeof(WCHAR)] = 0;
770 return STATUS_SUCCESS;
774 /**************************************************************************
775 * RtlAppendUnicodeStringToString (NTDLL.@)
777 NTSTATUS WINAPI RtlAppendUnicodeStringToString( UNICODE_STRING *dst, const UNICODE_STRING *src )
779 unsigned int len = src->Length + dst->Length;
780 if (len > dst->MaximumLength) return STATUS_BUFFER_TOO_SMALL;
781 memcpy( dst->Buffer + dst->Length/sizeof(WCHAR), src->Buffer, src->Length );
783 /* append terminating NULL if enough space */
784 if (len < dst->MaximumLength) dst->Buffer[len / sizeof(WCHAR)] = 0;
785 return STATUS_SUCCESS;
793 /**************************************************************************
794 * RtlIsTextUnicode (NTDLL.@)
796 * Apply various feeble heuristics to guess whether
797 * the text buffer contains Unicode.
798 * FIXME: should implement more tests.
800 DWORD WINAPI RtlIsTextUnicode(
806 DWORD flags = -1, out_flags = 0;
813 * Apply various tests to the text string. According to the
814 * docs, each test "passed" sets the corresponding flag in
815 * the output flags. But some of the tests are mutually
816 * exclusive, so I don't see how you could pass all tests ...
819 /* Check for an odd length ... pass if even. */
821 out_flags |= IS_TEXT_UNICODE_ODD_LENGTH;
823 /* Check for the special unicode marker byte. */
825 out_flags |= IS_TEXT_UNICODE_SIGNATURE;
828 * Check whether the string passed all of the tests.
830 flags &= ITU_IMPLEMENTED_TESTS;
831 if ((out_flags & flags) != flags)