+static BOOL WINAPI SdbpMatchExe(PDB db, TAGID exe, WCHAR* dir)
+{
+ static const WCHAR fmt[] = {'%','s','%','s',0};
+ WCHAR buffer[256]; /* FIXME: rewrite using a buffer that can grow if needed, f.e. RtlInitBuffer stuff! */
+ TAGID matching_file;
+
+ /* TODO: check size/checksum from the main exe as well as from the extra files */
+ for (matching_file = SdbFindFirstTag(db, exe, TAG_MATCHING_FILE);
+ matching_file != TAGID_NULL; matching_file = SdbFindNextTag(db, exe, matching_file))
+ {
+ TAGID tagName = SdbFindFirstTag(db, matching_file, TAG_NAME);
+ LPWSTR name = SdbGetStringTagPtr(db, tagName);
+
+ if (!wcscmp(name, L"*"))
+ {
+ // if attributes dont match main file, return FALSE!
+ continue;
+ }
+
+ snprintfW(buffer, _countof(buffer), fmt, dir, name);
+ if (!SdbpFileExists(buffer))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void SdbpAddDatabaseGuid(PDB db, PSDBQUERYRESULT result)
+{
+ size_t n;
+
+ for (n = 0; n < _countof(result->rgGuidDB); ++n)
+ {
+ if (!memcmp(&result->rgGuidDB[n], &db->database_id, sizeof(db->database_id)))
+ return;
+
+ if (result->dwCustomSDBMap & (1<<n))
+ continue;
+
+ memcpy(&result->rgGuidDB[n], &db->database_id, sizeof(result->rgGuidDB[n]));
+ result->dwCustomSDBMap |= (1<<n);
+ return;
+ }
+}
+
+static BOOL SdbpAddSingleLayerMatch(TAGREF layer, PSDBQUERYRESULT result)
+{
+ size_t n;
+
+ for (n = 0; n < result->dwLayerCount; ++n)
+ {
+ if (result->atrLayers[n] == layer)
+ return FALSE;
+ }
+
+ if (n >= _countof(result->atrLayers))
+ return FALSE;
+
+ result->atrLayers[n] = layer;
+ result->dwLayerCount++;
+
+ return TRUE;
+}
+
+
+static BOOL SdbpAddNamedLayerMatch(HSDB hsdb, PCWSTR layerName, PSDBQUERYRESULT result)
+{
+ TAGID database, layer;
+ TAGREF tr;
+ PDB db = hsdb->db;
+
+ database = SdbFindFirstTag(db, TAGID_ROOT, TAG_DATABASE);
+ if (database == TAGID_NULL)
+ return FALSE;
+
+ layer = SdbFindFirstNamedTag(db, database, TAG_LAYER, TAG_NAME, layerName);
+ if (layer == TAGID_NULL)
+ return FALSE;
+
+ if (!SdbTagIDToTagRef(hsdb, db, layer, &tr))
+ return FALSE;
+
+ if (!SdbpAddSingleLayerMatch(tr, result))
+ return FALSE;
+
+ SdbpAddDatabaseGuid(db, result);
+ return TRUE;
+}
+
+static void SdbpAddExeLayers(HSDB hsdb, PDB db, TAGID tagExe, PSDBQUERYRESULT result)
+{
+ TAGID layer = SdbFindFirstTag(db, tagExe, TAG_LAYER);
+
+ while (layer != TAGID_NULL)
+ {
+ TAGREF tr;
+ TAGID layerIdTag = SdbFindFirstTag(db, layer, TAG_LAYER_TAGID);
+ DWORD tagId = SdbReadDWORDTag(db, layerIdTag, TAGID_NULL);
+
+ if (layerIdTag != TAGID_NULL &&
+ tagId != TAGID_NULL &&
+ SdbTagIDToTagRef(hsdb, db, tagId, &tr))
+ {
+ SdbpAddSingleLayerMatch(tr, result);
+ }
+ else
+ {
+ /* Try a name lookup */
+ TAGID layerTag = SdbFindFirstTag(db, layer, TAG_NAME);
+ if (layerTag != TAGID_NULL)
+ {
+ LPCWSTR layerName = SdbGetStringTagPtr(db, layerTag);
+ if (layerName)
+ {
+ SdbpAddNamedLayerMatch(hsdb, layerName, result);
+ }
+ }
+ }
+
+ layer = SdbFindNextTag(db, tagExe, layer);
+ }
+}
+
+static void SdbpAddExeMatch(HSDB hsdb, PDB db, TAGID tagExe, PSDBQUERYRESULT result)
+{
+ size_t n;
+ TAGREF tr;
+
+ if (!SdbTagIDToTagRef(hsdb, db, tagExe, &tr))
+ return;
+
+ for (n = 0; n < result->dwExeCount; ++n)
+ {
+ if (result->atrExes[n] == tr)
+ return;
+ }
+
+ if (n >= _countof(result->atrExes))
+ return;
+
+ result->atrExes[n] = tr;
+ result->dwExeCount++;
+
+ SdbpAddExeLayers(hsdb, db, tagExe, result);
+
+ SdbpAddDatabaseGuid(db, result);
+}
+
+static ULONG SdbpAddLayerMatches(HSDB hsdb, PWSTR pwszLayers, DWORD pdwBytes, PSDBQUERYRESULT result)
+{
+ PWSTR start = pwszLayers, p;
+ ULONG Added = 0;
+
+ const PWSTR end = pwszLayers + (pdwBytes / sizeof(WCHAR));
+ while (start < end && (*start == L'!' || *start == L'#' || *start == L' ' || *start == L'\t'))
+ start++;
+
+ if (start == end)
+ return 0;
+
+ do
+ {
+ while (*start == L' ' || *start == L'\t')
+ ++start;
+
+ if (*start == UNICODE_NULL)
+ break;
+ p = wcspbrk(start, L" \t");
+
+ if (p)
+ *p = UNICODE_NULL;
+
+ if (SdbpAddNamedLayerMatch(hsdb, start, result))
+ Added++;
+
+ start = p + 1;
+ } while (start < end && p);
+
+ return Added;
+}
+
+static BOOL SdbpPropagateEnvLayers(HSDB hsdb, LPWSTR Environment, PSDBQUERYRESULT Result)
+{
+ static const UNICODE_STRING EnvKey = RTL_CONSTANT_STRING(L"__COMPAT_LAYER");
+ UNICODE_STRING EnvValue;
+ NTSTATUS Status;
+ WCHAR Buffer[MAX_LAYER_LENGTH];
+
+ RtlInitEmptyUnicodeString(&EnvValue, Buffer, sizeof(Buffer));
+
+ Status = RtlQueryEnvironmentVariable_U(Environment, &EnvKey, &EnvValue);
+
+ if (!NT_SUCCESS(Status))
+ return FALSE;
+
+ return SdbpAddLayerMatches(hsdb, Buffer, EnvValue.Length, Result) > 0;
+}
+
+