/********************************************************************

 import_nt.c

  Win32 specific import code.

*/

#include "Python.h"
#include "osdefs.h"
#include <windows.h>
#include "importdl.h"
#include "malloc.h" /* for alloca */

/* a string loaded from the DLL at startup */
extern const char *PyWin_DLLVersionString;

/* Find a module on Windows.

   Read the registry Software\Python\PythonCore\<version>\Modules\<name> (or
   Software\Python\PythonCore\<version>\Modules\<name>\Debug in debug mode)
   from HKEY_CURRENT_USER, or HKEY_LOCAL_MACHINE. Find the file descriptor using
   the file extension. Open the file.

   On success, write the file descriptor into *ppFileDesc, the module path
   (Unicode object) into *pPath, and return the opened file object. If the
   module cannot be found (e.g. no registry key or the file doesn't exist),
   return NULL. On error, raise a Python exception and return NULL.
 */
FILE *
_PyWin_FindRegisteredModule(PyObject *moduleName,
                            struct filedescr **ppFileDesc,
                            PyObject **pPath)
{
    wchar_t pathBuf[MAXPATHLEN+1];
    int pathLen = MAXPATHLEN+1;
    PyObject *path, *moduleKey, *suffix;
    wchar_t *wmoduleKey, *wsuffix;
    struct filedescr *fdp;
    HKEY keyBase;
    int modNameSize;
    long regStat;
    Py_ssize_t extLen;
    FILE *fp;

    moduleKey = PyUnicode_FromFormat(
#ifdef _DEBUG
        /* In debugging builds, we _must_ have the debug version registered */
        "Software\\Python\\PythonCore\\%s\\Modules\\%U\\Debug",
#else
        "Software\\Python\\PythonCore\\%s\\Modules\\%U",
#endif
        PyWin_DLLVersionString, moduleName);
    if (moduleKey == NULL)
        return NULL;
    wmoduleKey = PyUnicode_AsUnicode(moduleKey);
    if (wmoduleKey == NULL) {
        Py_DECREF(moduleKey);
        return NULL;
    }

    keyBase = HKEY_CURRENT_USER;
    modNameSize = pathLen;
    regStat = RegQueryValueW(keyBase, wmoduleKey,
                             pathBuf, &modNameSize);
    if (regStat != ERROR_SUCCESS) {
        /* No user setting - lookup in machine settings */
        keyBase = HKEY_LOCAL_MACHINE;
        /* be anal - failure may have reset size param */
        modNameSize = pathLen;
        regStat = RegQueryValueW(keyBase, wmoduleKey,
                                 pathBuf, &modNameSize);
        if (regStat != ERROR_SUCCESS) {
            Py_DECREF(moduleKey);
            return NULL;
        }
    }
    Py_DECREF(moduleKey);
    if (modNameSize < 3) {
        /* path shorter than "a.o" or negative length (cast to
           size_t is wrong) */
        return NULL;
    }
    /* use the file extension to locate the type entry. */
    for (fdp = _PyImport_Filetab; fdp->suffix != NULL; fdp++) {
        suffix = PyUnicode_FromString(fdp->suffix);
        if (suffix == NULL)
            return NULL;
        wsuffix = PyUnicode_AsUnicodeAndSize(suffix, &extLen);
        if (wsuffix == NULL) {
            Py_DECREF(suffix);
            return NULL;
        }
        if ((Py_ssize_t)modNameSize > extLen &&
            _wcsnicmp(pathBuf + ((Py_ssize_t)modNameSize-extLen-1),
                      wsuffix,
                      extLen) == 0)
        {
            Py_DECREF(suffix);
            break;
        }
        Py_DECREF(suffix);
    }
    if (fdp->suffix == NULL)
        return NULL;
    path = PyUnicode_FromWideChar(pathBuf, wcslen(pathBuf));
    if (path == NULL)
        return NULL;
    fp = _Py_fopen(path, fdp->mode);
    if (fp == NULL) {
        Py_DECREF(path);
        return NULL;
    }
    *pPath = path;
    *ppFileDesc = fdp;
    return fp;
}
