1 /********************************************************************************
2 Copyright (C) 2016 Marvell International Ltd.
3 
4 Marvell BSD License Option
5 
6 If you received this File from Marvell, you may opt to use, redistribute and/or
7 modify this File under the following licensing terms.
8 Redistribution and use in source and binary forms, with or without modification,
9 are permitted provided that the following conditions are met:
10 
11 * Redistributions of source code must Retain the above copyright notice,
12   this list of conditions and the following disclaimer.
13 
14 * Redistributions in binary form must reproduce the above copyright
15   notice, this list of conditions and the following disclaimer in the
16   documentation and/or other materials provided with the distribution.
17 
18 * Neither the name of Marvell nor the names of its contributors may be
19   used to endorse or promote products derived from this software without
20   specific prior written permission.
21 
22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
29 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 
33 *******************************************************************************/
34 #define CHAR_NULL 0x0000
35 
36 #include <Library/BaseLib.h>
37 #include <Uefi.h>
38 #include <Library/UefiLib.h>
39 #include <Library/DebugLib.h>
40 
41 STATIC
42 CHAR16
CharToUpper(IN CHAR16 Char)43 CharToUpper (
44   IN CHAR16 Char
45   )
46 {
47 
48   if (Char >= L'a' && Char <= L'z') {
49     return (CHAR16) (Char - (L'a' - L'A'));
50   }
51 
52   return Char;
53 }
54 
55 STATIC
56 BOOLEAN
IsDecimalDigitChar(IN CHAR16 Char)57 IsDecimalDigitChar (
58   IN CHAR16 Char
59   )
60 {
61 
62   return (BOOLEAN) (Char >= L'0' && Char <= L'9');
63 }
64 
65 
66 STATIC
67 UINTN
HexCharToUintn(IN CHAR16 Char)68 HexCharToUintn (
69   IN CHAR16 Char
70   )
71 {
72   if (IsDecimalDigitChar (Char)) {
73     return Char - L'0';
74   }
75 
76   return (UINTN) (10 + CharToUpper (Char) - L'A');
77 }
78 
79 STATIC
80 BOOLEAN
IsHexDigitCharacter(CHAR16 Char)81 IsHexDigitCharacter (
82   CHAR16 Char
83   )
84 {
85 
86   return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' &&
87     Char <= L'F') || (Char >= L'a' && Char <= L'f'));
88 }
89 
90 STATIC
91 UINTN
HexStrToUintn(CHAR16 * String)92 HexStrToUintn (
93   CHAR16 *String
94   )
95 {
96   UINTN Result = 0;
97 
98   if (String == NULL || StrSize(String) == 0) {
99     return (UINTN)(-1);
100   }
101 
102   // Ignore spaces and tabs
103   while ((*String == L' ') || (*String == L'\t')) {
104     String++;
105   }
106 
107   // Ignore leading zeros after spaces
108   while (*String == L'0') {
109     String++;
110   }
111 
112   if (CharToUpper (*String) != L'X') {
113     return (UINTN)(-1);
114   }
115 
116   // Skip 'x'
117   String++;
118 
119   while (IsHexDigitCharacter (*String)) {
120     Result <<= 4;
121     Result += HexCharToUintn (*String);
122     String++;
123   }
124 
125   return (UINTN) Result;
126 }
127 
128 STATIC
129 UINTN
DecimalStrToUintn(CHAR16 * String)130 DecimalStrToUintn (
131   CHAR16 *String
132   )
133 {
134   UINTN Result = 0;
135 
136   while (IsDecimalDigitChar (*String)) {
137     Result = 10 * Result + (*String - L'0');
138     String++;
139   }
140 
141   return Result;
142 }
143 
144 STATIC
145 UINTN
StrToUintn(CHAR16 * String)146 StrToUintn (
147   CHAR16 *String
148   )
149 {
150   CHAR16 *Walker;
151 
152   // Chop off leading spaces
153   for (Walker = String; Walker != NULL && *Walker != CHAR_NULL && *Walker == L' '; Walker++);
154 
155   if (StrnCmp(Walker, L"0x", 2) == 0 || StrnCmp(Walker, L"0X", 2) == 0) {
156     return HexStrToUintn (Walker);
157   } else {
158     return DecimalStrToUintn (Walker);
159   }
160 }
161 
162 EFI_STATUS
ParsePcdString(IN CHAR16 * PcdString,IN UINT8 Count,OUT UINTN * ValueTable,OUT CHAR16 ** StrTable)163 ParsePcdString (
164   IN  CHAR16 *PcdString,
165   IN  UINT8  Count,
166   OUT UINTN  *ValueTable,
167   OUT CHAR16 **StrTable
168   )
169 {
170   BOOLEAN ValueFlag = FALSE;
171   CHAR16 *Walker;
172   UINTN i, Tmp = 0;
173 
174   if (ValueTable != NULL) {
175     ValueFlag = TRUE;
176   }
177 
178   // Set pointer at the end of PCD string
179   Walker = PcdString + StrLen (PcdString);
180   for (i = 0; i < Count; i++) {
181     while ((--Walker) >= PcdString) {
182       if (*Walker == L';') {
183         // Cut off parsed chunk from PCD string by replacing ';' with
184         // null-terminator
185         *Walker = '\0';
186         if (ValueFlag) {
187           Tmp = StrToUintn ((Walker + 1));
188           if ((UINTN)(-1) == Tmp) {
189             return EFI_INVALID_PARAMETER;
190           }
191           // Entry is parsed from the end to the beginning
192           // so fill table in the same manner
193           ValueTable[Count - (i + 1)] = Tmp;
194         } else {
195           StrTable[Count - (i + 1)] = Walker + 1;
196         }
197         Walker--;
198         break;
199       }
200       if (Walker == PcdString) {
201         if (ValueFlag) {
202           Tmp = StrToUintn ((Walker));
203           if (Tmp == (UINTN)(-1)) {
204             return EFI_INVALID_PARAMETER;
205           }
206         }
207         // Last device's entry should be added to the table here.
208         // If not, return error
209         if (i != (Count - 1)) {
210           DEBUG((DEBUG_ERROR, "ParsePcdLib: Please set PCD value for every "
211             "device\n"));
212           return EFI_INVALID_PARAMETER;
213         }
214         // We parse from the end to the beginning
215         // so fill table in the same manner
216         if (ValueFlag) {
217           ValueTable[Count - (i + 1)] = Tmp;
218         } else {
219           StrTable[Count - (i + 1)] = Walker;
220         }
221         // End both loops
222         return EFI_SUCCESS;
223       }
224     }
225   }
226 
227   return EFI_SUCCESS;
228 }
229