/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: ddpdb.c,v 1.2.2.1 2004/07/09 01:59:19 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

/* Windows include files: */
#include <windows.h>
#include <regstr.h>
#include <ddraw.h>

#ifdef IMPORT
#include <initguid.h>
#endif

/* standard libraries: */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

/* our headers: */
#include "hxdx5032.h"   // for win95 driver info in CFullScreenInfo

#include "ddpdb.h"
#include "colormap.h"
#include "hxdllldr.h"

#define F(cid)          (1U << (cid))   /* converts CID into a bitmask  */
#define MAX_BUF         512
#define ENUM_MAX        6

/*
 * DirectDraw profiles:
 */
#define DDPDB_MAGIC     "DDPDB"
#define DDPDB_VERSION   0x100
#define MAXPROFILES     256

static struct
{
    char            szMagic[8];                 /* some identifier      */
    DWORD           dwVersion;                  /* database version     */
    DWORD           dwNumProfiles;              /* # of records         */
    DDDEVICEPROFILE ddProfiles[MAXPROFILES];    /* data                 */

} DDPDB =
{
    DDPDB_MAGIC,
    DDPDB_VERSION,
    30,  /* # of profiles !!!!!!!!! */
    {{
        VER_PLATFORM_WIN32_WINDOWS,
        {"ATI Rage II+ PCI (ati_m64)", "ati_m64.drv", 0x6b8,0x4000a,
        0x1002, 0x4755, 0x0, 0x9a5b,
        {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* buggy driver... do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUVs only !!!): */
        {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY)}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
	{"RAGE PRO TURBO AGP 2X (English)",
	 "macxdd32.dll",
	 0x10937,0x4000a,
	 0x1002, 0x4742, 0x47421002, 0x5c, 
	 {0xd7b71ee2,0x402,0x11cf,{0x85,0x7a,0x43,0x67,0xf9,0xc2,0xc9,0x35}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
     {
         VER_PLATFORM_WIN32_NT,
         {"1002-4C46-03",
          "ati2dvai.dll",
          0x10426,0x5000c,
          0x3320334d, 0x7a484d33, 0x50474128, 0x400029,
          {0x800,0x4,0x0,{0x48,0x7,0x13,0x0,0xffffffd2,0x2c,0x40,0x0}}},
         /* do NOT use overlays !!!: */
         {0, 0, 0, 0, 0},
         /* no blits either: */
         {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Matrox Millennium G200 AGP", "MGAXDD32.DLL", 0x1100e,0x4000a, 0x102B, 0x521, 0, 0,
        {0xd7b71ecb,0x4661,0x11cf,{0xbe,0x73,0x01,0x20,0xa5,0xc2,0xc9,0x35}}},
        /* overlays (use YUVs only): */
        {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY)},
        /* blits (use YUVs & matching RGBs): */
        {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB32),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB24),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB565),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB555),
        F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_NT,
        {"Matrox Millennium G200 AGP", "mga64.dll", 0x0,0x40000,
        /* MGA-G200 B8 R1: */ 0x2d41474d, 0x30303247, 0x20384220, 0x03152, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s & matching RGBs only): */
        {F(CID_YUY2) + F(CID_RGB32),
         F(CID_YUY2) + F(CID_RGB24),
         F(CID_YUY2) + F(CID_RGB565),
         F(CID_YUY2) + F(CID_RGB555),
         F(CID_YUY2) + F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_NT,
        {"Matrox Millennium G200 AGP", "tsirchnl.dll", 0xc9,0x70008,
        0x2d41474d, 0x30303247, 0x20384220, 0x4b003152,
        {0x4f4e4d4c,0x5150,0x5352,{0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s & matching RGBs only): */
        {F(CID_YUY2) + F(CID_RGB32),
         F(CID_YUY2) + F(CID_RGB24),
         F(CID_YUY2) + F(CID_RGB565),
         F(CID_YUY2) + F(CID_RGB555),
         F(CID_YUY2) + F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Matrox Millennium II PowerDesk", "MGAXDD32.DLL", 0x10ee2,0x4000a,
        0x102b, 0x51b, 0x0, 0x0,
        {0xd7b71ecb,0x465b,0x11cf,{0x52,0x6d,0x1,0x20,0xa5,0xc2,0xc9,0x35}}},
        /* does not have overlays... */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s only): */
        {F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Matrox Millennium II PowerDesk", "MGAXDD32.DLL", 0xe2e,0x40003,
        0x102b, 0x51b, 0x0, 0x0,
        {0xd7b71ecb,0x465b,0x11cf,{0x9e,0x6d,0x0,0x20,0xac,0xc2,0xc9,0x35}}},
        /* does not have overlays... */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s only): */
        {F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Matrox Millennium II PCI", "mgapdx64.drv", 0x110b8,0x4000a,
        0x102b, 0x51b, 0x0, 0x25b,
        {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* does not have overlays... */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s only): */
        {F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2),
         F(CID_YUY2)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Diamond Viper V330", "vprddle.DLL", 0x10080,0x4000a, 0x12d2, 0x18, 0, 0,
        {0xd7b71c32,0x4358,0x11cf,{0x30,0x63,0x01,0x20,0xa5,0xc2,0xc9,0x35}}},
        /* overlays (use YUY2 & UYVY only): */
        {F(CID_YUY2) + F(CID_UYVY),
        F(CID_YUY2) + F(CID_UYVY),
        F(CID_YUY2) + F(CID_UYVY),
        F(CID_YUY2) + F(CID_UYVY),
        F(CID_YUY2) + F(CID_UYVY)},
        /* blits (use YUY2, UYVY & matching RGBs): */
        {F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB32),
        F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB24),
        F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB565),
        F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB555),
        F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB8)}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
	{"NVIDIA GeForce 256 AGP Plus (Dell)",
	 "NVDD32.DLL",
	 0x10179,0x4000c,
	 0x10de, 0x100, 0x810de, 0x10, 
	{0xd7b71e3e,0x4240,0x11cf,{0x17,0x72,0x9,0x20,0xb3,0xc2,0xc9,0x35}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Diamond Viper V330", "vprdrvle.drv", 0x1007e, 0x4000a, 0x12d2, 0x18, 0x0, 0x0,
        {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s & matching RGBs only): */
        {F(CID_YUY2) + F(CID_RGB32),
         F(CID_YUY2) + F(CID_RGB24),
         F(CID_YUY2) + F(CID_RGB565),
         F(CID_YUY2) + F(CID_RGB555),
         F(CID_YUY2) + F(CID_RGB8)}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
	{"Diamond Viper V550", "NVDD32.DLL", 0x10170,0x4000c, 0x10de, 0x20, 0x5501092, 0x4,
	{0xd7b71e3e,0x4360,0x11cf,{0x52,0x72,0x51,0x25,0xa7,0xc2,0xc9,0x35}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
        {"[Hercules]  Thriller 3D Series (v 0.81.3539)",
         "v200032.dll",
         0xdd2,0x4000a,
         0x1163, 0x2000, 0x34843, 0x6,
	{0xd7b71f83,0x6340,0x11cf,{0x21,0x26,0x3,0x20,0xa3,0xc2,0xc9,0x35}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_NT,
        {"Diamond Multimedia Systems, Inc.  Stealth II G460  Ver. 1.12\x0d\x0aV",
        "stlthg46.dll", 0x0,0x40000,
        /* Intel740: */  0x65746e49, 0x3034376c, 0, 0, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
	{"STB Lightspeed 128, with STB Vision 95",
	 "stbvisn.drv", 0x514,0x40003,
	 0x100c, 0x3208, 0x0, 0x0, {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Diamond SpeedStar A50 for Windows 98", "DMSSA50x.dll", 0xc8,0x4000a,
        0x1039, 0x6326, 0xa501092, 0xb,
        {0xd7b71ed9,0x2066,0x11cf,{0xea,0x73,0x50,0x2a,0xae,0xc2,0xc9,0x35}}},
        /* do NOT use overlays in 16-bit mode !!!: */
        {F(CID_YUY2),
         F(CID_YUY2),
         0,
         0,
         F(CID_YUY2)},
        /* no blits: */
        {0, 0, 0, 0, 0}
    },
    /* these STB cards use nVidia Riva 182zx: */
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"STB Velocity 128 3D", "stbv128.drv",
        0x10074,0x4000a, 0x12d2, 0x18, 0x0, 0x0, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s & matching RGBs only): */
        {F(CID_YUY2) + F(CID_RGB32),
         F(CID_YUY2) + F(CID_RGB24),
         F(CID_YUY2) + F(CID_RGB565),
         F(CID_YUY2) + F(CID_RGB555),
         F(CID_YUY2) + F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"STB Velocity 128 (TV Support)", "STBV128.DRV",
        0x1006d,0x4000a, 0x12d2, 0x18, 0x0, 0x0, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s & matching RGBs only): */
        {F(CID_YUY2) + F(CID_RGB32),
         F(CID_YUY2) + F(CID_RGB24),
         F(CID_YUY2) + F(CID_RGB565),
         F(CID_YUY2) + F(CID_RGB555),
         F(CID_YUY2) + F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"STB Lightspeed 128, without STB Vision 95", "stbls128.drv",
        0x514,0x40003, 0x100c, 0x3208, 0x0, 0x0, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* overlays (use UYVY only): */
        {F(CID_UYVY),
        F(CID_UYVY),
        F(CID_UYVY),
        F(CID_UYVY),
        0 /* this driver has a bug in 8-bit mode!!! */},
        /* blits are not available anyway: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"S3 Inc. Trio64V+", "s3_2.drv", 0x1083c,0x4000a,
        0x5333, 0x8811, 0x0, 0x0,
        {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* disable overlays: */
        {0, 0, 0, 0, 0},
        /* RGB blits only: */
        {F(CID_RGB32),
         F(CID_RGB24),
         F(CID_RGB565),
         F(CID_RGB555),
         F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Chips And Technologies, Accelerator (new)", "chipsnd.drv",
        0x3b6,0x40013,0x102c, 0xe0, 0x0, 0x0, {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* blits (use YUY2s & matching RGBs only): */
        {F(CID_YUY2) + F(CID_RGB32),
         F(CID_YUY2) + F(CID_RGB24),
         F(CID_YUY2) + F(CID_RGB565),
         F(CID_YUY2) + F(CID_RGB555),
         F(CID_YUY2) + F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Cirrus Logic 7548 PCI", "cirrusmm.drv", 0x7ee,0x40003,
         0x1013, 0x38, 0x0, 0x0,
         {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* does not have overlays...: */
        {0, 0, 0, 0, 0},
        /* RGB blits only: */
        {F(CID_RGB32),
         F(CID_RGB24),
         F(CID_RGB565),
         F(CID_RGB555),
         F(CID_RGB8)}
    },
    /* NeoMagic controllers (widely used in Dell laptops): */
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"NeoMagic MagicGraph 128XD", "NmgcDD.dll", 0x10006,0x4000a,
        0x10c8, 0x4, 0x751028, 0x0,
        {0xd7b71e28,0x4344,0x11cf,{0x9e,0x73,0x74,0x20,0xa5,0xc2,0xc9,0x35}}},
        /* overlays (use YUY2 only): */
        {F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2)},
        /* don't use BLITS!!!: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"NeoMagic MagicGraph 128XD", "Nmgc.drv",
        0x10004,0x4000a, 0x10c8, 0x4, 0x0, 0x0, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* overlays (use YUY2 only): */
        {F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2)},
        /* don't use BLITS!!!: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"NeoMagic MagicGraph 128 PCI", "nmx.drv",
        0x5920000,0x40003, 0x0, 0x0, 0x0, 0x0, {0,0,0,{0,0,0,0,0,0,0,0}}},
        /* overlays (use YUY2 only): */
        {F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2)},
        /* don't use BLITS!!!: */
        {0, 0, 0, 0, 0}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Diamond Stealth II G460",
         "s2g432le.dll",
         0x10542,0x4000a,
         0x8086, 0x7800, 0x0, 0x0,
         {0x0,0x0,0x0,{0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0}}},
        /* overlays (use YUY2 only): */
        {F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2),
        F(CID_YUY2)},
        /* blits (use matching RGBs only): */
        {F(CID_RGB32),
        F(CID_RGB24),
        F(CID_RGB565),
        F(CID_RGB555),
        F(CID_RGB8)}
    },
    {
        VER_PLATFORM_WIN32_WINDOWS,
        {"Diamond Stealth II G460",
         "s2g432le.dll",
         0x10542,0x4000a,
         0x8086, 0x7800, 0x1001092, 0x21,
         {0xd7b78e66,0x3b40,0x11cf,{0x60,0x76,0x1,0x21,0x84,0xc2,0xc9,0x35}}},
        /* don't use overlays: */
        {0, 0, 0, 0, 0},
        /* blits (use matching RGBs only): */
        {F(CID_RGB32),
        F(CID_RGB24),
        F(CID_RGB565),
        F(CID_RGB555),
        F(CID_RGB8)}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
	{"NeoMagic MagicMedia 256AV",
	 "NmgcDD5.dll",
	 0x11451,0x4000a,
	 0x10c8, 0x5, 0x8f1028, 0x20, 
	{0xd7b71e28,0x4345,0x11cf,{0xc9,0x67,0x8e,0x20,0x85,0xc2,0xc9,0x35}}},
        /* do NOT use overlays !!!: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    },
    {
	VER_PLATFORM_WIN32_WINDOWS,
        {"NVIDIA RIVA TNT2 Ultra",
         "NVDD32.DLL",
         0x10170,0x4000c,
         0x10de, 0x29, 0x10211102, 0x11, 
	{0xd7b71e3e,0x4369,0x11cf,{0xc2,0x73,0x20,0x30,0xb2,0xc2,0xc9,0x35}}},
        /* don't use overlays: */
        {0, 0, 0, 0, 0},
        /* no blits either: */
        {0, 0, 0, 0, 0}
    }}
};

static BOOL DDPDB_Opened = FALSE;
static BOOL DDPDB_NewProfile = FALSE;
static time_t DDPDB_FileTime;

/*
 * Initializes profile database:        
 */
BOOL DDPDB_Open(char *pszProfile)
{
    BOOL bRet = FALSE;

    /* check arguments: */
    if (pszProfile && *pszProfile) {

        struct _stat st;

        /* get profile info: */
        if (!_stat(pszProfile, &st) &&
            /* check if we need to reload it: */
            (!DDPDB_Opened || st.st_mtime != DDPDB_FileTime)) {

            FILE *fp;
            size_t s;

            /* save profile time: */
            DDPDB_FileTime = st.st_mtime;

            /* try to open profile: */
            if ((fp = fopen(pszProfile, "rb")) != NULL) {

                /* try to read this file: */
                if ((s = fread((void*)&DDPDB, 1, sizeof DDPDB, fp)) > 0 &&
                    !strncmp(DDPDB.szMagic, DDPDB_MAGIC, 5) &&
                    DDPDB.dwVersion >= DDPDB_VERSION &&
                    DDPDB.dwNumProfiles >= 1 &&
                    DDPDB.dwNumProfiles < MAXPROFILES &&
                    DDPDB.dwNumProfiles * sizeof(DDDEVICEPROFILE) + 16 == s) {

                    /* success: */
                    DDPDB_Opened ++;
                    DDPDB_NewProfile = TRUE;
                    bRet = TRUE;
                }

                /* close file: */
                fclose(fp);
            }
        }
    }
    return bRet;
}

/*
 * Terminates the use of profile database:
 */
BOOL DDPDB_Close ()
{
    return DDPDB_Opened && !--DDPDB_Opened;
}

/*
 * Checks if profile has been updated.
 */
BOOL DDPDB_IsNewProfile ()
{
    BOOL bResult = DDPDB_NewProfile;
    DDPDB_NewProfile = FALSE;
    return bResult;
}


/*********************
 * Default device profiles:
 */
static DDDEVICEPROFILE ddWinNTDefaultProfile =
{
    VER_PLATFORM_WIN32_NT,
    {"", "", 0,0, 0},
    /* overlays (use YUVs only): */
    {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY)},
    /* blits (use YUVs & matching RGBs): */
    {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB32),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB24),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB565),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB555),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB8)}
};

static DDDEVICEPROFILE ddWin9xDefaultProfile =
{
    VER_PLATFORM_WIN32_WINDOWS,
    {"", "", 0,0, 0,0,0,0, 0},
    /* overlays (use YUVs only): */
    {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY)},
    /* blits (use YUVs & matching RGBs): */
    {F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB32),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB24),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB565),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB555),
     F(CID_YV12) + F(CID_YUY2) + F(CID_UYVY) + F(CID_RGB8)}
};

/*
 * Get pointer to a best matching DirectDraw device profile.
 */
LPDDDEVICEPROFILE DDPDB_GetDeviceProfile (LPDIRECTDRAW lpDD)
{
    OSVERSIONINFO osVersion;
    DDDEVICEIDENTIFIER ddID;                    /* DirectDraw & Win95 info */
    char szChipType[MAXCHIPTYPE];               /* NT info      */
    unsigned int bestMatchIdx, deviceBestMatch, driverBestMatch;
    unsigned int i, deviceMatch, driverMatch;

#if DIRECTDRAW_VERSION > 0x0500
    LPDIRECTDRAW4 lpDD4;
#endif

    /* check if we are runnning NT: */
    memset(&osVersion,0, sizeof(OSVERSIONINFO));
    osVersion.dwOSVersionInfoSize  = sizeof(OSVERSIONINFO);
    if (GetVersionEx(&osVersion) && osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) {

        /* try to get WinNT device information: */
        if (GetWinNTDeviceID (&ddID, szChipType)) {

            /* clear best match criteria: */
            deviceBestMatch = driverBestMatch = bestMatchIdx = 0;

            /* scan database: */
            for (i = 0; i < DDPDB.dwNumProfiles; i++) {

                /* check platform ID: */
                if (DDPDB.ddProfiles[i].dwPlatformId == VER_PLATFORM_WIN32_NT) {

                    /* clear match criteria: */
                    deviceMatch = driverMatch = 0;

                    /* check non-critical parameters: */
                    if (!DDPDB.ddProfiles[i].ID.WinNT.szDescription[0] ||
                        !strncmp (DDPDB.ddProfiles[i].ID.WinNT.szDescription, ddID.szDescription, MAXDESCRIPT-1))
                        deviceMatch ++;
                    if (!DDPDB.ddProfiles[i].ID.WinNT.szDriver[0] ||
                        !strnicmp (DDPDB.ddProfiles[i].ID.WinNT.szDriver, ddID.szDriver, MAXDRIVER-1))
                        driverMatch ++;

                    /* check critical data: */
                    if (!DDPDB.ddProfiles[i].ID.WinNT.dwDriverVersionHighPart)
                        driverMatch ++;
                    else if (DDPDB.ddProfiles[i].ID.WinNT.dwDriverVersionHighPart == (DWORD)ddID.liDriverVersion.HighPart)
                        driverMatch += 2;
                    else
                        continue;
                    if (!DDPDB.ddProfiles[i].ID.WinNT.dwDriverVersionLowPart)
                        driverMatch ++;
                    else if (DDPDB.ddProfiles[i].ID.WinNT.dwDriverVersionLowPart == (DWORD)ddID.liDriverVersion.LowPart)
                        driverMatch += 2;
                    else
                        continue;
                    if (!DDPDB.ddProfiles[i].ID.WinNT.szChipType[0])
                        deviceMatch += 1;
                    else if (!strncmp (DDPDB.ddProfiles[i].ID.WinNT.szChipType, szChipType, MAXCHIPTYPE-1))
                        deviceMatch += 2;
                    else
                        continue;

                    /* check the results: */
                    if (deviceMatch + driverMatch > deviceBestMatch + driverBestMatch &&
                        deviceMatch >= deviceBestMatch && driverMatch >= driverBestMatch)
                    {
                        /* update best match: */
                        deviceBestMatch = deviceMatch;
                        driverBestMatch = driverMatch;
                        bestMatchIdx = i;
                    }
                }
            }

            /* check overal search results: */
            if (deviceBestMatch && driverBestMatch >= 3)
            {
                return DDPDB.ddProfiles + bestMatchIdx ;
            }
            
        }

        /* return WinNT default profile: */
        return &ddWinNTDefaultProfile;

    } else { /* Win9x: */

        /* try to get DirectDraw device identifier: */
        memset (&ddID, 0, sizeof (DDDEVICEIDENTIFIER));
        
#if DIRECTDRAW_VERSION > 0x0500 && !defined(IMPORT)
        if ((IDirectDraw_QueryInterface(lpDD, &IID_IDirectDraw4, (void**)&lpDD4) == DD_OK &&
            IDirectDraw4_GetDeviceIdentifier(lpDD4, &ddID, DDGDI_GETHOSTIDENTIFIER) == DD_OK) ||
            /* try to gather Win9x device information manually: */
            GetWin9xDeviceID (&ddID)) {

            /* clear best match criteria: */
            deviceBestMatch = driverBestMatch = bestMatchIdx = 0;

            /* scan database: */
            for (i = 0; i < DDPDB.dwNumProfiles; i++) {

                /* check platform ID: */
                if (DDPDB.ddProfiles[i].dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {

                    /* clear match criteria: */
                    deviceMatch = driverMatch = 0;

                    /* check non-critical parameters: */
                    if (!DDPDB.ddProfiles[i].ID.Win9x.szDescription[0] ||
                        !strncmp (DDPDB.ddProfiles[i].ID.Win9x.szDescription, ddID.szDescription, MAXDESCRIPT-1))
                        deviceMatch ++;
                    if (!DDPDB.ddProfiles[i].ID.Win9x.szDriver[0] ||
                        !strnicmp (DDPDB.ddProfiles[i].ID.Win9x.szDriver, ddID.szDriver, MAXDRIVER-1))
                        driverMatch ++;

                    /* check critical data: */
                    if (!DDPDB.ddProfiles[i].ID.Win9x.dwDriverVersionHighPart)
                        driverMatch ++;
                    else if (DDPDB.ddProfiles[i].ID.Win9x.dwDriverVersionHighPart == (DWORD)ddID.liDriverVersion.HighPart)
                        driverMatch += 2;
                    else
                        continue;
                    if (!DDPDB.ddProfiles[i].ID.Win9x.dwDriverVersionLowPart)
                        driverMatch ++;
                    else if (DDPDB.ddProfiles[i].ID.Win9x.dwDriverVersionLowPart == (DWORD)ddID.liDriverVersion.LowPart)
                        driverMatch += 2;
                    else
                        continue;
                    if (!DDPDB.ddProfiles[i].ID.Win9x.dwVendorId)
                        deviceMatch ++;
                    else if (DDPDB.ddProfiles[i].ID.Win9x.dwVendorId == ddID.dwVendorId)
                        deviceMatch += 2;
                    else
                        continue;
                    if (!DDPDB.ddProfiles[i].ID.Win9x.dwDeviceId)
                        deviceMatch ++;
                    else if (DDPDB.ddProfiles[i].ID.Win9x.dwDeviceId == ddID.dwDeviceId)
                        deviceMatch += 2;
                    else
                        continue;

                    /* check the results: */
                    if (deviceMatch + driverMatch > deviceBestMatch + driverBestMatch &&
                        deviceMatch >= deviceBestMatch && driverMatch >= driverBestMatch) {

                        /* update best match: */
                        deviceBestMatch = deviceMatch;
                        driverBestMatch = driverMatch;
                        bestMatchIdx  = i;
                    }
                }
            }

            /* check overal search results: */
            if (deviceBestMatch >= 3 && driverBestMatch >= 3)
                return DDPDB.ddProfiles + bestMatchIdx;
        }
#endif //DIRECTDRAW_VERSION <= 0x0500

        /* return default profile: */
        return &ddWin9xDefaultProfile;
    }
}

/* packs 2-character string into a normal, single-character one: */
static void PackWideString (char *dest, char *src, int n)
{
    register char *d = dest, *s = src;
    while (n-- && *s) {
        *d = *s;
        s += 2;
        d += 1;
    }
    *d = '\0';
}

static BOOL GetFileVersion(LPTSTR pPath, LPDDDEVICEIDENTIFIER lpddID)
{
    DWORD   dwVerInfoSize;
    DWORD   dwVerHnd;
    BOOL    fSuccess = FALSE;

    // load version.dll
    HINSTANCE		    hLib = NULL;
    VERQUERYVALUE	    _pVerQueryValue = NULL;
    GETFILEVERSIONINFO	    _pGetFileVersionInfo = NULL;
    GETFILEVERSIONINFOSIZE  _pGetFileVersionInfoSize = NULL;

    hLib = LoadLibrary("version.dll");

    if (hLib)
    {
	_pVerQueryValue = (VERQUERYVALUE)GetProcAddress(hLib, "VerQueryValueA");
	_pGetFileVersionInfo = (GETFILEVERSIONINFO)GetProcAddress(hLib, "GetFileVersionInfoA");
	_pGetFileVersionInfoSize = (GETFILEVERSIONINFOSIZE)GetProcAddress(hLib, "GetFileVersionInfoSizeA");
    }

    if (_pVerQueryValue		&&
	_pGetFileVersionInfo	&&
	_pGetFileVersionInfoSize)
    {
	/* set everything to 0: */
	lpddID->liDriverVersion.HighPart = 0;
	lpddID->liDriverVersion.LowPart = 0;

	/* get size of version info: */
	if ((dwVerInfoSize = _pGetFileVersionInfoSize(pPath, &dwVerHnd)) != 0) {

	    HANDLE  hMem;                     /* handle to mem alloc'ed */
	    LPSTR   lpstrVffInfo;             /* Pointer to block to hold info */

	    /* Get a block big enough to hold version info */
	    hMem          = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
	    lpstrVffInfo  = (char *)GlobalLock(hMem);

	    /* get file version info: */
	    if (_pGetFileVersionInfo(pPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo)) {

		UINT    VersionLen;
		LPSTR   lpVersion;

		/* query version info: */
		if (_pVerQueryValue(lpstrVffInfo, "\\",
		    (void FAR* FAR*)&lpVersion, &VersionLen)) {

		    /* copy version info: */
		    VS_FIXEDFILEINFO* pFileInfo = (VS_FIXEDFILEINFO*)lpVersion;
		    lpddID->liDriverVersion.HighPart = pFileInfo->dwFileVersionMS;
		    lpddID->liDriverVersion.LowPart = pFileInfo->dwFileVersionLS;

		    /* indicate success: */
		    fSuccess = TRUE;
		}
	    }

	    /* Let go of the memory */
	    GlobalUnlock(hMem);
	    GlobalFree(hMem);
	}
    }

    FreeLibrary(hLib);

    return fSuccess;
}

#define MAX_BUF        512
#ifdef TRACE
#define Trace(pMsg)  printf("-->%s\n", pMsg)
#else
#define Trace(pMsg)  ((void)0)
#endif

/*
 * This whole thing is based on Jeff's CFullScreenInfo:: code:
 */
BOOL GetWinNTDeviceID (LPDDDEVICEIDENTIFIER lpddID, char *pszChipType)
{
    HKEY        hKey;
    char        szBuffer[MAX_BUF];
    DWORD       bufSize  = sizeof(szBuffer) - 1;
    char        pDLLPath[_MAX_PATH];
    const char* pszStrip = "\\registry\\machine\\";
    LONG        res = ERROR_SUCCESS;
    BOOL        retVal = FALSE;
    
    /* open Hardware\\DEVICEMAP\\VIDEO key: */
    res = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
                        "Hardware\\DEVICEMAP\\VIDEO",
                        0,
                        KEY_READ,
                        &hKey
                        );
    
    if( ERROR_SUCCESS == res )
    {
        /* query a Video0 entry: */
        memset(szBuffer, 0, sizeof(szBuffer) );
        res = RegQueryValueEx(hKey,
                              "\\Device\\Video0",
                              NULL,
                              NULL,
                              (LPBYTE) szBuffer,
                              (LPDWORD)&bufSize);

        //Done with first key.
        RegCloseKey(hKey);
        
        if( ERROR_SUCCESS == res )
        {
            //Find \Registry\Machine in the key's values and strip it
            //off. Some machines write the key in different cases.
            //If we can't find it, something is wrong. It also must
            //be at the start of the string.
            _strlwr( szBuffer );
            if( strstr(szBuffer, pszStrip) == szBuffer )
            {
                res = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
                                   szBuffer + strlen(pszStrip), //Skip pre-log.
                                   0,
                                   KEY_READ,
                                   &hKey);

                if( res == ERROR_SUCCESS )
                {
                    /* get Device Description: */
                    memset( szBuffer, 0, sizeof(szBuffer) );
                    bufSize = sizeof( szBuffer)-1;
                    res = RegQueryValueEx( hKey,
                                           "HardwareInformation.AdapterString",
                                           NULL,
                                           NULL,
                                           (LPBYTE) szBuffer,
                                           (LPDWORD)&bufSize);
            
                    if( ERROR_SUCCESS == res )
                    {
                        /* move it to dddid: */
                        PackWideString(lpddID->szDescription, szBuffer, MAXDESCRIPT-1);

                        /* get ChipType information: */
                        memset( szBuffer, 0, sizeof(szBuffer) );
                        bufSize = sizeof( szBuffer)-1;
                        res = RegQueryValueEx( hKey,
                                               "HardwareInformation.ChipType",
                                               NULL,
                                               NULL,
                                               (LPBYTE) szBuffer,
                                               (LPDWORD)&bufSize);
            
                        if( ERROR_SUCCESS == res )
                        {
                            /* copy it: */
                            PackWideString (pszChipType, szBuffer, MAXCHIPTYPE-1);

                            /* get driver name: */
                            memset( szBuffer, 0, sizeof(szBuffer) );
                            bufSize = sizeof( szBuffer)-1;
                            res = RegQueryValueEx( hKey,
                                                   "InstalledDisplayDrivers",
                                                   NULL,
                                                   NULL,
                                                   (LPBYTE) szBuffer,
                                                   (LPDWORD)&bufSize);
                            if( ERROR_SUCCESS == res && bufSize )
                            {
                                //copy driver name
                                strcat(szBuffer, ".dll");
                                strncpy(lpddID->szDriver, szBuffer, MAXDRIVER-1);

                                // get full path to the driver:
                                if(GetSystemDirectory(pDLLPath, _MAX_PATH) != 0)
                                {
                                    strcat(pDLLPath, "\\");
                                    strcat(pDLLPath, szBuffer);

                                    // query file version:
                                    if( GetFileVersion(pDLLPath, lpddID) )
                                    {
                                        retVal = TRUE;
                                    }
                                    
                                }
                            }
                        }
                    }
                    RegCloseKey(hKey);
                }
            }
        }
    }
    
    return retVal;
}

static BOOL DevNodeIsActive(char *szDeviceID)
{
    HINSTANCE hDevNodeInst;
    DWORD dwStatus;
    DWORD dwProblemNumber;
    DWORD cr;

    DWORD (WINAPI *pGetDevNodeStatus32Call) (const char *, LPDWORD, LPDWORD);

    /*
     * 10 is a magic number for the configuration manager api
     * that eventually gets called in the 16 bit dll.
     */
    dwStatus = dwProblemNumber = cr = 10;
    pGetDevNodeStatus32Call = 0;

    if ((hDevNodeInst = LoadLibrary(_32BIT_DLLNAME)) != 0)
    {
        if (((FARPROC)pGetDevNodeStatus32Call = GetProcAddress(hDevNodeInst, "GetDevNodeStatus32Call")) != NULL)
        {
            cr = (* pGetDevNodeStatus32Call) (szDeviceID, &dwStatus, &dwProblemNumber);
        }

        FreeLibrary(hDevNodeInst);
    }

    return cr == 0 && dwProblemNumber == 0;
}

static unsigned int hex2uint (char *p, int n)
{
    register unsigned int i = 0;
    while (n--)
    {
        register unsigned int j = *p;
        i <<= 4;
        if (j <= '9')   j -= '0';
        else            j -= 'A' - 10;
        p ++;
        i |= j;
    }
    return i;
}

/*
 * Extract Win9x DirectDraw device information:
 */
BOOL GetWin9xDeviceID (LPDDDEVICEIDENTIFIER lpddID)
{
    static char *szEnum_Name [ENUM_MAX] = {
        REGSTR_KEY_ROOTENUM, REGSTR_KEY_BIOSENUM,
        REGSTR_KEY_PCIENUM,  REGSTR_KEY_ISAENUM,
        REGSTR_KEY_EISAENUM, REGSTR_KEY_PCMCIAENUM
    };

    /* moved out of stack for safety reasons... */
    static char szCurrentKey [MAX_BUF];
    static char szCurrentDeviceNode[MAX_BUF];
    static char szCurrentDevice [MAX_BUF];
    static char szClass [64];
    static char szDeviceID [MAX_BUF];
    static char szSoftwareKey [MAX_BUF];
    static char pDLLPath [_MAX_PATH];

    ULONG ulType;
    ULONG32 cbData;
    HKEY hSoftwareKey;
    char *p;
    int i;

    Trace("entering GetWin9xDeviceID... ");

    /* we want to look through the ENUM\BIOS, ENUM\ISAPNP, and ENUM\PCI
     * trees for devices of the DISPLAY class.  For each display device
     * we find we will ask the Device manager if it is active. */
    for (i = 0; i < ENUM_MAX; i++)
    {
        HKEY hBusKey;
        /* construct a string for the current key: */
        strcpy(szCurrentKey, REGSTR_KEY_ENUM);
        strcat(szCurrentKey, "\\");
        strcat(szCurrentKey, szEnum_Name[i]);

        Trace("\nopenining LOCAL_MACHINE key:");
        Trace(szCurrentKey);

        /* start reading the devices */
        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCurrentKey, 0, KEY_READ, &hBusKey) == ERROR_SUCCESS)
        {
            ULONG32 dwDevNodeEnumIndex = 0;

            Trace("opened;");

            /* Enumerate all of the devices on the bus */
            while (1)
            {
                HKEY hDeviceNodeKey;

                memset(szCurrentDeviceNode, 0, sizeof(szCurrentDeviceNode));
                cbData = sizeof(szCurrentDeviceNode) - 1;
                if (RegEnumKeyEx(hBusKey, dwDevNodeEnumIndex, szCurrentDeviceNode, &cbData, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
                    break;

                /* construct a string for current device node: */
                strcpy(szCurrentKey,REGSTR_KEY_ENUM);
                strcat(szCurrentKey, "\\");
                strcat(szCurrentKey, szEnum_Name[i]);
                strcat(szCurrentKey, "\\");
                strcat(szCurrentKey, szCurrentDeviceNode);

                Trace("opening device node:");
                Trace(szCurrentKey);

                /* get the registry key for the current device node */
                if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCurrentKey, 0, KEY_READ, &hDeviceNodeKey) == ERROR_SUCCESS)
                {
                    ULONG32 dwHWDeviceEnumIndex = 0;

                    Trace("opened;");

                    /* enumerate all of the hardware devices in this Device Node */
                    while (1)
                    {
                        HKEY hHWDeviceKey;
                        int nBaseKeyLength;

                        memset(szCurrentDevice, 0, sizeof(szCurrentDevice));
                        cbData = sizeof(szCurrentDevice) - 1;
                        if (RegEnumKeyEx(hDeviceNodeKey, dwHWDeviceEnumIndex, szCurrentDevice, &cbData, NULL, NULL, NULL, NULL) != ERROR_SUCCESS)
                            break;

                        /* get the registry key for the current hardware device */
                        nBaseKeyLength = strlen(szCurrentKey);

                        /* append currect device name: */
                        strcat(szCurrentKey, "\\");
                        strcat(szCurrentKey, szCurrentDevice);

                        Trace("opening device named:");
                        Trace(szCurrentKey);

                        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCurrentKey, 0, KEY_READ, &hHWDeviceKey) == ERROR_SUCCESS)
                        {
                            Trace("opened;");

                            /* ask if this device is a "DISPLAY" device by checking it's class */
                            cbData = sizeof(szClass);
                            szClass[0] = 0;

                            Trace("quering class of this device: ");

                            if (RegQueryValueEx(hHWDeviceKey, "Class", 0, &ulType, (LPBYTE) szClass, &cbData) == ERROR_SUCCESS)
                            {
                                Trace("obtained:");
                                Trace(szClass);

                                /* is it Display??? */
                                if (!stricmp(szClass, "DISPLAY"))
                                {
                                    Trace("looks like a display adapter!!");

                                    /* if it is a display device then we want to find out if it is
                                     * the active device for this class. */
                                    memset(szSoftwareKey, 0, sizeof(szSoftwareKey));
                                    cbData = sizeof(szSoftwareKey) - 1;

                                    /* create a string for Device ID: */
                                    strcpy(szDeviceID, szEnum_Name[i]);
                                    strcat(szDeviceID, "\\");
                                    strcat(szDeviceID, szCurrentDeviceNode);
                                    strcat(szDeviceID, "\\");
                                    strcat(szDeviceID, szCurrentDevice);

                                    Trace("quering device ID:");
                                    Trace(szDeviceID);

                                    /* get the registry key name for the software key for the device,
                                     * if it is not null and this is the active device then we are done. */
                                    if (RegQueryValueEx(hHWDeviceKey, "Driver", 0, &ulType, (LPBYTE) szSoftwareKey, &cbData) == ERROR_SUCCESS &&
                                        szSoftwareKey[0] != '0' &&
                                        DevNodeIsActive(szDeviceID))    /* Call Config Manager in 16-bit code */
                                    {
                                        Trace("device found!!!:");

                                        /* close all open keys and continue processing... */
                                        RegCloseKey(hHWDeviceKey);
                                        RegCloseKey(hDeviceNodeKey);
                                        RegCloseKey(hBusKey);
                                        goto cont;
                                    }
                                }
                            }
                            /* close hardware device key: */
                            RegCloseKey(hHWDeviceKey);
                        }
                        /* reset the key to the base for the next time through the loop: */
                        memset (szCurrentKey + nBaseKeyLength, 0, sizeof(szCurrentKey) - nBaseKeyLength);

                        /* move to next device key */
                        dwHWDeviceEnumIndex ++;
                    }
                    /* close device node key: */
                    RegCloseKey(hDeviceNodeKey);
                }
                /* move to the next device node */
                dwDevNodeEnumIndex ++;
            }
            /* close bus key: */
            RegCloseKey(hBusKey);
        }
    }
    Trace("exiting GetWin9xDeviceID (device not found):");
    /* not found: */
    return FALSE;


cont:
    /* get Vendor ID: */
    if ((p = strstr(szDeviceID, "VEN_")) != 0)
        lpddID->dwVendorId = hex2uint (p + strlen("VEN_"), 4);

    /* get DeviceID: */
    if ((p = strstr(szDeviceID, "DEV_")) != 0)
        lpddID->dwDeviceId = hex2uint (p + strlen("DEV_"), 4);

    /* get Revision #: */
    if ((p = strstr(szDeviceID, "REV_")) != 0)
        lpddID->dwRevision = hex2uint (p + strlen("REV_"), 4);

    /* if we found the software key, we want to go get the Driver description
     * and the driver file name: */

    /* create a software key string: */
    strcpy(szCurrentKey, REGSTR_PATH_CLASS);
    strcat(szCurrentKey, "\\");
    strcat(szCurrentKey, szSoftwareKey);

    Trace("opening software key:");
    Trace(szCurrentKey);

    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCurrentKey, 0, KEY_READ, &hSoftwareKey) == ERROR_SUCCESS)
    {
        /* use external buffer: */
        char* szAdapterString = lpddID->szDescription;
        cbData = MAX_DDDEVICEID_STRING;

        Trace("opened;");

        /* query device description: */
        RegQueryValueEx(hSoftwareKey, "DriverDesc", 0, &ulType, (LPBYTE)szAdapterString, &cbData);

        /* close software key; */
        RegCloseKey(hSoftwareKey);
    }

    /* now look in the Default key for the driver file name */
    strcat(szCurrentKey, "\\DEFAULT");
    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, szCurrentKey, 0, KEY_READ, &hSoftwareKey) == ERROR_SUCCESS)
    {
        char* szDisplayDriverName = lpddID->szDriver;
        cbData = MAX_DDDEVICEID_STRING;

        /* query driver name: */
        RegQueryValueEx(hSoftwareKey, "drv", 0, &ulType, (LPBYTE)szDisplayDriverName, &cbData);

        /* close software key: */
        RegCloseKey(hSoftwareKey);

        /* get the file version: */
        if (GetSystemDirectory(pDLLPath, _MAX_PATH) != 0)
        {
            strcat(pDLLPath, "\\");
            strcat(pDLLPath, szDisplayDriverName);

            Trace("trying to get a file version:");

            /* query file version: */
            GetFileVersion(pDLLPath, lpddID);
        }
    }

    Trace("exiting GetWin9xDeviceID:");
    return TRUE;
}


/***********************************
 * Utilities:
 **************************************/

#ifdef DUMP
/* a simple database creation program: */
int main (int argc, char *argv[])
{
    FILE *fp;
    int s;

    /* check arguments: */
    if (argc < 2) {
        fprintf (stderr, "Use:\n\tDDPDB <file name>\n");
        exit (EXIT_FAILURE);
    }

    /* create a file: */
    if ((fp = fopen (argv[1], "wb+")) == NULL) {
        fprintf (stderr, "Cannot open database file.\n");
        exit (EXIT_FAILURE);
    }

    /* calculate the size of file: */
    s = 16 + DDPDB.dwNumProfiles * sizeof(DDDEVICEPROFILE);

    /* dump raw data: */
    if (fwrite((void*)&DDPDB, 1, s, fp) != s) {
        fprintf (stderr, "Write error (out of disk space?).\n");
        exit (EXIT_FAILURE);
    }

    /* close file: */
    fclose(fp);
    exit (EXIT_SUCCESS);
}
#endif /* DUMP */


#ifdef IMPORT
/* a profile generation program: */
int main ()
{
    OSVERSIONINFO osVersion;
    LPDIRECTDRAW lpDD;
    LPDIRECTDRAW4 lpDD4;
    DDDEVICEIDENTIFIER ddID;                    /* DirectDraw & Win95 info      */
    char szChipType[MAXCHIPTYPE];               /* NT info      */

    /* try to load DirectDraw library: */
    if (DirectDrawCreate (NULL, &lpDD, NULL) != DD_OK) {
        printf ("Cannot create DirectDraw object!");
        exit(EXIT_FAILURE);
    }

    /* check if we are runnning NT: */
    memset(&osVersion,0, sizeof(OSVERSIONINFO));
    osVersion.dwOSVersionInfoSize  = sizeof(OSVERSIONINFO);
    if (GetVersionEx(&osVersion) && osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT)
    {
        /* try to get WinNT device information: */
        if (!GetWinNTDeviceID (&ddID, szChipType)) {
            fprintf (stderr, "Cannot get NT driver info\n");
            exit (EXIT_FAILURE);
        }
        /* print header: */
        printf ("\tVER_PLATFORM_WIN32_NT,\n");

    }
    else
    { /* Win9x: */
#ifndef IMPORT        
        /* try to get DirectDraw device identifier: */
        memset (&ddID, 0, sizeof (DDDEVICEIDENTIFIER));
        if (
            (IDirectDraw_QueryInterface(lpDD, &IID_IDirectDraw4, (void**)&lpDD4) != DD_OK ||
            IDirectDraw4_GetDeviceIdentifier(lpDD4, &ddID, DDGDI_GETHOSTIDENTIFIER) != DD_OK) &&
            /* try to gather Win9x device information manually: */
            !GetWin9xDeviceID (&ddID)) {
                fprintf (stderr, "Cannot get Win9x driver info\n");
                exit (EXIT_FAILURE);
            }

        /* print header: */
        printf( "\tVER_PLATFORM_WIN32_WINDOWS,\n");
#else
        printf( "Need more work to run this tool on win95 machines.....\n" );
#endif        
    }

    /* dump description: */
    ddID.szDescription[MAXDESCRIPT-1] = '\0';
    printf ("\t{\"%s\",\n", ddID.szDescription);

    /* dump driver: */
    ddID.szDriver[MAXDRIVER-1] = '\0';
    printf ("\t \"%s\",\n", ddID.szDriver);

    /* driver version: */
    printf ("\t 0x%x,0x%x,\n", ddID.liDriverVersion.LowPart, ddID.liDriverVersion.HighPart);

    if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_NT) {
        /* dump: WinNT vars:*/
        printf ("\t 0x%x, 0x%x, 0x%x, 0x%x, \n",
            *(DWORD*)(szChipType), *(DWORD*)(szChipType+4), *(DWORD*)(szChipType+8), *(DWORD*)(szChipType+12));

        printf ("\t {0x%x,0x%x,0x%x,{0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x}}\n",
            *(DWORD*)(szChipType+16), *(WORD*)(szChipType+20), *(WORD*)(szChipType+22),
            szChipType[24], szChipType[25], szChipType[26], szChipType[27],
            szChipType[28], szChipType[29], szChipType[30], szChipType[31]);

    } else {
        /* dump: Win9x vars:*/
        printf ("\t 0x%x, 0x%x, 0x%x, 0x%x, \n",
            ddID.dwVendorId, ddID.dwDeviceId, ddID.dwSubSysId, ddID.dwRevision);
        printf ("\t {0x%x,0x%x,0x%x,{0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x,0x%x}}\n",
            ddID.guidDeviceIdentifier.Data1,
            ddID.guidDeviceIdentifier.Data2,    ddID.guidDeviceIdentifier.Data3,
            ddID.guidDeviceIdentifier.Data4[0], ddID.guidDeviceIdentifier.Data4[1],
            ddID.guidDeviceIdentifier.Data4[2], ddID.guidDeviceIdentifier.Data4[3],
            ddID.guidDeviceIdentifier.Data4[4], ddID.guidDeviceIdentifier.Data4[5],
            ddID.guidDeviceIdentifier.Data4[6], ddID.guidDeviceIdentifier.Data4[7]);
    }

    exit (EXIT_SUCCESS);
}
#endif /* IMPORT */

/* ddpdb.c -- end of file */

