mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-11-04 03:27:00 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			419 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			419 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
//-----------------------------------------------------------------------------
 | 
						|
// util.c
 | 
						|
//   Shared library for use by cx_Freeze.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
 | 
						|
#include <Python.h>
 | 
						|
 | 
						|
#ifdef WIN32
 | 
						|
#include <windows.h>
 | 
						|
#include <imagehlp.h>
 | 
						|
 | 
						|
#pragma pack(2)
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    BYTE bWidth;                        // Width, in pixels, of the image
 | 
						|
    BYTE bHeight;                       // Height, in pixels, of the image
 | 
						|
    BYTE bColorCount;                   // Number of colors in image
 | 
						|
    BYTE bReserved;                     // Reserved ( must be 0)
 | 
						|
    WORD wPlanes;                       // Color Planes
 | 
						|
    WORD wBitCount;                     // Bits per pixel
 | 
						|
    DWORD dwBytesInRes;                 // How many bytes in this resource?
 | 
						|
    DWORD dwImageOffset;                // Where in the file is this image?
 | 
						|
} ICONDIRENTRY;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    WORD idReserved;                    // Reserved (must be 0)
 | 
						|
    WORD idType;                        // Resource Type (1 for icons)
 | 
						|
    WORD idCount;                       // How many images?
 | 
						|
    ICONDIRENTRY idEntries[0];          // An entry for each image
 | 
						|
} ICONDIR;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    BYTE bWidth;                        // Width, in pixels, of the image
 | 
						|
    BYTE bHeight;                       // Height, in pixels, of the image
 | 
						|
    BYTE bColorCount;                   // Number of colors in image
 | 
						|
    BYTE bReserved;                     // Reserved ( must be 0)
 | 
						|
    WORD wPlanes;                       // Color Planes
 | 
						|
    WORD wBitCount;                     // Bits per pixel
 | 
						|
    DWORD dwBytesInRes;                 // How many bytes in this resource?
 | 
						|
    WORD nID;                           // resource ID
 | 
						|
} GRPICONDIRENTRY;
 | 
						|
 | 
						|
typedef struct {
 | 
						|
    WORD idReserved;                    // Reserved (must be 0)
 | 
						|
    WORD idType;                        // Resource Type (1 for icons)
 | 
						|
    WORD idCount;                       // How many images?
 | 
						|
    GRPICONDIRENTRY idEntries[0];       // An entry for each image
 | 
						|
} GRPICONDIR;
 | 
						|
#endif
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// Globals
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
#ifdef WIN32
 | 
						|
static PyObject *g_BindErrorException = NULL;
 | 
						|
static PyObject *g_ImageNames = NULL;
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#ifdef WIN32
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// BindStatusRoutine()
 | 
						|
//   Called by BindImageEx() at various points. This is used to determine the
 | 
						|
// dependency tree which is later examined by cx_Freeze.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static BOOL __stdcall BindStatusRoutine(
 | 
						|
    IMAGEHLP_STATUS_REASON reason,      // reason called
 | 
						|
    PSTR imageName,                     // name of image being examined
 | 
						|
    PSTR dllName,                       // name of DLL
 | 
						|
    ULONG virtualAddress,               // computed virtual address
 | 
						|
    ULONG parameter)                    // parameter (value depends on reason)
 | 
						|
{
 | 
						|
    char fileName[MAX_PATH + 1];
 | 
						|
 | 
						|
    switch (reason) {
 | 
						|
        case BindImportModule:
 | 
						|
            if (!SearchPath(NULL, dllName, NULL, sizeof(fileName), fileName,
 | 
						|
                    NULL))
 | 
						|
                return FALSE;
 | 
						|
            Py_INCREF(Py_None);
 | 
						|
            if (PyDict_SetItemString(g_ImageNames, fileName, Py_None) < 0)
 | 
						|
                return FALSE;
 | 
						|
            break;
 | 
						|
        default:
 | 
						|
            break;
 | 
						|
    }
 | 
						|
    return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// GetFileData()
 | 
						|
//   Return the data for the given file.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static int GetFileData(
 | 
						|
    const char *fileName,               // name of file to read
 | 
						|
    char **data)                        // pointer to data (OUT)
 | 
						|
{
 | 
						|
    DWORD numberOfBytesRead, dataSize;
 | 
						|
    HANDLE file;
 | 
						|
 | 
						|
    file = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL,
 | 
						|
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
 | 
						|
    if (file == INVALID_HANDLE_VALUE)
 | 
						|
        return -1;
 | 
						|
    dataSize = GetFileSize(file, NULL);
 | 
						|
    if (dataSize == INVALID_FILE_SIZE) {
 | 
						|
        CloseHandle(file);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    *data = PyMem_Malloc(dataSize);
 | 
						|
    if (!*data) {
 | 
						|
        CloseHandle(file);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    if (!ReadFile(file, *data, dataSize, &numberOfBytesRead, NULL)) {
 | 
						|
        CloseHandle(file);
 | 
						|
        return -1;
 | 
						|
    }
 | 
						|
    CloseHandle(file);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// CreateGroupIconResource()
 | 
						|
//   Return the group icon resource given the icon file data.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static GRPICONDIR *CreateGroupIconResource(
 | 
						|
    ICONDIR *iconDir,                   // icon information
 | 
						|
    DWORD *resourceSize)                // size of resource (OUT)
 | 
						|
{
 | 
						|
    GRPICONDIR *groupIconDir;
 | 
						|
    int i;
 | 
						|
 | 
						|
    *resourceSize = sizeof(GRPICONDIR) +
 | 
						|
            sizeof(GRPICONDIRENTRY) * iconDir->idCount;
 | 
						|
    groupIconDir = PyMem_Malloc(*resourceSize);
 | 
						|
    if (!groupIconDir)
 | 
						|
        return NULL;
 | 
						|
    groupIconDir->idReserved = iconDir->idReserved;
 | 
						|
    groupIconDir->idType = iconDir->idType;
 | 
						|
    groupIconDir->idCount = iconDir->idCount;
 | 
						|
    for (i = 0; i < iconDir->idCount; i++) {
 | 
						|
        groupIconDir->idEntries[i].bWidth = iconDir->idEntries[i].bWidth;
 | 
						|
        groupIconDir->idEntries[i].bHeight = iconDir->idEntries[i].bHeight;
 | 
						|
        groupIconDir->idEntries[i].bColorCount =
 | 
						|
                iconDir->idEntries[i].bColorCount;
 | 
						|
        groupIconDir->idEntries[i].bReserved = iconDir->idEntries[i].bReserved;
 | 
						|
        groupIconDir->idEntries[i].wPlanes = iconDir->idEntries[i].wPlanes;
 | 
						|
        groupIconDir->idEntries[i].wBitCount = iconDir->idEntries[i].wBitCount;
 | 
						|
        groupIconDir->idEntries[i].dwBytesInRes =
 | 
						|
                iconDir->idEntries[i].dwBytesInRes;
 | 
						|
        groupIconDir->idEntries[i].nID = i + 1;
 | 
						|
    }
 | 
						|
 | 
						|
    return groupIconDir;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtAddIcon()
 | 
						|
//   Add the icon as a resource to the specified file.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtAddIcon(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments
 | 
						|
{
 | 
						|
    char *executableName, *iconName, *data, *iconData;
 | 
						|
    GRPICONDIR *groupIconDir;
 | 
						|
    DWORD resourceSize;
 | 
						|
    ICONDIR *iconDir;
 | 
						|
    BOOL succeeded;
 | 
						|
    HANDLE handle;
 | 
						|
    int i;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "ss", &executableName, &iconName))
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    // begin updating the executable
 | 
						|
    handle = BeginUpdateResource(executableName, FALSE);
 | 
						|
    if (!handle) {
 | 
						|
        PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
 | 
						|
                GetLastError(), executableName);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    // first attempt to get the data from the icon file
 | 
						|
    data = NULL;
 | 
						|
    succeeded = TRUE;
 | 
						|
    groupIconDir = NULL;
 | 
						|
    if (GetFileData(iconName, &data) < 0)
 | 
						|
        succeeded = FALSE;
 | 
						|
    iconDir = (ICONDIR*) data;
 | 
						|
 | 
						|
    // next, attempt to add a group icon resource
 | 
						|
    if (succeeded) {
 | 
						|
        groupIconDir = CreateGroupIconResource(iconDir, &resourceSize);
 | 
						|
        if (groupIconDir)
 | 
						|
            succeeded = UpdateResource(handle, RT_GROUP_ICON,
 | 
						|
                    MAKEINTRESOURCE(1),
 | 
						|
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
 | 
						|
                    groupIconDir, resourceSize);
 | 
						|
        else succeeded = FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    // next, add each icon as a resource
 | 
						|
    if (succeeded) {
 | 
						|
        for (i = 0; i < iconDir->idCount; i++) {
 | 
						|
            iconData = &data[iconDir->idEntries[i].dwImageOffset];
 | 
						|
            resourceSize = iconDir->idEntries[i].dwBytesInRes;
 | 
						|
            succeeded = UpdateResource(handle, RT_ICON, MAKEINTRESOURCE(i + 1),
 | 
						|
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), iconData,
 | 
						|
                    resourceSize);
 | 
						|
            if (!succeeded)
 | 
						|
                break;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // finish writing the resource (or discarding the changes upon an error)
 | 
						|
    if (!EndUpdateResource(handle, !succeeded)) {
 | 
						|
        if (succeeded) {
 | 
						|
            succeeded = FALSE;
 | 
						|
            PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
 | 
						|
                    GetLastError(), executableName);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    // clean up
 | 
						|
    if (groupIconDir)
 | 
						|
        PyMem_Free(groupIconDir);
 | 
						|
    if (data)
 | 
						|
        PyMem_Free(data);
 | 
						|
    if (!succeeded)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    Py_INCREF(Py_None);
 | 
						|
    return Py_None;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtBeginUpdateResource()
 | 
						|
//   Wrapper for BeginUpdateResource().
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtBeginUpdateResource(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments
 | 
						|
{
 | 
						|
    BOOL deleteExistingResources;
 | 
						|
    char *fileName;
 | 
						|
    HANDLE handle;
 | 
						|
 | 
						|
    deleteExistingResources = TRUE;
 | 
						|
    if (!PyArg_ParseTuple(args, "s|i", &fileName, &deleteExistingResources))
 | 
						|
        return NULL;
 | 
						|
    handle = BeginUpdateResource(fileName, deleteExistingResources);
 | 
						|
    if (!handle) {
 | 
						|
        PyErr_SetExcFromWindowsErrWithFilename(PyExc_WindowsError,
 | 
						|
                GetLastError(), fileName);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    return PyInt_FromLong((long) handle);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtUpdateResource()
 | 
						|
//   Wrapper for UpdateResource().
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtUpdateResource(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments
 | 
						|
{
 | 
						|
    int resourceType, resourceId, resourceDataSize;
 | 
						|
    char *resourceData;
 | 
						|
    HANDLE handle;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "iiis#", &handle, &resourceType, &resourceId,
 | 
						|
            &resourceData, &resourceDataSize))
 | 
						|
        return NULL;
 | 
						|
    if (!UpdateResource(handle, MAKEINTRESOURCE(resourceType),
 | 
						|
            MAKEINTRESOURCE(resourceId),
 | 
						|
            MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), resourceData,
 | 
						|
            resourceDataSize)) {
 | 
						|
        PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    Py_INCREF(Py_None);
 | 
						|
    return Py_None;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtEndUpdateResource()
 | 
						|
//   Wrapper for EndUpdateResource().
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtEndUpdateResource(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments
 | 
						|
{
 | 
						|
    BOOL discardChanges;
 | 
						|
    HANDLE handle;
 | 
						|
 | 
						|
    discardChanges = FALSE;
 | 
						|
    if (!PyArg_ParseTuple(args, "i|i", &handle, &discardChanges))
 | 
						|
        return NULL;
 | 
						|
    if (!EndUpdateResource(handle, discardChanges)) {
 | 
						|
        PyErr_SetExcFromWindowsErr(PyExc_WindowsError, GetLastError());
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
    Py_INCREF(Py_None);
 | 
						|
    return Py_None;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtGetDependentFiles()
 | 
						|
//   Return a list of files that this file depends on.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtGetDependentFiles(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments
 | 
						|
{
 | 
						|
    PyObject *results;
 | 
						|
    char *imageName;
 | 
						|
 | 
						|
    if (!PyArg_ParseTuple(args, "s", &imageName))
 | 
						|
        return NULL;
 | 
						|
    g_ImageNames = PyDict_New();
 | 
						|
    if (!g_ImageNames)
 | 
						|
        return NULL;
 | 
						|
    if (!BindImageEx(BIND_NO_BOUND_IMPORTS | BIND_NO_UPDATE | BIND_ALL_IMAGES,
 | 
						|
                imageName, NULL, NULL, BindStatusRoutine)) {
 | 
						|
        Py_DECREF(g_ImageNames);
 | 
						|
        PyErr_SetExcFromWindowsErrWithFilename(g_BindErrorException,
 | 
						|
                GetLastError(), imageName);
 | 
						|
        return NULL;
 | 
						|
    }
 | 
						|
    results = PyDict_Keys(g_ImageNames);
 | 
						|
    Py_DECREF(g_ImageNames);
 | 
						|
    return results;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtGetSystemDir()
 | 
						|
//   Return the Windows directory (C:\Windows for example).
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtGetSystemDir(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments (ignored)
 | 
						|
{
 | 
						|
    char dir[MAX_PATH + 1];
 | 
						|
 | 
						|
    if (GetSystemDirectory(dir, sizeof(dir)))
 | 
						|
        return PyString_FromString(dir);
 | 
						|
    PyErr_SetExcFromWindowsErr(PyExc_RuntimeError, GetLastError());
 | 
						|
    return NULL;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// ExtSetOptimizeFlag()
 | 
						|
//   Set the optimize flag as needed.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyObject *ExtSetOptimizeFlag(
 | 
						|
    PyObject *self,                     // passthrough argument
 | 
						|
    PyObject *args)                     // arguments
 | 
						|
{
 | 
						|
    if (!PyArg_ParseTuple(args, "i", &Py_OptimizeFlag))
 | 
						|
        return NULL;
 | 
						|
    Py_INCREF(Py_None);
 | 
						|
    return Py_None;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// Methods
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
static PyMethodDef g_ModuleMethods[] = {
 | 
						|
    { "SetOptimizeFlag", ExtSetOptimizeFlag, METH_VARARGS },
 | 
						|
#ifdef WIN32
 | 
						|
    { "BeginUpdateResource", ExtBeginUpdateResource, METH_VARARGS },
 | 
						|
    { "UpdateResource", ExtUpdateResource, METH_VARARGS },
 | 
						|
    { "EndUpdateResource", ExtEndUpdateResource, METH_VARARGS },
 | 
						|
    { "AddIcon", ExtAddIcon, METH_VARARGS },
 | 
						|
    { "GetDependentFiles", ExtGetDependentFiles, METH_VARARGS },
 | 
						|
    { "GetSystemDir", ExtGetSystemDir, METH_NOARGS },
 | 
						|
#endif
 | 
						|
    { NULL }
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
// initutil()
 | 
						|
//   Initialization routine for the shared libary.
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
void initutil(void)
 | 
						|
{
 | 
						|
    PyObject *module;
 | 
						|
 | 
						|
    module = Py_InitModule("cx_Freeze.util", g_ModuleMethods);
 | 
						|
    if (!module)
 | 
						|
        return;
 | 
						|
#ifdef WIN32
 | 
						|
    g_BindErrorException = PyErr_NewException("cx_Freeze.util.BindError",
 | 
						|
            NULL, NULL);
 | 
						|
    if (!g_BindErrorException)
 | 
						|
        return;
 | 
						|
    if (PyModule_AddObject(module, "BindError", g_BindErrorException) < 0)
 | 
						|
        return;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 |