Fixed misleading naming "strcmp" returning gboolean: -> "compare"
[captive.git] / src / libcaptive / fs / name.c
1 /* $Id$
2  * reactos filesystem name strings functions emulation of libcaptive
3  * Copyright (C) 2002 Jan Kratochvil <project-captive@jankratochvil.net>
4  * 
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; exactly version 2 of June 1991 is required
8  * 
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  * 
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18
19
20 #include "config.h"
21
22 #include "reactos/ddk/fsfuncs.h"        /* self */
23 #include <glib/gmessages.h>
24 #include "captive/unicode.h"
25 #include "reactos/unicode.h"    /* for ANSI_* */
26 #include "captive/macros.h"
27 #include <ctype.h>
28
29
30 UCHAR **FsRtlLegalAnsiCharacterArray;
31
32
33 /**
34  * captive_FsRtlLegalAnsiCharacterArray_init:
35  * Initialize #FsRtlLegalAnsiCharacterArray character classes
36  * by appropriate #FSRTL_FAT_LEGAL etc. flags.
37  */
38 void captive_FsRtlLegalAnsiCharacterArray_init(void)
39 {
40 static UCHAR *array;
41 guint ui;
42 const gchar fat_valid[]="!#&(-./@_~";
43
44         /* Use allocation instead of static array to get ElectricFence sanity boundaries.
45          * Use even the negative 0x80 part as someone may access 'FsRtlLegalAnsiCharacterArray'
46          * with 'signed char' (but also with 'unsigned char'). See also memcpy(3) below.
47          */
48         captive_new0n(array,0x80+0x100);
49         array+=0x80;
50
51         for (ui=0;ui<0x100;ui++) {
52 UCHAR f=0;
53
54                 if (isalnum(ui) || strchr(fat_valid,ui))
55                         f|=FSRTL_FAT_LEGAL;
56                 if (isalnum(ui) || strchr(fat_valid,ui))
57                         f|=FSRTL_HPFS_LEGAL;
58                 if (isalnum(ui) || strchr(fat_valid,ui))
59                         f|=FSRTL_NTFS_LEGAL;
60                 if (ui=='*' || ui=='?')
61                         f|=FSRTL_WILD_CHARACTER;
62                 if (isalnum(ui))
63                         f|=FSRTL_OLE_LEGAL;
64
65                 array[(unsigned int)(unsigned char)ui]=f;
66                 }
67
68         memcpy(array-0x80,array+0x80,0x80*sizeof(*array));
69
70         FsRtlLegalAnsiCharacterArray=&array;
71 }
72
73
74 /**
75  * FsRtlDoesNameContainWildCards:
76  * @Name: Filename to check for wildcards.
77  * %NULL value is forbidden.
78  * Non-zero terminated #PUNICODE_STRING is permitted.
79  *
80  * Check if @Name contains wildcard markers as its substring(s).
81  *
82  * Returns: %TRUE if @Name contains "*", "?", %ANSI_DOS_STAR, %ANSI_DOS_DOT or %ANSI_DOS_QM.
83  */
84 BOOLEAN FsRtlDoesNameContainWildCards(IN PUNICODE_STRING Name)
85 {
86 const UNICODE_STRING *cName=Name;
87 const WCHAR *wcp;
88
89         g_return_val_if_fail(captive_validate_UnicodeString_noterm(cName),FALSE);
90
91         for (wcp=cName->Buffer;wcp<cName->Buffer+(cName->Length/sizeof(*cName->Buffer));*wcp++)
92                 if (0
93                                 || *wcp=='*'
94                                 || *wcp=='?'
95                                 || *wcp==ANSI_DOS_STAR
96                                 || *wcp==ANSI_DOS_DOT
97                                 || *wcp==ANSI_DOS_QM)
98                         return TRUE;
99         return FALSE;
100 }
101
102
103 /**
104  * FsRtlDissectName:
105  * @Path_noterm: Initialized #UNICODE_STRING to parse.
106  * @FirstName: Returns the first filename from @Path_noterm.
107  * %NULL value is forbidden.
108  * @RemainingName: Returns the part of @Path_noterm behind @FirstName.
109  * %NULL value is forbidden.
110  *
111  * Will parse @Path_noterm as regex (FirstName,RemainingName)=/^\?([^/]*)/?(.*)$/;
112  * @FirstName and @RemainingName must be pointers to allocated #UNICODE_STRING
113  * but their #Buffer will be pointing to inside @Path_noterm buffer afterwards.
114  * Therefore do not free it! The returned strings may not be 0-terminated strings.
115  *
116  * @Path_noterm does not neet to be zero-terminated.
117  */
118 VOID FsRtlDissectName(IN UNICODE_STRING Path_noterm,OUT PUNICODE_STRING FirstName,OUT PUNICODE_STRING RemainingName)
119 {
120 PWSTR Path_end;
121 PWSTR delim_FirstName_start    ,delim_FirstName_end;
122 PWSTR delim_RemainingName_start,delim_RemainingName_end;
123
124         g_return_if_fail(captive_validate_UnicodeString_noterm(&Path_noterm));
125         g_return_if_fail(FirstName!=NULL);
126         g_return_if_fail(RemainingName!=NULL);
127
128         Path_end=Path_noterm.Buffer+Path_noterm.Length/sizeof(*Path_noterm.Buffer);
129
130         delim_FirstName_start=Path_noterm.Buffer;
131         if (delim_FirstName_start<Path_end && *delim_FirstName_start=='\\')
132                 delim_FirstName_start++;
133         for (delim_FirstName_end=delim_FirstName_start;
134                         delim_FirstName_end<Path_end && *delim_FirstName_end!='\\';
135                         delim_FirstName_end++);
136         delim_RemainingName_start=delim_FirstName_end;
137         if (delim_RemainingName_start<Path_end && *delim_RemainingName_start=='\\')
138                 delim_RemainingName_start++;
139         delim_RemainingName_end=Path_end;
140
141         g_assert(delim_FirstName_start    <=delim_FirstName_end);
142         g_assert(delim_FirstName_end      <=delim_RemainingName_start);
143         g_assert(delim_RemainingName_start<=delim_RemainingName_end);
144
145         FirstName->Buffer=delim_FirstName_start;
146         FirstName->Length=(delim_FirstName_end-delim_FirstName_start)*sizeof(*FirstName->Buffer);
147         FirstName->MaximumLength=FirstName->Length;
148         FirstName->Buffer=delim_FirstName_start;
149
150         RemainingName->Buffer=delim_RemainingName_start;
151         RemainingName->Length=(delim_RemainingName_end-delim_RemainingName_start)*sizeof(*RemainingName->Buffer);
152         RemainingName->MaximumLength=RemainingName->Length;
153         RemainingName->Buffer=delim_RemainingName_start;
154 }
155
156
157 /**
158  * FsRtlAreNamesEqual:
159  * @Name1: First filesystem name (FIXME: pathname or basename?) of type #PUNICODE_STRING.
160  * Invalid string input is forbidden.
161  * @Name2: Second filesystem name (FIXME: pathname or basename?) of type #PUNICODE_STRING.
162  * Invalid string input is forbidden.
163  * @IgnoreCase: Compare @Name1 and @Name2 case-insensitively?
164  * @UpcaseTable:
165  * %NULL value is required if @IgnoreCase==%FALSE.
166  * TODO: NOT IMPLEMENTED YET.
167  *
168  * Compare the given filenames if they match according to the specified criteria.
169  * FIXME: libcaptive implements this function currently as captive_UnicodeString_compare_insensitive()
170  * or captive_UnicodeString_compare(); How are filesystem names specific from regular strings?
171  *
172  * Returns: %TRUE if @Name1 and @Name2 match.
173  */
174 BOOLEAN FsRtlAreNamesEqual
175                 (IN PUNICODE_STRING Name1,IN PUNICODE_STRING Name2,IN BOOLEAN IgnoreCase,IN PWCHAR UpcaseTable OPTIONAL)
176 {
177         g_return_val_if_fail(captive_validate_UnicodeString(Name1),FALSE);
178         g_return_val_if_fail(FsRtlDoesNameContainWildCards(Name1)==FALSE,FALSE);
179         g_return_val_if_fail(captive_validate_UnicodeString(Name2),FALSE);
180         g_return_val_if_fail(FsRtlDoesNameContainWildCards(Name2)==FALSE,FALSE);
181         g_return_val_if_fail(UpcaseTable==NULL,FALSE);  /* TODO: NOT IMPLEMENTED YET */
182         /* Do not permit passing of 'UpcaseTable' if it would not make any sense.
183          * Just a sanity check, it should not harm. Such assertion is not mandatory by W32 doc.
184          */
185         g_return_val_if_fail((IgnoreCase==FALSE && UpcaseTable==NULL) || IgnoreCase==TRUE,FALSE);
186
187         if (IgnoreCase)
188                 return captive_UnicodeString_compare_insensitive(Name1,Name2);
189         else
190                 return captive_UnicodeString_compare            (Name1,Name2);
191 }