diff --git a/src/ms_ovba/Models/Entities/module_base.py b/src/ms_ovba/Models/Entities/module_base.py index 1f8d734e5..82dd6f691 100644 --- a/src/ms_ovba/Models/Entities/module_base.py +++ b/src/ms_ovba/Models/Entities/module_base.py @@ -4,7 +4,7 @@ ) from ms_ovba.Models.Fields.packed_data import PackedData from ms_ovba.Models.Fields.idSizeField import IdSizeField -from typing import TypeVar +from typing import Literal, TypeVar T = TypeVar('T', bound='ModuleBase') @@ -24,7 +24,7 @@ def __init__(self: T, name: str) -> None: # self.readonly = SimpleRecord(0x001E, 4, helpContext) # self.private = SimpleRecord(0x001E, 4, helpContext) self._cache = b'' - self.workspace = [0, 0, 0, 0, 'C'] + self.workspace: tuple[int, int, int, int, Literal['C', 'I', 'Z']] self.type = '' self.created = 0 self.modified = 0 @@ -76,8 +76,9 @@ def bin_path(self: T) -> str: return self._file_path + ".bin" def add_workspace(self: T, val1: int, val2: int, - val3: int, val4: int, val5: int) -> None: - self.workspace = [val1, val2, val3, val4, val5] + val3: int, val4: int, + val5: Literal['C', 'I', 'Z']) -> None: + self.workspace = (val1, val2, val3, val4, val5) def pack(self: T, endien: str, cp_name: str) -> bytes: """ diff --git a/src/ms_ovba/Views/dirStream.py b/src/ms_ovba/Views/dirStream.py index 51be1ff60..8d8490736 100644 --- a/src/ms_ovba/Views/dirStream.py +++ b/src/ms_ovba/Views/dirStream.py @@ -21,19 +21,19 @@ class DirStream(): """ def __init__(self: T, project: VbaProject) -> None: - self.project = project + self._project = project self._include_compat = project.compat def to_bytes(self: T) -> bytes: information = self._load_information() - endien = self.project.endien - cp_name = self.project.codepage_name + endien = self._project.endien + cp_name = self._project.codepage_name pack_symbol = '<' if endien == 'little' else '>' # should be 0xFFFF - cookie_value = self.project.project_cookie + cookie_value = self._project.project_cookie self.project_cookie = IdSizeField(19, 2, cookie_value) - references = self.project.references - modules = self.project.modules + references = self._project.references + modules = self._project.modules output = b'' for record in information: output += record.pack(endien, cp_name) @@ -70,7 +70,7 @@ def _load_information(self: T) -> List: project_name = IdSizeField(4, 10, "VBAProject") docstring = DoubleEncodedString([5, 0x0040], "") helpfile = DoubleEncodedString([6, 0x003D], "") - help_context = IdSizeField(7, 4, 0) + help_context = IdSizeField(7, 4, self._project.help_context_id) lib_flags = IdSizeField(8, 4, 0) version = IdSizeField(9, 4, 0x65BE0257) minor_version = PackedData("H", 17) diff --git a/src/ms_ovba/Views/project.py b/src/ms_ovba/Views/project.py index fde3b35b0..08653ce98 100644 --- a/src/ms_ovba/Views/project.py +++ b/src/ms_ovba/Views/project.py @@ -1,7 +1,9 @@ import binascii +import re +import warnings from ms_ovba_crypto import MsOvbaCrypto from ms_ovba.vbaProject import VbaProject -from typing import TypeVar +from typing import Any, TypeVar T = TypeVar('T', bound='Project') @@ -12,7 +14,7 @@ class Project: The Project data view for the vbaProject """ def __init__(self: T, project: VbaProject) -> None: - self.project = project + self._project = project # Attributes # A list of attributes and values @@ -27,14 +29,14 @@ def add_attribute(self: T, name: str, value: str) -> None: def __str__(self: T) -> str: # Use \x0D0A line endings. - project = self.project + project = self._project project_id = project.project_id result = [f'ID="{project_id}"'] modules = project.modules for module in modules: result += [module.to_project_module_string()] result += ['Name="VBAProject"'] - result += ['HelpContextID="0"'] + result += ['HelpContextID="' + str(project.help_context_id) + '"'] for name, value in self.attributes.items(): result += [f'{name}="{value}"'] cmg = MsOvbaCrypto.encrypt(project_id, project.protection_state) @@ -46,20 +48,394 @@ def __str__(self: T) -> str: result += [''] result += ['[Host Extender Info]'] result += [self.hostExtenderInfo] - result += [''] - result += ['[Workspace]'] + workspace_started = False + for module in modules: - separator = ", " - joined = module.modName.value + '=' - joined += separator.join(map(str, module.workspace)) - result += [joined] + if module.workspace is not None: + if not workspace_started: + workspace_started = True + result += [''] + result += ['[Workspace]'] + separator = ", " + joined = module.modName.value + '=' + joined += separator.join(map(str, module.workspace)) + result += [joined] return "\r\n".join(result) + "\r\n" def to_bytes(self: T) -> bytes: - codepage_name = self.project.codepage_name + codepage_name = self._project.codepage_name return bytes(str(self), codepage_name) def write_file(self: T) -> None: bin_f = open("project.bin", "wb") bin_f.write(self.to_bytes()) bin_f.close() + + @staticmethod + def is_valid(filename: str) -> Any: + """ + Validate the structure of the file. This method does + not test if data values match between streams. + """ + + with open(filename, 'r', newline='') as file: + i = 1 + for line in file: + if line[-2:] not in ["\r\n", "\n\r"]: + warnings.warn( + ("Incorrect Line ending: " + + filename + " line: " + str(i)), + SyntaxWarning) + return False + i += 1 + with open(filename, 'r') as file: + line = file.readline().strip() + i = 1 + if not Project._valid_project_id_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + while Project._project_item_line(line): + if not Project._valid_project_item_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if Project._help_file_line(line): + if not Project._valid_help_file_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if Project._exe_line(line): + if not Project._valid_exe_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if not Project._valid_name_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if not Project._valid_help_id_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if Project._description_line(line): + if not Project._valid_description_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if Project._version_line(line): + if not Project._valid_version_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if not Project._valid_protection_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if not Project._valid_password_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if not Project._valid_visibility_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if line != "": + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if line != "[HostExtender Info]": + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + while Project._host_extender_line(line): + if not Project._valid_host_extender_line(line): + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + if line != "": + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline() + i += 1 + if line != '': + line = line.strip() + if line != "[Workspace]": + warnings.warn( + ("Invalid Data: " + filename + " line: " + + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + while line != '': + if not Project._valid_workspace_line(line): + warnings.warn( + ("Invalid Data: " + filename + + " line: " + str(i)), SyntaxWarning) + return False + line = file.readline().strip() + i += 1 + return True + + @staticmethod + def _project_item_line(line: str) -> bool: + options = ['Doc', 'Mod', 'Cla', 'Bas', 'Pac'] + return line[:3] in options + + @staticmethod + def _help_file_line(line: str) -> bool: + return line[0:5] == 'HelpF' + + @staticmethod + def _exe_line(line: str) -> bool: + return line[0:3] == 'Exe' + + @staticmethod + def _description_line(line: str) -> bool: + return line[0:3] == 'Des' + + @staticmethod + def _version_line(line: str) -> bool: + return line[0:3] == 'Ver' + + @staticmethod + def _host_extender_line(line: str) -> bool: + return line[0:2] == '&H' + + @staticmethod + def _valid_project_id_line(line: str) -> Any: + pieces = line.split('=') + return ( + len(pieces) == 2 and pieces[0] == 'ID' and + pieces[1][0] == '"' and pieces[1][-1] == '"' and + Project._valid_guid(pieces[1][1:-1]) + ) + + @staticmethod + def _valid_project_item_line(line: str) -> bool: + pieces = line.split('=') + # Verify the name. + if pieces[0] == 'Document': + doc_string = pieces[1].split('/') + return ( + Project._valid_modulename(doc_string[0]) and + Project._valid_hex32(doc_string[1]) + ) + elif pieces[0] == 'Package': + pass + elif pieces[0] in ['Module', 'Class', 'BaseClass']: + # ToDo: append name to an array for validation + # against dir-stream + return Project._valid_modulename(pieces[1]) + return False + + @staticmethod + def _valid_help_file_line(line: str) -> bool: + pieces = line.split('=') + return ( + len(pieces) == 2 and pieces[0] == "HelpFile" and + Project._valid_path(pieces[1]) + ) + + @staticmethod + def _valid_exe_line(line: str) -> bool: + pieces = line.split('=') + return ( + pieces[0] == "ExeName32" and + Project._valid_path(pieces[1]) + ) + + @staticmethod + def _valid_name_line(line: str) -> bool: + pieces = line.split('=') + return ( + pieces[0] == "Name" and + Project._valid_quoted_string(pieces[1], 1, 128) + ) + + @staticmethod + def _valid_help_id_line(line: str) -> bool: + pieces = line.split('=') + if pieces[0] == "HelpContextID": + string = pieces[1] + if string[0] != '"' or string[-1] != '"': + return False + candidate = string[1:-1] + try: + int(candidate) + return True + except ValueError: + return False + return False + + @staticmethod + def _valid_description_line(line: str) -> bool: + pieces = line.split('=') + return ( + pieces[0] == "Description" and + Project._valid_quoted_string(pieces[1], 0, 2000) + ) + + @staticmethod + def _valid_version_line(line: str) -> bool: + return ( + line == 'VersionCompatible32="393222000"' + ) + + @staticmethod + def _valid_protection_line(line: str) -> bool: + pieces = line.split('=') + return ( + pieces[0] == "CMG" and + Project._valid_quoted_hex(pieces[1], 22, 28) + ) + + @staticmethod + def _valid_password_line(line: str) -> bool: + pieces = line.split('=') + return ( + pieces[0] == "DPB" and + Project._valid_quoted_hex(pieces[1], 16, 2000) + ) + + @staticmethod + def _valid_visibility_line(line: str) -> bool: + pieces = line.split('=') + return ( + pieces[0] == "GC" and + Project._valid_quoted_hex(pieces[1], 16, 22) + ) + + @staticmethod + def _valid_host_extender_line(line: str) -> bool: + pieces = line.split('=') + ref = pieces[1].split(";") + return ( + Project._valid_hex32(pieces[0]) and + len(ref) == 3 and + Project._valid_guid(ref[0]) and + ( + ref[1] == "VBE" or + all(0x21 <= ord(char) <= 0xff for char in ref[1]) + ) and + Project._valid_hex32(ref[2]) + ) + + @staticmethod + def _valid_workspace_line(line: str) -> bool: + pieces = line.split('=') + data = pieces[1].split(", ") + return ( + Project._valid_modulename(pieces[0]) and + len(data) == 5 and + all(Project._valid_int32(num) for num in data[:4]) and + data[4] in ['C', 'I', 'Z'] + ) + + # Data Type Validators + @staticmethod + def _valid_hex32(hex: str) -> bool: + prefix = hex[:2] + value = int(hex[2:], 16) + min = -2147483648 + max = 2147483647 + return prefix == "&H" and (min <= value <= max) + + @staticmethod + def _valid_modulename(name: str) -> bool: + return len(name) <= 31 + + @staticmethod + def _valid_guid(guid: str) -> bool: + hd = '[0-9a-fA-F]' + pattern = ( + r'^\{' + hd + '{8}-' + + hd + '{4}-' + hd + '{4}-' + + hd + '{4}-' + hd + r'{12}\}$' + ) + # Use re.fullmatch to ensure the entire string is evaluated + return bool(re.fullmatch(pattern, guid)) + + @staticmethod + def _valid_path(path: str) -> bool: + return Project._valid_quoted_string(path, 0, 259) + + @staticmethod + def _valid_quoted_string(string: str, min: int, max: int) -> bool: + if len(string) < 2: + return False + substring = string[1:-1] + substring = substring.replace('""', " ") + substring = substring.replace('\t', " ") + substring = substring.replace('"', '\x19') + return ( + (min <= len(substring) <= max) and + string[0] == '"' and string[-1] == '"' and + all(32 <= ord(char) <= 255 for char in substring) + ) + + @staticmethod + def _valid_quoted_hex(string: str, min: int, max: int) -> bool: + if not (min + 2 <= len(string) <= max + 2): + return False + if string[0] != '"' or string[-1] != '"': + return False + string = string[1:-1] + return all( + ((48 <= ord(char) <= 57) or (65 <= ord(char) <= 70)) + for char in string + ) + + @staticmethod + def _valid_int32(string: str) -> bool: + try: + value = int(string) + min = -2147483648 + max = 2147483647 + return min <= value <= max + except ValueError: + return False diff --git a/src/ms_ovba/vbaProject.py b/src/ms_ovba/vbaProject.py index 81bcd5d20..ff631318d 100644 --- a/src/ms_ovba/vbaProject.py +++ b/src/ms_ovba/vbaProject.py @@ -31,6 +31,7 @@ def __init__(self: T) -> None: self._license_records: list[LicenseInfo] = [] # Attributes and values + self.help_context_id = 0 self.attributes: dict[str, str] = {} self._project_cookie = 0xFFFF diff --git a/tests/Functional/test_fullFile.py b/tests/Functional/test_fullFile.py index 109743429..58ddec2f9 100644 --- a/tests/Functional/test_fullFile.py +++ b/tests/Functional/test_fullFile.py @@ -321,6 +321,7 @@ def create_cache(proj_cookie: int, modules: list) -> bytes: def create_doc_module(project: VbaProject, name: str, cookie: int, guid_s: str, path: str) -> DocModule: mod = DocModule(name) + mod.add_workspace(0, 0, 0, 0, 'C') mod.cookie = cookie guid = uuid.UUID(guid_s) mod.add_guid(guid) diff --git a/tests/Unit/Views/test_project.py b/tests/Unit/Views/test_project.py index d3c486a0d..b971157b5 100644 --- a/tests/Unit/Views/test_project.py +++ b/tests/Unit/Views/test_project.py @@ -1,3 +1,4 @@ +import pytest import unittest.mock from ms_ovba.Views.project import Project from typing import Type, TypeVar @@ -52,6 +53,7 @@ def __init__(self: T) -> None: self.password = b'\x00' self.visibility_state = b'\xFF' self.attributes = {} + self.help_context_id = 0 @unittest.mock.patch('random.randint', NotSoRandom.randint) @@ -72,3 +74,113 @@ def test_blank() -> None: expected += file.read(0x0152) assert project.to_bytes() == expected + + +def test_guid_valid() -> None: + guid = "{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" + assert Project._valid_guid(guid) + + +def test_guid_invalid() -> None: + guid = "{9E394C0Z-697E-4AEE-9FA6-446F51FB30DC}" + assert not Project._valid_guid(guid) + + +def test_project_line_valid() -> None: + line = 'ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}"' + assert Project._valid_project_id_line(line) + + +def test_password_line_valid() -> None: + line = 'DPB="BCBEA7A2591C5A1C5A1C"' + assert Project._valid_password_line(line) + + +def test_project_line_invalid() -> None: + line = 'ID={9E394C0B-697E-4AEE-9FA6-446F51FB30DC}' + assert not Project._valid_project_id_line(line) + + +def test_invalid_exe_line() -> None: + line = ( + 'ExeName32="12345678910111213141516171819202122232425262728293031' + + '3233343536373839404142434445464748495051525354555657585960616263' + + '6465666768697071727374757677787980818283848586878889909192939495' + + '9697989910010110210310410510610710810911011111211311411511611711' + + '8119120121122123"' + ) + assert not Project._valid_exe_line(line) + + +def test_host_extender_line() -> None: + line = "&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000" + assert Project._valid_host_extender_line(line) + + +invalid_quoted_strings = [ + ('"abc"', 0, 2, "Too Long"), + ('"abcde"', 6, 12, "Too Short"), + ('abcde', 5, 12, "Not Quoted"), + ('"a"b"', 0, 20, "Unpaired DQUOT") +] + + +@pytest.mark.parametrize("string, min, max, msg", invalid_quoted_strings) +def test_invalid_quoted_string(string: str, + min: int, max: int, msg: str) -> None: + assert not Project._valid_quoted_string(string, min, max), msg + + +valid_quoted_strings = [ + ('"abcde"', 0, 20), + ('"abcde"', 5, 12), + ('"a=b"', 0, 20), + ('"a""b"', 0, 20) +] + + +@pytest.mark.parametrize("string, min, max", valid_quoted_strings) +def test_valid_quoted_string(string: str, min: int, max: int) -> None: + assert Project._valid_quoted_string(string, min, max) + + +def test_valid_file() -> None: + path = 'tests/blank/PROJECT' + assert Project.is_valid(path) + + +def test_incorrect_line_endings() -> None: + path = 'tests/test_files/PROJECT_bad' + msg = "Incorrect Line ending: " + path + " line: 1" + with pytest.warns() as record: + assert not Project.is_valid(path) + assert len(record) == 1 + assert record[0].message.args[0] == msg + + +file_numbers = [ + ("1"), + ("2"), + ("3"), + ("4"), + ("5"), + ("6"), + ("7"), + ("8"), + ("9"), + ("10"), + ("11"), + ("12"), + ("13"), + ("14") +] + + +@pytest.mark.parametrize("number", file_numbers) +def test_incorrect_lines(number: str) -> None: + path = 'tests/test_files/PROJECT_line' + number + msg = f"Invalid Data: {path} line: {number}" + with pytest.warns() as record: + assert not Project.is_valid(path) + assert len(record) == 1 + assert record[0].message.args[0] == msg diff --git a/tests/blank/PROJECT b/tests/blank/PROJECT index 38b200edd..f90b6a608 100644 --- a/tests/blank/PROJECT +++ b/tests/blank/PROJECT @@ -1,18 +1,18 @@ -ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" -Document=ThisWorkbook/&H00000000 -Document=Sheet1/&H00000000 -Module=Module1 -Name="VBAProject" -HelpContextID="0" -VersionCompatible32="393222000" -CMG="41435A5A5E5A5E5A5E5A5E" -DPB="BCBEA7A2591C5A1C5A1C" -GC="37352C2BDCDD56DE56DEA9" - -[HostExtender Info] -&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 - -[Workspace] -ThisWorkbook=0, 0, 0, 0, C -Sheet1=0, 0, 0, 0, C -Module1=26, 26, 1349, 522, Z +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_bad b/tests/test_files/PROJECT_bad new file mode 100644 index 000000000..38b200edd --- /dev/null +++ b/tests/test_files/PROJECT_bad @@ -0,0 +1,18 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_good b/tests/test_files/PROJECT_good new file mode 100644 index 000000000..e1ab7935c --- /dev/null +++ b/tests/test_files/PROJECT_good @@ -0,0 +1,21 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464" +Name="VBAProject" +HelpContextID="0" +Description="Can description contain an equals sign?" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z \ No newline at end of file diff --git a/tests/test_files/PROJECT_line1 b/tests/test_files/PROJECT_line1 new file mode 100644 index 000000000..7938cfbed --- /dev/null +++ b/tests/test_files/PROJECT_line1 @@ -0,0 +1,18 @@ +ID="{9E394C0B-697E-4AEE-9FA6446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line10 b/tests/test_files/PROJECT_line10 new file mode 100644 index 000000000..c534fe68a --- /dev/null +++ b/tests/test_files/PROJECT_line10 @@ -0,0 +1,21 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="0" +Description="" +VersionCompatible32="1.0" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line11 b/tests/test_files/PROJECT_line11 new file mode 100644 index 000000000..228368467 --- /dev/null +++ b/tests/test_files/PROJECT_line11 @@ -0,0 +1,21 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="0" +Description="" +VersionCompatible32="393222000" +GMC="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line12 b/tests/test_files/PROJECT_line12 new file mode 100644 index 000000000..e58170710 --- /dev/null +++ b/tests/test_files/PROJECT_line12 @@ -0,0 +1,21 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="0" +Description="" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line13 b/tests/test_files/PROJECT_line13 new file mode 100644 index 000000000..b47c82c5a --- /dev/null +++ b/tests/test_files/PROJECT_line13 @@ -0,0 +1,21 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="0" +Description="" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GCC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line14 b/tests/test_files/PROJECT_line14 new file mode 100644 index 000000000..d99e9e3aa --- /dev/null +++ b/tests/test_files/PROJECT_line14 @@ -0,0 +1,20 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="0" +Description="" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line2 b/tests/test_files/PROJECT_line2 new file mode 100644 index 000000000..00398df95 --- /dev/null +++ b/tests/test_files/PROJECT_line2 @@ -0,0 +1,18 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line3 b/tests/test_files/PROJECT_line3 new file mode 100644 index 000000000..cb9a92d5a --- /dev/null +++ b/tests/test_files/PROJECT_line3 @@ -0,0 +1,18 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H100000000000000000000 +Module=Module1 +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line4 b/tests/test_files/PROJECT_line4 new file mode 100644 index 000000000..117bdfaf1 --- /dev/null +++ b/tests/test_files/PROJECT_line4 @@ -0,0 +1,18 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Mod ule1-;:()&@2836:).!,)37yshebxieushdjsiejxhsusndjejdnxj +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line5 b/tests/test_files/PROJECT_line5 new file mode 100644 index 000000000..23640bad4 --- /dev/null +++ b/tests/test_files/PROJECT_line5 @@ -0,0 +1,19 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo"124.exe" +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line6 b/tests/test_files/PROJECT_line6 new file mode 100644 index 000000000..6249d8069 --- /dev/null +++ b/tests/test_files/PROJECT_line6 @@ -0,0 +1,20 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123" +Name="VBAProject" +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line7 b/tests/test_files/PROJECT_line7 new file mode 100644 index 000000000..00d3834be --- /dev/null +++ b/tests/test_files/PROJECT_line7 @@ -0,0 +1,20 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name=VBAProject +HelpContextID="0" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line8 b/tests/test_files/PROJECT_line8 new file mode 100644 index 000000000..6964e0e90 --- /dev/null +++ b/tests/test_files/PROJECT_line8 @@ -0,0 +1,20 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="X" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z diff --git a/tests/test_files/PROJECT_line9 b/tests/test_files/PROJECT_line9 new file mode 100644 index 000000000..dbd28ff0c --- /dev/null +++ b/tests/test_files/PROJECT_line9 @@ -0,0 +1,21 @@ +ID="{9E394C0B-697E-4AEE-9FA6-446F51FB30DC}" +Document=ThisWorkbook/&H00000000 +Document=Sheet1/&H00000000 +Module=Module1 +HelpFile="foo""124.exe" +ExeName32="12345678910111213141516171819202122232425262728293031323343536373839404142434445464748945051525354555657585960616263646566" +Name="VBAProject" +HelpContextID="0" +Description=" +VersionCompatible32="393222000" +CMG="41435A5A5E5A5E5A5E5A5E" +DPB="BCBEA7A2591C5A1C5A1C" +GC="37352C2BDCDD56DE56DEA9" + +[HostExtender Info] +&H00000001={3832D640-CF90-11CF-8E43-00A0C911005A};VBE;&H00000000 + +[Workspace] +ThisWorkbook=0, 0, 0, 0, C +Sheet1=0, 0, 0, 0, C +Module1=26, 26, 1349, 522, Z