• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2 
3   EFI_REGULAR_EXPRESSION_PROTOCOL Implementation
4 
5   (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6 
7   This program and the accompanying materials are licensed and made available
8   under the terms and conditions of the BSD License that accompanies this
9   distribution.  The full text of the license may be found at
10   http://opensource.org/licenses/bsd-license.php.
11 
12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
13   WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14 
15 **/
16 
17 #include "RegularExpressionDxe.h"
18 
19 STATIC
20 EFI_REGEX_SYNTAX_TYPE * CONST mSupportedSyntaxes[] = {
21   &gEfiRegexSyntaxTypePosixExtendedGuid,
22   &gEfiRegexSyntaxTypePerlGuid
23 };
24 
25 STATIC
26 EFI_REGULAR_EXPRESSION_PROTOCOL mProtocolInstance = {
27   RegularExpressionMatch,
28   RegularExpressionGetInfo
29 };
30 
31 
32 
33 #define CHAR16_ENCODING ONIG_ENCODING_UTF16_LE
34 
35 /**
36   Call the Oniguruma regex match API.
37 
38   Same parameters as RegularExpressionMatch, except SyntaxType is required.
39 
40   @param String         A pointer to a NULL terminated string to match against the
41                         regular expression string specified by Pattern.
42 
43   @param Pattern        A pointer to a NULL terminated string that represents the
44                         regular expression.
45   @param SyntaxType     A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
46                         regular expression syntax type to use. May be NULL in which
47                         case the function will use its default regular expression
48                         syntax type.
49 
50   @param Result         On return, points to TRUE if String fully matches against
51                         the regular expression Pattern using the regular expression
52                         SyntaxType. Otherwise, points to FALSE.
53 
54   @param Captures       A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
55                         the captured groups in the event of a match. The full
56                         sub-string match is put in Captures[0], and the results of N
57                         capturing groups are put in Captures[1:N]. If Captures is
58                         NULL, then this function doesn't allocate the memory for the
59                         array and does not build up the elements. It only returns the
60                         number of matching patterns in CapturesCount. If Captures is
61                         not NULL, this function returns a pointer to an array and
62                         builds up the elements in the array. CapturesCount is also
63                         updated to the number of matching patterns found. It is the
64                         caller's responsibility to free the memory pool in Captures
65                         and in each CapturePtr in the array elements.
66 
67   @param CapturesCount  On output, CapturesCount is the number of matching patterns
68                         found in String. Zero means no matching patterns were found
69                         in the string.
70 
71   @retval  EFI_SUCCESS       Regex compilation and match completed successfully.
72   @retval  EFI_DEVICE_ERROR  Regex compilation failed.
73 
74 **/
75 STATIC
76 EFI_STATUS
OnigurumaMatch(IN CHAR16 * String,IN CHAR16 * Pattern,IN EFI_REGEX_SYNTAX_TYPE * SyntaxType,OUT BOOLEAN * Result,OUT EFI_REGEX_CAPTURE ** Captures,OPTIONAL OUT UINTN * CapturesCount)77 OnigurumaMatch (
78   IN  CHAR16                *String,
79   IN  CHAR16                *Pattern,
80   IN  EFI_REGEX_SYNTAX_TYPE *SyntaxType,
81   OUT BOOLEAN               *Result,
82   OUT EFI_REGEX_CAPTURE     **Captures,     OPTIONAL
83   OUT UINTN                 *CapturesCount
84   )
85 {
86   regex_t         *OnigRegex;
87   OnigSyntaxType  *OnigSyntax;
88   OnigRegion      *Region;
89   INT32           OnigResult;
90   OnigErrorInfo   ErrorInfo;
91   CHAR8           ErrorMessage[ONIG_MAX_ERROR_MESSAGE_LEN];
92   UINT32          Index;
93   OnigUChar       *Start;
94 
95   //
96   // Detemine the internal syntax type
97   //
98   OnigSyntax = ONIG_SYNTAX_DEFAULT;
99   if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePosixExtendedGuid)) {
100     OnigSyntax = ONIG_SYNTAX_POSIX_EXTENDED;
101   } else if (CompareGuid (SyntaxType, &gEfiRegexSyntaxTypePerlGuid)) {
102     OnigSyntax = ONIG_SYNTAX_PERL;
103   } else {
104     DEBUG ((DEBUG_ERROR, "Unsupported regex syntax - using default\n"));
105     ASSERT (FALSE);
106   }
107 
108   //
109   // Compile pattern
110   //
111   Start = (OnigUChar*)Pattern;
112   OnigResult = onig_new (
113                  &OnigRegex,
114                  Start,
115                  Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
116                  ONIG_OPTION_DEFAULT,
117                  CHAR16_ENCODING,
118                  OnigSyntax,
119                  &ErrorInfo
120                  );
121 
122   if (OnigResult != ONIG_NORMAL) {
123     onig_error_code_to_str (ErrorMessage, OnigResult, &ErrorInfo);
124     DEBUG ((DEBUG_ERROR, "Regex compilation failed: %a\n", ErrorMessage));
125     return EFI_DEVICE_ERROR;
126   }
127 
128   //
129   // Try to match
130   //
131   Start = (OnigUChar*)String;
132   Region = onig_region_new ();
133   if (Region == NULL) {
134     onig_free (OnigRegex);
135     return EFI_OUT_OF_RESOURCES;
136   }
137   OnigResult = onig_search (
138                  OnigRegex,
139                  Start,
140                  Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
141                  Start,
142                  Start + onigenc_str_bytelen_null (CHAR16_ENCODING, Start),
143                  Region,
144                  ONIG_OPTION_NONE
145                  );
146   if (OnigResult >= 0) {
147     *Result = TRUE;
148   } else {
149     *Result = FALSE;
150     if (OnigResult != ONIG_MISMATCH) {
151       onig_error_code_to_str (ErrorMessage, OnigResult);
152       DEBUG ((DEBUG_ERROR, "Regex match failed: %a\n", ErrorMessage));
153     }
154   }
155 
156   //
157   // If successful, copy out the region (capture) information
158   //
159   if (*Result && Captures != NULL) {
160     *CapturesCount = Region->num_regs;
161     *Captures = AllocatePool (*CapturesCount * sizeof(**Captures));
162     if (*Captures != NULL) {
163       for (Index = 0; Index < *CapturesCount; ++Index) {
164         //
165         // Region beg/end values represent bytes, not characters
166         //
167         (*Captures)[Index].CapturePtr = (CHAR16*)((UINTN)String + Region->beg[Index]);
168         (*Captures)[Index].Length = (Region->end[Index] - Region->beg[Index]) / sizeof(CHAR16);
169       }
170     }
171   }
172 
173   onig_region_free (Region, 1);
174   onig_free (OnigRegex);
175 
176   return EFI_SUCCESS;
177 }
178 
179 /**
180   Returns information about the regular expression syntax types supported
181   by the implementation.
182 
183   @param This                      A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL
184                                    instance.
185 
186   @param  RegExSyntaxTypeListSize  On input, the size in bytes of RegExSyntaxTypeList.
187                                    On output with a return code of EFI_SUCCESS, the
188                                    size in bytes of the data returned in
189                                    RegExSyntaxTypeList. On output with a return code
190                                    of EFI_BUFFER_TOO_SMALL, the size of
191                                    RegExSyntaxTypeList required to obtain the list.
192 
193   @param   RegExSyntaxTypeList     A caller-allocated memory buffer filled by the
194                                    driver with one EFI_REGEX_SYNTAX_TYPE element
195                                    for each supported Regular expression syntax
196                                    type. The list must not change across multiple
197                                    calls to the same driver. The first syntax
198                                    type in the list is the default type for the
199                                    driver.
200 
201   @retval EFI_SUCCESS            The regular expression syntax types list
202                                  was returned successfully.
203   @retval EFI_UNSUPPORTED        The service is not supported by this driver.
204   @retval EFI_DEVICE_ERROR       The list of syntax types could not be
205                                  retrieved due to a hardware or firmware error.
206   @retval EFI_BUFFER_TOO_SMALL   The buffer RegExSyntaxTypeList is too small
207                                  to hold the result.
208   @retval EFI_INVALID_PARAMETER  RegExSyntaxTypeListSize is NULL
209 
210 **/
211 EFI_STATUS
212 EFIAPI
RegularExpressionGetInfo(IN EFI_REGULAR_EXPRESSION_PROTOCOL * This,IN OUT UINTN * RegExSyntaxTypeListSize,OUT EFI_REGEX_SYNTAX_TYPE * RegExSyntaxTypeList)213 RegularExpressionGetInfo (
214   IN     EFI_REGULAR_EXPRESSION_PROTOCOL *This,
215   IN OUT UINTN                           *RegExSyntaxTypeListSize,
216   OUT    EFI_REGEX_SYNTAX_TYPE           *RegExSyntaxTypeList
217   )
218 {
219   UINTN SyntaxSize;
220   UINTN Index;
221 
222   if (This == NULL || RegExSyntaxTypeListSize == NULL) {
223     return EFI_INVALID_PARAMETER;
224   }
225 
226   if (*RegExSyntaxTypeListSize != 0 && RegExSyntaxTypeList == NULL) {
227     return EFI_INVALID_PARAMETER;
228   }
229 
230   SyntaxSize = ARRAY_SIZE (mSupportedSyntaxes) * sizeof(**mSupportedSyntaxes);
231 
232   if (*RegExSyntaxTypeListSize < SyntaxSize) {
233     *RegExSyntaxTypeListSize = SyntaxSize;
234     return EFI_BUFFER_TOO_SMALL;
235   }
236 
237   for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) {
238     CopyMem (&RegExSyntaxTypeList[Index], mSupportedSyntaxes[Index], sizeof(**mSupportedSyntaxes));
239   }
240   *RegExSyntaxTypeListSize = SyntaxSize;
241 
242   return EFI_SUCCESS;
243 }
244 
245 /**
246   Checks if the input string matches to the regular expression pattern.
247 
248   @param This          A pointer to the EFI_REGULAR_EXPRESSION_PROTOCOL instance.
249                        Type EFI_REGULAR_EXPRESSION_PROTOCOL is defined in Section
250                        XYZ.
251 
252   @param String        A pointer to a NULL terminated string to match against the
253                        regular expression string specified by Pattern.
254 
255   @param Pattern       A pointer to a NULL terminated string that represents the
256                        regular expression.
257 
258   @param SyntaxType    A pointer to the EFI_REGEX_SYNTAX_TYPE that identifies the
259                        regular expression syntax type to use. May be NULL in which
260                        case the function will use its default regular expression
261                        syntax type.
262 
263   @param Result        On return, points to TRUE if String fully matches against
264                        the regular expression Pattern using the regular expression
265                        SyntaxType. Otherwise, points to FALSE.
266 
267   @param Captures      A Pointer to an array of EFI_REGEX_CAPTURE objects to receive
268                        the captured groups in the event of a match. The full
269                        sub-string match is put in Captures[0], and the results of N
270                        capturing groups are put in Captures[1:N]. If Captures is
271                        NULL, then this function doesn't allocate the memory for the
272                        array and does not build up the elements. It only returns the
273                        number of matching patterns in CapturesCount. If Captures is
274                        not NULL, this function returns a pointer to an array and
275                        builds up the elements in the array. CapturesCount is also
276                        updated to the number of matching patterns found. It is the
277                        caller's responsibility to free the memory pool in Captures
278                        and in each CapturePtr in the array elements.
279 
280   @param CapturesCount On output, CapturesCount is the number of matching patterns
281                        found in String. Zero means no matching patterns were found
282                        in the string.
283 
284   @retval EFI_SUCCESS            The regular expression string matching
285                                  completed successfully.
286   @retval EFI_UNSUPPORTED        The regular expression syntax specified by
287                                  SyntaxType is not supported by this driver.
288   @retval EFI_DEVICE_ERROR       The regular expression string matching
289                                  failed due to a hardware or firmware error.
290   @retval EFI_INVALID_PARAMETER  String, Pattern, Result, or CapturesCountis
291                                  NULL.
292 
293 **/
294 EFI_STATUS
295 EFIAPI
RegularExpressionMatch(IN EFI_REGULAR_EXPRESSION_PROTOCOL * This,IN CHAR16 * String,IN CHAR16 * Pattern,IN EFI_REGEX_SYNTAX_TYPE * SyntaxType,OPTIONAL OUT BOOLEAN * Result,OUT EFI_REGEX_CAPTURE ** Captures,OPTIONAL OUT UINTN * CapturesCount)296 RegularExpressionMatch (
297   IN  EFI_REGULAR_EXPRESSION_PROTOCOL *This,
298   IN  CHAR16                          *String,
299   IN  CHAR16                          *Pattern,
300   IN  EFI_REGEX_SYNTAX_TYPE           *SyntaxType, OPTIONAL
301   OUT BOOLEAN                         *Result,
302   OUT EFI_REGEX_CAPTURE               **Captures, OPTIONAL
303   OUT UINTN                           *CapturesCount
304   )
305 {
306   EFI_STATUS  Status;
307   UINT32      Index;
308   BOOLEAN     Supported;
309 
310   if (This == NULL || String == NULL || Pattern == NULL || Result == NULL || CapturesCount == NULL) {
311     return EFI_INVALID_PARAMETER;
312   }
313 
314   //
315   // Figure out which syntax to use
316   //
317   if (SyntaxType == NULL) {
318     SyntaxType = mSupportedSyntaxes[0];
319   } else {
320     Supported = FALSE;
321     for (Index = 0; Index < ARRAY_SIZE (mSupportedSyntaxes); ++Index) {
322       if (CompareGuid (SyntaxType, mSupportedSyntaxes[Index])) {
323         Supported = TRUE;
324         break;
325       }
326     }
327     if (!Supported) {
328       return EFI_UNSUPPORTED;
329     }
330   }
331 
332   Status = OnigurumaMatch (String, Pattern, SyntaxType, Result, Captures, CapturesCount);
333 
334   return Status;
335 }
336 
337 /**
338   Entry point for RegularExpressionDxe.
339 
340   @param ImageHandle     Image handle this driver.
341   @param SystemTable     Pointer to SystemTable.
342 
343   @retval Status         Whether this function complete successfully.
344 
345 **/
346 EFI_STATUS
347 EFIAPI
RegularExpressionDxeEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)348 RegularExpressionDxeEntry (
349   IN  EFI_HANDLE        ImageHandle,
350   IN  EFI_SYSTEM_TABLE  *SystemTable
351   )
352 {
353   EFI_STATUS  Status;
354 
355   Status = gBS->InstallMultipleProtocolInterfaces (
356                   &ImageHandle,
357                   &gEfiRegularExpressionProtocolGuid,
358                   &mProtocolInstance,
359                   NULL
360                   );
361 
362   return Status;
363 }
364