// // BASIC DATABASE STRUCTURE // // The database file format was specifically designed to allow for a simple, extensible representation // of a hierarchical file like an XML file, and be forwards and backwards compatible. A future reader // should be able to read any current files, and future files should be readable by this code. // // // CORE BINARY FORMAT // // The file begins with a header of three DWORDs (defined in struct DB_HEADER): // // MajorVersion // MinorVersion // MagicNumber // // The Major version should only be changed if the new format would break old readers, i.e. NEVER. // The Minor version can be changed for informational purposes if there is a significant change // to the layout of the data. // The Magic number is there to ensure we don't try to read some random file with the same extension. // // Following the header are tags, packed end-to-end with no padding. All tags are of the form: // // TAG[SIZE][DATA...] // // Where SIZE and DATA are optional, depending on the type of TAG. // // TAG is 2 bytes long, SIZE is 4 bytes long, and DATA is anywhere from 0 to 2^32 bytes long. // // The top 4 bits of a TAG are reserved for internal database BASIC TYPE info. // This tells the database what kind of data is stored after the TAG, and if the tag has an // implied size. For example a TAG of basic type TAG_TYPE_BYTE has an implied size of 1 byte, // and does not require a SIZE. But a tag of basic type TAG_TYPE_STRING does not have an implied // size, and will therefore have a SIZE after the tag. // // The BASIC TYPES are: // TAG_TYPE_NULL (no SIZE, 0 bytes of DATA) // TAG_TYPE_BYTE (no SIZE, 1 byte of DATA) // TAG_TYPE_WORD (no SIZE, 2 bytes of DATA) // TAG_TYPE_DWORD (no SIZE, 4 bytes of DATA) // TAG_TYPE_QWORD (no SIZE, 8 bytes of DATA) // TAG_TYPE_STRINGREF (no SIZE, 4 bytes of DATA) // TAG_TYPE_LIST (SIZE, variable DATA) // TAG_TYPE_STRING (SIZE, variable DATA) // TAG_TYPE_BINARY (SIZE, variable DATA) // // Each of these types can be used for many different TAGs, by OR-ing the TAG_TYPE_x with a constant. // See SHIMTAGS.H and SHIMDB.H for examples. // // TAG_TYPE_STRINGREF is used for strings that should be placed in a stringtable by the database code. // This allows for efficient packing of duplicate strings. Tags of type STRING will be directly added // to the DB with no indirection. // // TAG_TYPE_LIST is defined to contain only more tags. Its SIZE is the combined size of all of its child // TAGs, including the TAG, DATA, and SIZE of each of them. This allows easy skipping over an entire // branch of the heirarchy. // // If new BASIC TYPES are defined later, they MUST have a SIZE associated with them, as the code assumes // that any type it doesn't recognize must have a SIZE. The first 5 types are really just a size optimization, // and new types should not try to have implied sizes. // // // THE SHIMDB LAYOUT // // Our layout for the application compatibility database mirrors closely the layout found in the DB.XML // file, found in the NT tree in WINDOWS\APPCOMPAT\DB, used to store information about apps that need // some kind of application compatibility fix applied to them. This comment block may get out of // date as new data is added to the database, so for the most current layout, consult // that file. One can also run the DUMPSDB.EXE utility (found in \WINDOWS\APPCOMPAT\DUMPSDB) // on an existing SDB to see the exact layout being used. // // The root contains only two tags: DATABASE (list) and STRINGTABLE (list). // The STRINGTABLE is used internally by the DB; all the useful data is under DATABASE. // // DATABASE contains a single LIBRARY (list) tag, 0 or more LAYER (list) tags, and 0 or more EXE (list) tags. // // LIBRARY contains 0 or more INEXCLUDE (list) tags, 0 or more DLL (list) tags, and 0 or more PATCH (list) tags // // an INEXCLUDE record contains potentially MODULE (string), API (string), INCLUDE (null, its existence // or nonexistence is treated like a boolean), and OFFSET (dword). // // a DLL record contains potentially NAME (string), SHORTNAME (string), // DESCRIPTION (string), DLL_BITS (binary), // and 0 or more INEXCLUDE (list) tags. // // a PATCH record contains potentially NAME (string), // DESCRIPTION (string), and PATCH_BITS (binary), // // a LAYER record contains exactly the same things that can be in an EXE record except MATCHING_FILE tags // and PATCH_REF tags. // // an EXE record contains potentially a NAME (string), KERNEL_FLAGS (qword), 0 or more // MATCHING_FILE (list) tags, 0 or more DLL_REF (list) tags, and 0 or more PATCH_REF (list) tags. // // a MATCHING_FILE record contains potentially a NAME (string), SIZE (dword), TIME (qword), and CHECKSUM (dword) // // a DLL_REF record contains potentially a NAME (string), DLL_TAGID (dword), and 0 or more INEXCLUDE (list) // tags. // // a PATCH_REF record contains potentially a NAME (string) and PATCH_TAGID (dword) // // Here's a map of where each tag is generally found, where "+" means there can be 0 or more, and [] means // the tag is optional: // // DATABASE // LIBRARY // [INEXCLUDE+] // [INCLUDE] // MODULE // [API] // [OFFSET] // [DLL+] // NAME // [SHORTNAME] // [DESCRIPTION] // [INEXCLUDE+] // [DLL_BITS] // [PATCH+] // NAME // [DESCRIPTION] // [PATCH_BITS] // [EXE+] // NAME // [APP_NAME] // [VENDOR_NAME] // [KERNEL_FLAGS] // [MATCHING_FILE+] // NAME // [SIZE] // [TIME] // [CHECKSUM] // [DLL_REF+] // NAME // [DLL_TAGID] // [INEXCLUDE+] // [PATCH_REF+] // NAME // [PATCH_TAGID] // [STRINGTABLE] // STRINGTABLE_ITEM+ //