mirror of
https://github.com/reactos/reactos.git
synced 2024-11-27 05:23:33 +08:00
24a56f89ab
This removes all fake apiset forwarders, and handles apisets inside ntdll. This is not 100% compatible with how windows does it, but it should be good enough for us.
151 lines
4.3 KiB
Python
151 lines
4.3 KiB
Python
'''
|
|
PROJECT: ReactOS apisets
|
|
LICENSE: MIT (https://spdx.org/licenses/MIT)
|
|
PURPOSE: Create apiset lookup table based on the data files of https://apisets.info
|
|
COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
|
|
'''
|
|
|
|
from pathlib import Path
|
|
from dataclasses import dataclass, field
|
|
import sys
|
|
import json
|
|
|
|
# These are modules we do not have, so redirect them to ones we do have.
|
|
REDIRECT_HOSTS = {
|
|
'kernelbase.dll': 'kernel32.dll',
|
|
'kernel.appcore.dll': 'kernel32.dll',
|
|
'combase.dll': 'ole32.dll',
|
|
'ucrtbase.dll': 'msvcrt.dll',
|
|
'shcore.dll': 'shell32.dll',
|
|
'winmmbase.dll': 'winmm.dll',
|
|
'gdi32full.dll': 'gdi32.dll'
|
|
}
|
|
|
|
OUTPUT_HEADER = """/*
|
|
* PROJECT: ReactOS apisets
|
|
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
|
* PURPOSE: Autogenerated table of all apisets
|
|
* COPYRIGHT: Copyright 2024 Mark Jansen <mark.jansen@reactos.org>
|
|
*/
|
|
|
|
#include <ndk/umtypes.h>
|
|
#include <ndk/rtlfuncs.h>
|
|
#include "apisetsp.h"
|
|
|
|
const ROS_APISET g_Apisets[] = {
|
|
"""
|
|
|
|
OUTPUT_FOOTER = """};
|
|
|
|
const LONG g_ApisetsCount = RTL_NUMBER_OF(g_Apisets);
|
|
"""
|
|
|
|
def winver_to_name(version):
|
|
major, minor, build, _ = map(int, version.split('.'))
|
|
if (major, minor) == (6, 1):
|
|
return 'APISET_WIN7'
|
|
if (major, minor) == (6, 2):
|
|
return 'APISET_WIN8'
|
|
if (major, minor) == (6, 3):
|
|
return 'APISET_WIN81'
|
|
if (major, minor) == (10, 0):
|
|
if build < 22000:
|
|
return 'APISET_WIN10'
|
|
return 'APISET_WIN11'
|
|
assert False, (major, minor, build)
|
|
|
|
@dataclass
|
|
class Apiset:
|
|
name: str
|
|
host: str
|
|
versions: list[str] = field(default_factory=list)
|
|
|
|
def add_version(self, version):
|
|
if version not in self.versions:
|
|
self.versions.append(version)
|
|
|
|
def __str__(self):
|
|
version_str = ' | '.join(self.versions)
|
|
name = self.name
|
|
assert name[-4:].lower() == '.dll'
|
|
name = name[:-4]
|
|
prefix, postfix = '', ''
|
|
host = self.host
|
|
if host == '':
|
|
# Disable forwarders that have an empty host
|
|
prefix = '// '
|
|
else:
|
|
# Check to see if there is any dll we want to swap (kernelbase -> kernel32)
|
|
replace = REDIRECT_HOSTS.get(host.lower(), None)
|
|
if replace:
|
|
postfix = ' // ' + host
|
|
host = replace
|
|
return f' {prefix}{{ RTL_CONSTANT_STRING(L"{name}"), RTL_CONSTANT_STRING(L"{host}"), {version_str} }},{postfix}'
|
|
|
|
|
|
class ApisetSchema:
|
|
def __init__(self, file):
|
|
self._data = json.load(file.open())
|
|
self.version = winver_to_name(self._data['PE']['ProductVersion'])
|
|
self._arch = self._data['PE']['Machine']
|
|
|
|
def apisets(self):
|
|
for elem in self._data['namespaces']:
|
|
name = elem['name']
|
|
host = elem['host']
|
|
yield Apiset(name, host)
|
|
|
|
|
|
class CombinedSchemas:
|
|
def __init__(self):
|
|
self._apisets = {}
|
|
|
|
def add(self, schema: ApisetSchema):
|
|
for apiset in schema.apisets():
|
|
lowername = apiset.name.lower()
|
|
if lowername not in self._apisets:
|
|
self._apisets[lowername] = apiset
|
|
else:
|
|
apiset = self._apisets[lowername]
|
|
apiset.add_version(schema.version)
|
|
|
|
def generate(self, output):
|
|
for key in sorted(self._apisets):
|
|
apiset = self._apisets[key]
|
|
output.write(f'{apiset}\n'.encode('utf-8'))
|
|
|
|
|
|
def process_apisetschemas(input_dir: Path, output_file):
|
|
schemas = CombinedSchemas()
|
|
|
|
for schemafile in input_dir.glob('*.json'):
|
|
schema = ApisetSchema(schemafile)
|
|
# Skip Win11 for now
|
|
if schema.version != 'APISET_WIN11':
|
|
schemas.add(schema)
|
|
|
|
output_file.write(OUTPUT_HEADER.encode('utf-8'))
|
|
schemas.generate(output_file)
|
|
output_file.write(OUTPUT_FOOTER.encode('utf-8'))
|
|
|
|
|
|
def usage():
|
|
print('Usage: update.py <apisetschema folder>')
|
|
print(' where <apisetschema folder> is the folder with all apisetschema json files')
|
|
|
|
def main(args):
|
|
if len(args) < 1:
|
|
return usage()
|
|
|
|
apisetschemas = Path(args[0])
|
|
if not apisetschemas.is_dir():
|
|
return usage()
|
|
|
|
output = Path(__file__).parent / 'apisets.table.c'
|
|
|
|
process_apisetschemas(apisetschemas, output.open('wb'))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main(sys.argv[1:])
|