Repository: tianocore/edk2-pytool-library

Issue:
[Bug]: \edk2toollib\uefi\edk2\parsers\dec_parser.py fails parsing PCDs when a string contains '|'
### Contact Details

_No response_

### Describe the Bug

File: \edk2toollib\uefi\edk2\parsers\dec_parser.py 
Class: PcdDeclarationEntry()
Function: _parse(self, rawtext: str)

Code Snip:

``` python
    def _parse(self, rawtext: str):
        """Parses the PcdDeclaration Entry for one PCD."""
        sp = rawtext.partition(".")
        self.token_space_name = sp[0].strip()
        op = sp[2].split("|")
        # if it's 2 long, we need to check that it's a structured PCD
        if (len(op) == 2 and op[0].count(".") > 0):
            pass
        # otherwise it needs at least 4 parts
        elif (len(op) < 4):
            raise Exception(f"Too few parts: {op}")
        # but also less than 5
        elif (len(op) > 5):
            raise Exception(f"Too many parts: {rawtext}")
        elif (len(op) == 5 and op[4].strip() != '{'):
            raise Exception(f"Too many parts: {rawtext}")
```

If the following line to declare PcdTestString is used in a .DEC file:
    gTestTokenSpaceGuid.PcdTestString | L"TestVal_1 | TestVal_2" | VOID* | 0x00010001

This code will fail due to not detecting the second '|' character is part of the assignment string.


### Reproduction steps

1. Assign a string (VOID*) PCD to a string value that contains a '|' character
2. Run the pip module dec parser to collect all information from that DEC file

### Expected behavior

The DEC file parser should recognize the quotes around the PCD's string value and ignore any pertinent chars used when parsing the assignment line.

### What Python version are you using?

Python 3.10

### Execution Environment

Python 3.10.7


### Pip packages

Package                Version
---------------------- ---------
antlr4-python3-runtime 4.7.1
astroid                2.13.2
asttokens              2.2.1
attrs                  22.1.0
cffi                   1.15.1
colorama               0.4.6
cryptography           3.3.1
dill                   0.3.6
docutils               0.19
dtschema               2021.10
edk2-basetools         0.1.39
edk2-pytool-extensions 0.21.1
edk2-pytool-library    0.12.1
elementpath            3.0.2
future                 0.18.2
gitdb                  4.0.10
GitPython              3.1.29
isort                  5.11.4
jedi                   0.18.2
jsonschema             4.0.0
lazy-object-proxy      1.9.0
mccabe                 0.7.0
mypy                   0.991
mypy-extensions        0.4.3
parso                  0.8.3
pefile                 2022.5.30
pip                    22.3.1
platformdirs           2.6.2
pycparser              2.21
pygit2                 1.11.1
pylint                 2.15.10
pyrsistent             0.19.1
pyserial               3.5
PyYAML                 6.0
regex                  2022.8.17
rfc3987                1.3.8
ruamel.yaml            0.17.17
semantic-version       2.10.0
Send2Trash             1.8.0
setuptools             63.2.0
six                    1.16.0
smmap                  5.0.0
thonny                 4.0.1
tomli                  2.0.1
tomlkit                0.11.6
typing_extensions      4.4.0
wheel                  0.38.4
wrapt                  1.14.1
xmlschema              2.0.1


### Additional context

The standard UEFI build process is OK with the '|' in a PCD string, it appears to be just this parser that has trouble.

Comments:

Patch:
diff --git a/edk2toollib/uefi/edk2/parsers/dec_parser.py b/edk2toollib/uefi/edk2/parsers/dec_parser.py
index 8c3c7aa..0a94464 100644
--- a/edk2toollib/uefi/edk2/parsers/dec_parser.py
+++ b/edk2toollib/uefi/edk2/parsers/dec_parser.py
@@ -7,6 +7,7 @@
 ##
 """Code to help parse DEC files."""
 import os
+import re
 
 from edk2toollib.uefi.edk2.parsers.base_parser import HashFileParser
 from edk2toollib.uefi.edk2.parsers.guid_parser import GuidParser
@@ -123,7 +124,11 @@ def _parse(self, rawtext: str):
         """Parses the PcdDeclaration Entry for one PCD."""
         sp = rawtext.partition(".")
         self.token_space_name = sp[0].strip()
-        op = sp[2].split("|")
+
+        # Regular expression pattern to match the symbol '|' that is not inside quotes
+        pattern = r'\|(?=(?:[^\'"]*[\'"][^\'"]*[\'"])*[^\'"]*$)'
+        op = re.split(pattern, sp[2])
+
         # if it's 2 long, we need to check that it's a structured PCD
         if (len(op) == 2 and op[0].count(".") > 0):
             pass


Test patch:
diff --git a/tests.unit/parsers/test_dec_parser.py b/tests.unit/parsers/test_dec_parser.py
index 528a256..a34bd1b 100644
--- a/tests.unit/parsers/test_dec_parser.py
+++ b/tests.unit/parsers/test_dec_parser.py
@@ -7,15 +7,18 @@
 # SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
 
+import io
 import unittest
 import uuid
-import io
-from edk2toollib.uefi.edk2.parsers.dec_parser import LibraryClassDeclarationEntry
-from edk2toollib.uefi.edk2.parsers.dec_parser import GuidDeclarationEntry
-from edk2toollib.uefi.edk2.parsers.dec_parser import PpiDeclarationEntry
-from edk2toollib.uefi.edk2.parsers.dec_parser import ProtocolDeclarationEntry
-from edk2toollib.uefi.edk2.parsers.dec_parser import PcdDeclarationEntry
-from edk2toollib.uefi.edk2.parsers.dec_parser import DecParser
+
+from edk2toollib.uefi.edk2.parsers.dec_parser import (
+    DecParser,
+    GuidDeclarationEntry,
+    LibraryClassDeclarationEntry,
+    PcdDeclarationEntry,
+    PpiDeclarationEntry,
+    ProtocolDeclarationEntry,
+)
 
 
 class TestGuidDeclarationEntry(unittest.TestCase):
@@ -107,6 +110,22 @@ def test_bad_structured_input(self):
         with self.assertRaises(Exception):
             PcdDeclarationEntry("testpkg", SAMPLE_DATA_DECL)
 
+    def test_string_containing_a_pipe(self):
+        SAMPLE_DATA_DECL = """gTestTokenSpaceGuid.PcdTestString | L"TestVal_1 | TestVal_2" | VOID* | 0x00010001"""
+        a = PcdDeclarationEntry("testpkg", SAMPLE_DATA_DECL)
+        self.assertEqual(a.token_space_name, "gTestTokenSpaceGuid")
+        self.assertEqual(a.name, "PcdTestString")
+        self.assertEqual(a.default_value, "L\"TestVal_1 | TestVal_2\"")
+        self.assertEqual(a.type, "VOID*")
+        self.assertEqual(a.id, "0x00010001")
+
+        SAMPLE_DATA_DECL = """gTestTokenSpaceGuid.PcdTestString | L'TestVal_1 | TestVal_2' | VOID* | 0x00010001"""
+        a = PcdDeclarationEntry("testpkg", SAMPLE_DATA_DECL)
+        self.assertEqual(a.token_space_name, "gTestTokenSpaceGuid")
+        self.assertEqual(a.name, "PcdTestString")
+        self.assertEqual(a.default_value, "L'TestVal_1 | TestVal_2'")
+        self.assertEqual(a.type, "VOID*")
+        self.assertEqual(a.id, "0x00010001")
 
 class TestDecParser(unittest.TestCase):