xref: /reactos/ntoskrnl/io/pnpmgr/pnputil.c (revision b8dd046e)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         BSD - See COPYING.ARM in the top level directory
4  * FILE:            ntoskrnl/io/pnpmgr/pnputil.c
5  * PURPOSE:         PnP Utility Code
6  * PROGRAMMERS:     ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
17 /* FUNCTIONS ******************************************************************/
18 
19 VOID
20 NTAPI
21 PnpFreeUnicodeStringList(IN PUNICODE_STRING UnicodeStringList,
22                          IN ULONG StringCount)
23 {
24     ULONG i;
25 
26     /* Go through the list */
27     if (UnicodeStringList)
28     {
29         /* Go through each string */
30         for (i = 0; i < StringCount; i++)
31         {
32             /* Check if it exists */
33             if (UnicodeStringList[i].Buffer)
34             {
35                 /* Free it */
36                 ExFreePool(UnicodeStringList[i].Buffer);
37             }
38         }
39 
40         /* Free the whole list */
41         ExFreePool(UnicodeStringList);
42     }
43 }
44 
45 NTSTATUS
46 NTAPI
47 PnpRegMultiSzToUnicodeStrings(IN PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
48                               OUT PUNICODE_STRING *UnicodeStringList,
49                               OUT PULONG UnicodeStringCount)
50 {
51     PWCHAR p, pp, ps;
52     ULONG i = 0;
53     SIZE_T n;
54     ULONG Count = 0;
55 
56     /* Validate the key information */
57     if (KeyValueInformation->Type != REG_MULTI_SZ) return STATUS_INVALID_PARAMETER;
58 
59     /* Set the pointers */
60     p = (PWCHAR)((ULONG_PTR)KeyValueInformation +
61                  KeyValueInformation->DataOffset);
62     pp = (PWCHAR)((ULONG_PTR)p + KeyValueInformation->DataLength);
63 
64     /* Loop the data */
65     while (p != pp)
66     {
67         /* If we find a NULL, that means one string is done */
68         if (!*p)
69         {
70             /* Add to our string count */
71             Count++;
72 
73             /* Check for a double-NULL, which means we're done */
74             if (((p + 1) == pp) || !(*(p + 1))) break;
75         }
76 
77         /* Go to the next character */
78         p++;
79     }
80 
81     /* If we looped the whole list over, we missed increment a string, do it */
82     if (p == pp) Count++;
83 
84     /* Allocate the list now that we know how big it is */
85     *UnicodeStringList = ExAllocatePoolWithTag(PagedPool,
86                                                sizeof(UNICODE_STRING) * Count,
87                                                'sUpP');
88     if (!(*UnicodeStringList)) return STATUS_INSUFFICIENT_RESOURCES;
89 
90     /* Set pointers for second loop */
91     ps = p = (PWCHAR)((ULONG_PTR)KeyValueInformation +
92                      KeyValueInformation->DataOffset);
93 
94     /* Loop again, to do the copy this time */
95     while (p != pp)
96     {
97         /* If we find a NULL, that means one string is done */
98         if (!*p)
99         {
100             /* Check how long this string is */
101             n = (ULONG_PTR)p - (ULONG_PTR)ps + sizeof(UNICODE_NULL);
102 
103             /* Allocate the buffer */
104             (*UnicodeStringList)[i].Buffer = ExAllocatePoolWithTag(PagedPool,
105                                                                    n,
106                                                                    'sUpP');
107             if (!(*UnicodeStringList)[i].Buffer)
108             {
109                 /* Back out of everything */
110                 PnpFreeUnicodeStringList(*UnicodeStringList, i);
111                 return STATUS_INSUFFICIENT_RESOURCES;
112             }
113 
114             /* Copy the string into the buffer */
115             RtlCopyMemory((*UnicodeStringList)[i].Buffer, ps, n);
116 
117             /* Set the lengths */
118             (*UnicodeStringList)[i].MaximumLength = (USHORT)n;
119             (*UnicodeStringList)[i].Length = (USHORT)(n - sizeof(UNICODE_NULL));
120 
121             /* One more entry done */
122             i++;
123 
124             /* Check for a double-NULL, which means we're done */
125             if (((p + 1) == pp) || !(*(p + 1))) break;
126 
127             /* New string */
128             ps = p + 1;
129         }
130 
131         /* New string */
132         p++;
133     }
134 
135     /* Check if we've reached the last string */
136     if (p == pp)
137     {
138         /* Calculate the string length */
139         n = (ULONG_PTR)p - (ULONG_PTR)ps;
140 
141         /* Allocate the buffer for it */
142         (*UnicodeStringList)[i].Buffer = ExAllocatePoolWithTag(PagedPool,
143                                                                n +
144                                                                sizeof(UNICODE_NULL),
145                                                                'sUpP');
146         if (!(*UnicodeStringList)[i].Buffer)
147         {
148             /* Back out of everything */
149             PnpFreeUnicodeStringList(*UnicodeStringList, i);
150             return STATUS_INSUFFICIENT_RESOURCES;
151         }
152 
153         /* Make sure there's an actual string here */
154         if (n) RtlCopyMemory((*UnicodeStringList)[i].Buffer, ps, n);
155 
156         /* Null-terminate the string ourselves */
157         (*UnicodeStringList)[i].Buffer[n / sizeof(WCHAR)] = UNICODE_NULL;
158 
159         /* Set the lengths */
160         (*UnicodeStringList)[i].Length = (USHORT)n;
161         (*UnicodeStringList)[i].MaximumLength = (USHORT)(n + sizeof(UNICODE_NULL));
162     }
163 
164     /* And we're done */
165     *UnicodeStringCount = Count;
166     return STATUS_SUCCESS;
167 }
168 
169 BOOLEAN
170 NTAPI
171 PnpRegSzToString(IN PWCHAR RegSzData,
172                  IN ULONG RegSzLength,
173                  OUT PUSHORT StringLength OPTIONAL)
174 {
175     PWCHAR p, pp;
176 
177     /* Find the end */
178     pp = RegSzData + RegSzLength / sizeof(WCHAR);
179     for (p = RegSzData; p < pp; p++)
180     {
181         if (!*p)
182         {
183             break;
184         }
185     }
186 
187     /* Return the length. Truncation can happen but is of no consequence. */
188     if (StringLength)
189     {
190         *StringLength = (USHORT)(p - RegSzData) * sizeof(WCHAR);
191     }
192     return TRUE;
193 }
194 
195 /* EOF */
196