<commit_before>// CA4.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

const int cbCodeId = 0x3EB;
const int btnDecompId = 0x3EC;
const int btnCancelId = 2;

const SIZE_T fbRecordSize = 0xB4;

const LPVOID fileObjectAddr = (LPVOID)0x4101d8;
const SIZE_T fileObjectSize = 0x3A4;

const bool g_dumpRecords = false;
const bool g_doPackage = false;

struct FileObject
{
    LPVOID vtable;
    DWORD d2;
    char  error[0x100];
    char  scode[0x20]; //0x108
    DWORD type; //0x128
    DWORD d3;
    DWORD d4;
    DWORD maskmode;
    DWORD markettype; // 0x138
    char  filename[0x100];
    HANDLE dataheap; // 0x23c
    LPVOID filedata;
    DWORD totalsize;
    DWORD datasize;
    HANDLE codeheap;
    LPVOID codetable; //0x250
    DWORD tablesize;
    DWORD codesize;
    DWORD d10;
    HANDLE decodeheap; //0x260
    LPVOID decodedata;
    DWORD decodesize;
    DWORD decodebufsize;
    BYTE  b270_256[0xb4]; // 0x270
    BYTE  b324_40[0x28];  // 0x324
    BYTE  b34c_80[0x50];  // 0x34c
    DWORD d12;
    DWORD d13; // 0x3a0
};

struct RecordObject
{
    DWORD dt;
    DWORD time;
    DWORD close;
    DWORD volumeLow;
    DWORD volumeHigh;
    DWORD amountLow;
    DWORD amountHigh;
    DWORD transactions;
    DWORD accVolumeLow;
    DWORD accVolumeHigh;
    DWORD accAmountLow;
    DWORD accAmountHigh;
    DWORD flag;
    DWORD prices[10];
    DWORD volumes[20];
    DWORD reservedLow;
    DWORD reservedHigh;
};

const char *_7zExe = "\"c:\\Program Files\\7-Zip\\7z.exe\" a -sdel output.zip @listfile";

void Start7z()
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, (LPSTR)_7zExe,
        NULL, NULL, FALSE, 0, NULL,
        NULL, // current directory
        &si,
        &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
    }

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

#define MAKELONGLONG(l, h) ((LONGLONG)(l & 0xffffffff) | (LONGLONG)h << 32)

void DumpRecords(BYTE *pData, int records)
{
    RecordObject* pRec = (RecordObject *)pData;
    DWORD accTxn = 0;
    LONGLONG llReserved = MAKELONGLONG(pRec[0].reservedLow, pRec[0].reservedHigh);
    for (int i = 0; i < records; i++)
    {
        DWORD txn = pRec[i].transactions;
        if (MAKELONGLONG(pRec[i].reservedLow, pRec[i].reservedHigh) != llReserved)
        {
            txn = pRec[i].transactions - accTxn;
            llReserved = MAKELONGLONG(pRec[i].reservedLow, pRec[i].reservedHigh);
            accTxn = pRec[i].transactions;
        }
        else
        {
            accTxn += pRec[i].transactions;
        }
        printf("%u %06u %u %u %I64u %I64u\n", pRec[i].dt, pRec[i].time, pRec[i].close, txn,
                MAKELONGLONG(pRec[i].amountLow, pRec[i].amountHigh),
                MAKELONGLONG(pRec[i].volumeLow, pRec[i].volumeHigh));
    }
}

int _tmain_message(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        printf("specify a file name.\n");
        return 0;
    }

    if (!argv[2][0] || argv[2][1])
    {
        printf("specify a market marker (h/s).\n");
        return 0;
    }

    char fn[0x100];
    ZeroMemory(fn, sizeof(fn));
    strcpy_s(fn, sizeof(fn), argv[1]);

    FILE *paramfp = NULL;
    int err = fopen_s(&paramfp, "dzhtest.exe.param", "rb+");
    if (!err)
    {
        fseek(paramfp, 0, FILE_BEGIN);
        fwrite(fn, sizeof(char), sizeof(fn), paramfp);
        fseek(paramfp, 0x110, FILE_BEGIN);
        if (argv[2][0] == 'h')
        {
            // sh 0x1e
            fwrite("\x1e", sizeof(char), 1, paramfp);
        }
        else if (argv[2][0] == 's')
        {
            // sz 0x25
            fwrite("\x25", sizeof(char), 1, paramfp);
        }
        fclose(paramfp);
    }
    else
    {
        printf("failed to open param file.\n");
        return -1;
    }

    GetCurrentDirectoryA(sizeof(fn), fn);
    strcat_s(fn, sizeof(fn), "\\dzhtest.exe");

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, fn,
        NULL, NULL, FALSE, 0, NULL,
        NULL, // current directory
        &si,
        &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
        return -2;
    }

    // wait for dzhtest bootstrap
    WaitForSingleObject(pi.hProcess, 3000);

    HWND target = FindWindowA(NULL, "dzhtest");
    if (!target)
    {
        // if it's still not running, give up
        printf("target window not found!\n");
        return -3;
    }
    HWND btnWnd = GetDlgItem(target, btnDecompId);
    HWND cbWnd = GetDlgItem(target, cbCodeId);

    LRESULT r = SendMessage(cbWnd, CB_GETCOUNT, 0, 0);
    char scodesel[32];
    char *fl = new char[r * (sizeof(scodesel) + 1)];
    char *flpointer = fl;

    LPVOID fp;
    FileObject fo;
    SIZE_T bytesRead;
    ReadProcessMemory(pi.hProcess, (LPCVOID)fileObjectAddr, (LPVOID)&fp, sizeof(fp), &bytesRead);
    ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

    LPVOID initial = fo.decodedata;

    for (int i = 0; i < r; i++)
    {
        LRESULT re = SendMessage(cbWnd, CB_SETCURSEL, (WPARAM)i, 0);

        re = SendMessage(cbWnd, WM_GETTEXT, (WPARAM)sizeof(scodesel), (LPARAM)scodesel);

        re = SendMessage(target, WM_COMMAND, MAKEWPARAM(btnDecompId, BN_CLICKED), (LPARAM)btnWnd);

        ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

        if (initial && fo.decodedata != initial)
        {
            printf("decoded data buffer changed! %p %p", initial, fo.decodedata);
        }

        if (!fo.decodesize)
        {
            continue;
        }

        BYTE *pData = new BYTE[fo.decodesize];
        ReadProcessMemory(pi.hProcess, fo.decodedata, pData, fo.decodesize, &bytesRead);

        size_t cnt = sprintf_s(fn, sizeof(scodesel), "%d%s", *(DWORD *)pData, scodesel);
        FILE *outfp = NULL;
        err = fopen_s(&outfp, fn, "wb");
        if (!err)
        {
            fwrite(pData, 1, bytesRead, outfp);
            fclose(outfp);

            strncpy_s(flpointer, cnt + 1, fn, cnt);
            flpointer[cnt] = '\r';
            flpointer = flpointer + cnt + 1;
        }
        else
        {
            printf("failed to open [%s].\n", fn);
        }

        if (bytesRead % fbRecordSize == 0)
        {
            if (g_dumpRecords)
            {
                DumpRecords(pData, bytesRead / fbRecordSize);
            }
        }
        else
        {
            printf("probably wrong buffer length!\n");
        }
        delete pData;
    }

    FILE *outflist = NULL;
    err = fopen_s(&outflist, "listfile", "wb");
    if (!err)
    {
        fwrite(fl, sizeof(char), flpointer - fl, outflist);
        fclose(outflist);
    }
    else
    {
        printf("failed to open [%s].\n", "listfile");
    }
    delete fl;

    SendMessage(target, WM_COMMAND, MAKEWPARAM(btnCancelId, BN_CLICKED), (LPARAM)GetDlgItem(target, btnCancelId));
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    if (g_doPackage)
    {
        Start7z();
    }

    return 0;
}

int _tmain_inject(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        return -1;
    }

    HANDLE processHandle;
    HANDLE threadHandle;
    HMODULE dllHandle;
    DWORD processID;
    FARPROC loadLibraryAddress;
    LPVOID baseAddress;

    processID = (DWORD)_ttol(argv[1]);

    processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processID);

    if(processHandle == NULL)
    {
        printf("Error unable to open process. Error code: %d", GetLastError());

        return -2;
    }

    printf("Process handle %d is ready",processID);

    dllHandle = GetModuleHandle("Kernel32");

    if(dllHandle == NULL)
    {
        printf("Error unable to allocate kernel32 handle..Error code: %d. Press any key to exit...",GetLastError());
    }

    printf("kernel32 handle is ready\n");

    loadLibraryAddress = GetProcAddress(dllHandle,"LoadLibraryA");

    if(loadLibraryAddress == NULL)
    {
        printf("Cannot get LoadLibraryA() address. Error code: %d. Press any key to exit",GetLastError());

        return -2;
    }

    printf("LoadLibrary() address is ready\n");

    baseAddress = VirtualAllocEx(
        processHandle,
        NULL,
        2048,
        MEM_COMMIT|MEM_RESERVE,
        PAGE_READWRITE);

    if(baseAddress == NULL)
    {
        printf("Error unable to alocate memmory in remote process. Error code: %d. Press any key to exit", GetLastError());

        return 0;
    }

    printf("Memory allocation succeeded\n");

    BOOL isSucceeded = WriteProcessMemory(
        processHandle,
        baseAddress,
        argv[2],
        strlen(argv[2])+1,
        NULL);

    if(isSucceeded == 0)
    {
        printf("Error unable to write memory . Error code: %d Press any key to exit...",GetLastError());

        return 0;
    }

    printf("Argument has been written\n");

    threadHandle = CreateRemoteThread(
        processHandle,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)loadLibraryAddress,
        baseAddress,
        NULL,
        0);

    if(threadHandle != NULL)
    {
        printf("Remote thread has been created\n");
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // return _tmain_inject(argc, argv);

    //FILE *fp = fopen("C:\\BaiduYunDownload\\DN.txt", "rb");
    //fseek(fp, -100L * 1024L * 1024L, FILE_END);
    //if (fp){
    //    for (int i = 0; i < 10; i++)
    //    {
    //        BYTE buf[256];
    //        fread(buf, 1, 256, fp);
    //        printf("%d", buf[0]);
    //    }
    //    fclose(fp);
    //}

    return _tmain_message(argc, argv);
}
<commit_msg>use 7z instead of zip<commit_after>// CA4.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

const int cbCodeId = 0x3EB;
const int btnDecompId = 0x3EC;
const int btnCancelId = 2;

const SIZE_T fbRecordSize = 0xB4;

const LPVOID fileObjectAddr = (LPVOID)0x4101d8;
const SIZE_T fileObjectSize = 0x3A4;

const bool g_dumpRecords = false;
const bool g_doPackage = true;
const bool g_use7z = true;

struct FileObject
{
    LPVOID vtable;
    DWORD d2;
    char  error[0x100];
    char  scode[0x20]; //0x108
    DWORD type; //0x128
    DWORD d3;
    DWORD d4;
    DWORD maskmode;
    DWORD markettype; // 0x138
    char  filename[0x100];
    HANDLE dataheap; // 0x23c
    LPVOID filedata;
    DWORD totalsize;
    DWORD datasize;
    HANDLE codeheap;
    LPVOID codetable; //0x250
    DWORD tablesize;
    DWORD codesize;
    DWORD d10;
    HANDLE decodeheap; //0x260
    LPVOID decodedata;
    DWORD decodesize;
    DWORD decodebufsize;
    BYTE  b270_256[0xb4]; // 0x270
    BYTE  b324_40[0x28];  // 0x324
    BYTE  b34c_80[0x50];  // 0x34c
    DWORD d12;
    DWORD d13; // 0x3a0
};

struct RecordObject
{
    DWORD dt;
    DWORD time;
    DWORD close;
    DWORD volumeLow;
    DWORD volumeHigh;
    DWORD amountLow;
    DWORD amountHigh;
    DWORD transactions;
    DWORD accVolumeLow;
    DWORD accVolumeHigh;
    DWORD accAmountLow;
    DWORD accAmountHigh;
    DWORD flag;
    DWORD prices[10];
    DWORD volumes[20];
    DWORD reservedLow;
    DWORD reservedHigh;
};

const char *_7zExe = "\"c:\\Program Files\\7-Zip\\7z.exe\" a -sdel output.7z @listfile";
const char *_7zipExe = "\"c:\\Program Files\\7-Zip\\7z.exe\" a -sdel output.zip @listfile";

void Start7z()
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, g_use7z ? (LPSTR)_7zExe : (LPSTR)_7zipExe,
        NULL, NULL, FALSE, 0, NULL,
        NULL, // current directory
        &si,
        &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
    }

    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

#define MAKELONGLONG(l, h) ((LONGLONG)(l & 0xffffffff) | (LONGLONG)h << 32)

void DumpRecords(BYTE *pData, int records)
{
    RecordObject* pRec = (RecordObject *)pData;
    DWORD accTxn = 0;
    LONGLONG llReserved = MAKELONGLONG(pRec[0].reservedLow, pRec[0].reservedHigh);
    for (int i = 0; i < records; i++)
    {
        DWORD txn = pRec[i].transactions;
        if (MAKELONGLONG(pRec[i].reservedLow, pRec[i].reservedHigh) != llReserved)
        {
            txn = pRec[i].transactions - accTxn;
            llReserved = MAKELONGLONG(pRec[i].reservedLow, pRec[i].reservedHigh);
            accTxn = pRec[i].transactions;
        }
        else
        {
            accTxn += pRec[i].transactions;
        }
        printf("%u %06u %u %u %I64u %I64u\n", pRec[i].dt, pRec[i].time, pRec[i].close, txn,
                MAKELONGLONG(pRec[i].amountLow, pRec[i].amountHigh),
                MAKELONGLONG(pRec[i].volumeLow, pRec[i].volumeHigh));
    }
}

int _tmain_message(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        printf("specify a file name.\n");
        return 0;
    }

    if (!argv[2][0] || argv[2][1])
    {
        printf("specify a market marker (h/s).\n");
        return 0;
    }

    char fn[0x100];
    ZeroMemory(fn, sizeof(fn));
    strcpy_s(fn, sizeof(fn), argv[1]);

    FILE *paramfp = NULL;
    int err = fopen_s(&paramfp, "dzhtest.exe.param", "rb+");
    if (!err)
    {
        fseek(paramfp, 0, FILE_BEGIN);
        fwrite(fn, sizeof(char), sizeof(fn), paramfp);
        fseek(paramfp, 0x110, FILE_BEGIN);
        if (argv[2][0] == 'h')
        {
            // sh 0x1e
            fwrite("\x1e", sizeof(char), 1, paramfp);
        }
        else if (argv[2][0] == 's')
        {
            // sz 0x25
            fwrite("\x25", sizeof(char), 1, paramfp);
        }
        fclose(paramfp);
    }
    else
    {
        printf("failed to open param file.\n");
        return -1;
    }

    GetCurrentDirectoryA(sizeof(fn), fn);
    strcat_s(fn, sizeof(fn), "\\dzhtest.exe");

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    ZeroMemory(&pi, sizeof(pi));
    if (!CreateProcessA(NULL, fn,
        NULL, NULL, FALSE, 0, NULL,
        NULL, // current directory
        &si,
        &pi))
    {
        printf("CreateProcess failed (%d)\n", GetLastError());
        return -2;
    }

    // wait for dzhtest bootstrap
    WaitForSingleObject(pi.hProcess, 1500);

    HWND target = FindWindowA(NULL, "dzhtest");
    if (!target)
    {
        // if it's still not running, give up
        printf("target window not found!\n");
        return -3;
    }
    HWND btnWnd = GetDlgItem(target, btnDecompId);
    HWND cbWnd = GetDlgItem(target, cbCodeId);

    LRESULT r = SendMessage(cbWnd, CB_GETCOUNT, 0, 0);
    char scodesel[32];
    char *fl = new char[r * (sizeof(scodesel) + 1)];
    char *flpointer = fl;

    LPVOID fp;
    FileObject fo;
    SIZE_T bytesRead;
    ReadProcessMemory(pi.hProcess, (LPCVOID)fileObjectAddr, (LPVOID)&fp, sizeof(fp), &bytesRead);
    ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

    LPVOID initial = fo.decodedata;

    for (int i = 0; i < r; i++)
    {
        LRESULT re = SendMessage(cbWnd, CB_SETCURSEL, (WPARAM)i, 0);

        re = SendMessage(cbWnd, WM_GETTEXT, (WPARAM)sizeof(scodesel), (LPARAM)scodesel);

        re = SendMessage(target, WM_COMMAND, MAKEWPARAM(btnDecompId, BN_CLICKED), (LPARAM)btnWnd);

        ReadProcessMemory(pi.hProcess, fp, &fo, fileObjectSize, &bytesRead);

        if (initial && fo.decodedata != initial)
        {
            printf("decoded data buffer changed! %p %p", initial, fo.decodedata);
        }

        if (!fo.decodesize)
        {
            continue;
        }

        BYTE *pData = new BYTE[fo.decodesize];
        ReadProcessMemory(pi.hProcess, fo.decodedata, pData, fo.decodesize, &bytesRead);

        size_t cnt = sprintf_s(fn, sizeof(scodesel), "%d%s", *(DWORD *)pData, scodesel);
        FILE *outfp = NULL;
        err = fopen_s(&outfp, fn, "wb");
        if (!err)
        {
            fwrite(pData, 1, bytesRead, outfp);
            fclose(outfp);

            strncpy_s(flpointer, cnt + 1, fn, cnt);
            flpointer[cnt] = '\r';
            flpointer = flpointer + cnt + 1;
        }
        else
        {
            printf("failed to open [%s].\n", fn);
        }

        if (bytesRead % fbRecordSize == 0)
        {
            if (g_dumpRecords)
            {
                DumpRecords(pData, bytesRead / fbRecordSize);
            }
        }
        else
        {
            printf("probably wrong buffer length!\n");
        }
        delete pData;
    }

    FILE *outflist = NULL;
    err = fopen_s(&outflist, "listfile", "wb");
    if (!err)
    {
        fwrite(fl, sizeof(char), flpointer - fl, outflist);
        fclose(outflist);
    }
    else
    {
        printf("failed to open [%s].\n", "listfile");
    }
    delete fl;

    SendMessage(target, WM_COMMAND, MAKEWPARAM(btnCancelId, BN_CLICKED), (LPARAM)GetDlgItem(target, btnCancelId));
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    if (g_doPackage)
    {
        Start7z();
    }

    return 0;
}

int _tmain_inject(int argc, _TCHAR* argv[])
{
    if (argc != 3)
    {
        return -1;
    }

    HANDLE processHandle;
    HANDLE threadHandle;
    HMODULE dllHandle;
    DWORD processID;
    FARPROC loadLibraryAddress;
    LPVOID baseAddress;

    processID = (DWORD)_ttol(argv[1]);

    processHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processID);

    if(processHandle == NULL)
    {
        printf("Error unable to open process. Error code: %d", GetLastError());

        return -2;
    }

    printf("Process handle %d is ready",processID);

    dllHandle = GetModuleHandle("Kernel32");

    if(dllHandle == NULL)
    {
        printf("Error unable to allocate kernel32 handle..Error code: %d. Press any key to exit...",GetLastError());
    }

    printf("kernel32 handle is ready\n");

    loadLibraryAddress = GetProcAddress(dllHandle,"LoadLibraryA");

    if(loadLibraryAddress == NULL)
    {
        printf("Cannot get LoadLibraryA() address. Error code: %d. Press any key to exit",GetLastError());

        return -2;
    }

    printf("LoadLibrary() address is ready\n");

    baseAddress = VirtualAllocEx(
        processHandle,
        NULL,
        2048,
        MEM_COMMIT|MEM_RESERVE,
        PAGE_READWRITE);

    if(baseAddress == NULL)
    {
        printf("Error unable to alocate memmory in remote process. Error code: %d. Press any key to exit", GetLastError());

        return 0;
    }

    printf("Memory allocation succeeded\n");

    BOOL isSucceeded = WriteProcessMemory(
        processHandle,
        baseAddress,
        argv[2],
        strlen(argv[2])+1,
        NULL);

    if(isSucceeded == 0)
    {
        printf("Error unable to write memory . Error code: %d Press any key to exit...",GetLastError());

        return 0;
    }

    printf("Argument has been written\n");

    threadHandle = CreateRemoteThread(
        processHandle,
        NULL,
        0,
        (LPTHREAD_START_ROUTINE)loadLibraryAddress,
        baseAddress,
        NULL,
        0);

    if(threadHandle != NULL)
    {
        printf("Remote thread has been created\n");
    }

    return 0;
}

int _tmain(int argc, _TCHAR* argv[])
{
    // return _tmain_inject(argc, argv);

    //FILE *fp = fopen("C:\\BaiduYunDownload\\DN.txt", "rb");
    //fseek(fp, -100L * 1024L * 1024L, FILE_END);
    //if (fp){
    //    for (int i = 0; i < 10; i++)
    //    {
    //        BYTE buf[256];
    //        fread(buf, 1, 256, fp);
    //        printf("%d", buf[0]);
    //    }
    //    fclose(fp);
    //}

    return _tmain_message(argc, argv);
}
<|endoftext|>


<commit_before>#include <Python.h>
#include <structmember.h>

#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-global.h>
#include <poppler/cpp/poppler-page.h>

#include <string>
#include <vector>

static PyObject* PdftotextError;

typedef struct {
    PyObject_HEAD
    int page_count;
    PyObject* data;
    poppler::document* doc;
} PDF;

static PyMemberDef PDF_members[] = {
    {
        (char*)"page_count",
        T_INT,
        offsetof(PDF, page_count),
        READONLY,
        (char*)"Page count.",
    },
    {NULL},  // Sentinel
};

static void PDF_clear(PDF* self) {
    self->page_count = 0;
    delete self->doc;
    self->doc = NULL;
    Py_CLEAR(self->data);
}

static int PDF_load_data(PDF* self, PyObject* args, PyObject* kwds) {
    PyObject* arg;
    static char* kwlist[] = {(char*)"pdf_file", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) {
        return -1;
    }
    self->data = PyObject_CallMethod(arg, "read", NULL);
    if (self->data == NULL) {
        return -1;
    }
    return 0;
}

static int PDF_create_doc(PDF* self) {
    Py_ssize_t len;
    char* buf;

    if (PyBytes_AsStringAndSize(self->data, &buf, &len) < 0) {
        Py_CLEAR(self->data);
        return -1;
    }
    self->doc = poppler::document::load_from_raw_data(buf, len);
    if (self->doc == NULL) {
        PyErr_SetString(PdftotextError, "TODO: useful error message");
        Py_CLEAR(self->data);
        return -1;
    }
    return 0;
}

static int PDF_init(PDF* self, PyObject* args, PyObject* kwds) {
    PDF_clear(self);
    if (PDF_load_data(self, args, kwds) < 0) {
        return -1;
    }
    if (PDF_create_doc(self) < 0) {
        return -1;
    }
    self->page_count = self->doc->pages();
    return 0;
}

static void PDF_dealloc(PDF* self) {
    PDF_clear(self);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* PDF_read(PDF* self, PyObject* args, PyObject* kwds) {
    int page_number;
    static char* kwlist[] = {(char*)"page_number", NULL};
    const poppler::page* page;
    std::vector<char> page_utf8;

    if (self->doc == NULL) {
        return PyErr_Format(PdftotextError, "No document to read");
    }
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &page_number)) {
        return NULL;
    }
    if (page_number < 1 || page_number > self->page_count) {
        return PyErr_Format(PdftotextError, "Invalid page number");
    }
    page = self->doc->create_page(page_number - 1);
    if (page == NULL) {
        return PyErr_Format(PdftotextError, "Poppler error creating page");
    }
    page_utf8 = page->text().to_utf8();
    delete page;
    return PyUnicode_DecodeUTF8(page_utf8.data(), page_utf8.size(), NULL);
}

static PyObject* PDF_read_all(PyObject* self, PyObject*) {
    return PyUnicode_FromString("TODO: read the whole document");
}

static PyMethodDef PDF_methods[] = {
    {
        "read",
        (PyCFunction)PDF_read,
        METH_VARARGS | METH_KEYWORDS,
        "Extract text from the given page number.",
    },
    {
        "read_all",
        PDF_read_all,
        METH_NOARGS,
        "Extract text from the entire document.",
    },
    {NULL},  // Sentinel
};

static PyTypeObject pdftotext_PDFType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "pdftotext.PDF",                           // tp_name
    sizeof(PDF),                               // tp_basicsize
    0,                                         // tp_itemsize
    (destructor)PDF_dealloc,                   // tp_dealloc
    0,                                         // tp_print
    0,                                         // tp_getattr
    0,                                         // tp_setattr
    0,                                         // tp_reserved
    0,                                         // tp_repr
    0,                                         // tp_as_number
    0,                                         // tp_as_sequence
    0,                                         // tp_as_mapping
    0,                                         // tp_hash
    0,                                         // tp_call
    0,                                         // tp_str
    0,                                         // tp_getattro
    0,                                         // tp_setattro
    0,                                         // tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
    "TODO: docstring for PDF.",                // tp_doc
    0,                                         // tp_traverse
    0,                                         // tp_clear
    0,                                         // tp_richcompare
    0,                                         // tp_weaklistoffset
    0,                                         // tp_iter
    0,                                         // tp_iternext
    PDF_methods,                               // tp_methods
    PDF_members,                               // tp_members
    0,                                         // tp_getset
    0,                                         // tp_base
    0,                                         // tp_dict
    0,                                         // tp_descr_get
    0,                                         // tp_descr_set
    0,                                         // tp_dictoffset
    (initproc)PDF_init,                        // tp_init
};

static PyModuleDef pdftotextmodule = {
    PyModuleDef_HEAD_INIT,
    "pdftotext",
    "Simple PDF text extraction.",
};

PyMODINIT_FUNC PyInit_pdftotext() {
    PyObject* module;

    pdftotext_PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&pdftotext_PDFType) < 0) {
        return NULL;
    }

    module = PyModule_Create(&pdftotextmodule);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&pdftotext_PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&pdftotext_PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        "pdftotext.Error", "TODO: docstring for Error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    return module;
}
<commit_msg>Improve documentation<commit_after>#include <Python.h>
#include <structmember.h>

#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-global.h>
#include <poppler/cpp/poppler-page.h>

#include <string>
#include <vector>

static PyObject* PdftotextError;

typedef struct {
    PyObject_HEAD
    int page_count;
    PyObject* data;
    poppler::document* doc;
} PDF;

static PyMemberDef PDF_members[] = {
    {
        (char*)"page_count",
        T_INT,
        offsetof(PDF, page_count),
        READONLY,
        (char*)"Page count.",
    },
    {NULL},  // Sentinel
};

static void PDF_clear(PDF* self) {
    self->page_count = 0;
    delete self->doc;
    self->doc = NULL;
    Py_CLEAR(self->data);
}

static int PDF_load_data(PDF* self, PyObject* args, PyObject* kwds) {
    PyObject* arg;
    static char* kwlist[] = {(char*)"pdf_file", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &arg)) {
        return -1;
    }
    self->data = PyObject_CallMethod(arg, "read", NULL);
    if (self->data == NULL) {
        return -1;
    }
    return 0;
}

static int PDF_create_doc(PDF* self) {
    Py_ssize_t len;
    char* buf;

    if (PyBytes_AsStringAndSize(self->data, &buf, &len) < 0) {
        Py_CLEAR(self->data);
        return -1;
    }
    self->doc = poppler::document::load_from_raw_data(buf, len);
    if (self->doc == NULL) {
        PyErr_SetString(PdftotextError, "Poppler error creating document");
        Py_CLEAR(self->data);
        return -1;
    }
    return 0;
}

static int PDF_init(PDF* self, PyObject* args, PyObject* kwds) {
    PDF_clear(self);
    if (PDF_load_data(self, args, kwds) < 0) {
        return -1;
    }
    if (PDF_create_doc(self) < 0) {
        return -1;
    }
    self->page_count = self->doc->pages();
    return 0;
}

static void PDF_dealloc(PDF* self) {
    PDF_clear(self);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* PDF_read(PDF* self, PyObject* args, PyObject* kwds) {
    int page_number;
    static char* kwlist[] = {(char*)"page_number", NULL};
    const poppler::page* page;
    std::vector<char> page_utf8;

    if (self->doc == NULL) {
        return PyErr_Format(PdftotextError, "No document to read");
    }
    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &page_number)) {
        return NULL;
    }
    if (page_number < 1 || page_number > self->page_count) {
        return PyErr_Format(PdftotextError, "Invalid page number: %i", page_number);
    }
    page = self->doc->create_page(page_number - 1);
    if (page == NULL) {
        return PyErr_Format(PdftotextError, "Poppler error creating page");
    }
    page_utf8 = page->text().to_utf8();
    delete page;
    return PyUnicode_DecodeUTF8(page_utf8.data(), page_utf8.size(), NULL);
}

static PyObject* PDF_read_all(PyObject* self, PyObject*) {
    return PyUnicode_FromString("TODO: read the whole document");
}

static PyMethodDef PDF_methods[] = {
    {
        "read",
        (PyCFunction)PDF_read,
        METH_VARARGS | METH_KEYWORDS,
        "Extract text from the given page number.",
    },
    {
        "read_all",
        PDF_read_all,
        METH_NOARGS,
        "Extract text from the entire document.",
    },
    {NULL},  // Sentinel
};

static PyTypeObject pdftotext_PDFType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "pdftotext.PDF",                           // tp_name
    sizeof(PDF),                               // tp_basicsize
    0,                                         // tp_itemsize
    (destructor)PDF_dealloc,                   // tp_dealloc
    0,                                         // tp_print
    0,                                         // tp_getattr
    0,                                         // tp_setattr
    0,                                         // tp_reserved
    0,                                         // tp_repr
    0,                                         // tp_as_number
    0,                                         // tp_as_sequence
    0,                                         // tp_as_mapping
    0,                                         // tp_hash
    0,                                         // tp_call
    0,                                         // tp_str
    0,                                         // tp_getattro
    0,                                         // tp_setattro
    0,                                         // tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,  // tp_flags
    "PDF document.",                           // tp_doc
    0,                                         // tp_traverse
    0,                                         // tp_clear
    0,                                         // tp_richcompare
    0,                                         // tp_weaklistoffset
    0,                                         // tp_iter
    0,                                         // tp_iternext
    PDF_methods,                               // tp_methods
    PDF_members,                               // tp_members
    0,                                         // tp_getset
    0,                                         // tp_base
    0,                                         // tp_dict
    0,                                         // tp_descr_get
    0,                                         // tp_descr_set
    0,                                         // tp_dictoffset
    (initproc)PDF_init,                        // tp_init
};

static PyModuleDef pdftotextmodule = {
    PyModuleDef_HEAD_INIT,
    "pdftotext",
    "Simple PDF text extraction.",
};

PyMODINIT_FUNC PyInit_pdftotext() {
    PyObject* module;

    pdftotext_PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&pdftotext_PDFType) < 0) {
        return NULL;
    }

    module = PyModule_Create(&pdftotextmodule);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&pdftotext_PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&pdftotext_PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        "pdftotext.Error", "PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    return module;
}
<|endoftext|>


<commit_before>/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DBusObjectManager.h"
#include "DBusDaemonProxy.h"
#include "DBusStubAdapter.h"
#include "DBusOutputStream.h"
#include "DBusUtils.h"

#include <dbus/dbus-protocol.h>

#include <cassert>
#include <sstream>

#include <unordered_set>

namespace CommonAPI {
namespace DBus {

DBusObjectManager::DBusObjectManager(const std::shared_ptr<DBusProxyConnection>& dbusConnection):
        dbusConnection_(dbusConnection) {

    if (!dbusConnection->isObjectPathMessageHandlerSet()) {
        dbusConnection->setObjectPathMessageHandler(
                        std::bind(&DBusObjectManager::handleMessage, this, std::placeholders::_1));
    }
    dbusConnection->registerObjectPath("/");
}

DBusObjectManager::~DBusObjectManager() {
    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();
    if (dbusConnection) {
        dbusConnection->unregisterObjectPath("/");
        dbusConnection->setObjectPathMessageHandler(DBusProxyConnection::DBusObjectPathMessageHandler());
    }
}

DBusInterfaceHandlerToken DBusObjectManager::registerDBusStubAdapter(const std::string& objectPath,
                                                                     const std::string& interfaceName,
                                                                     DBusStubAdapter* dbusStubAdapter) {
    DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName);

    objectPathLock_.lock();
    bool noSuchHandlerRegistered = dbusRegisteredObjectsTable_.find(handlerPath) == dbusRegisteredObjectsTable_.end();

    assert(noSuchHandlerRegistered);

    dbusRegisteredObjectsTable_.insert({handlerPath, dbusStubAdapter});
    objectPathLock_.unlock();

    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();
    if (dbusConnection) {
        dbusConnection->registerObjectPath(objectPath);
    }

    return handlerPath;
}

void DBusObjectManager::unregisterDBusStubAdapter(const DBusInterfaceHandlerToken& dbusInterfaceHandlerToken) {
    objectPathLock_.lock();
    const std::string& objectPath = dbusInterfaceHandlerToken.first;

    std::shared_ptr<DBusProxyConnection> lockedConnection = dbusConnection_.lock();
    if (lockedConnection) {
        lockedConnection->unregisterObjectPath(objectPath);
    }

    dbusRegisteredObjectsTable_.erase(dbusInterfaceHandlerToken);
    objectPathLock_.unlock();
}

bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) {
    const char* objectPath = dbusMessage.getObjectPath();
    const char* interfaceName = dbusMessage.getInterfaceName();

    assert(objectPath);
    assert(interfaceName);

    DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName);

    objectPathLock_.lock();
    auto handlerIterator = dbusRegisteredObjectsTable_.find(handlerPath);
    const bool foundDBusInterfaceHandler = handlerIterator != dbusRegisteredObjectsTable_.end();
    bool dbusMessageHandled = false;

    if (foundDBusInterfaceHandler) {
        DBusStubAdapter* dbusStubAdapter = handlerIterator->second;
        dbusMessageHandled = dbusStubAdapter->onInterfaceDBusMessage(dbusMessage);
    } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.Introspectable")) {
        dbusMessageHandled = onIntrospectableInterfaceDBusMessage(dbusMessage);
    } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.ObjectManager")) {
        dbusMessageHandled = onObjectManagerInterfaceDBusMessage(dbusMessage);
    }
    objectPathLock_.unlock();

    return dbusMessageHandled;
}

bool DBusObjectManager::onObjectManagerInterfaceDBusMessage(const DBusMessage& dbusMessage) {
    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();

    if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("GetManagedObjects")) {
        return false;
    }

    DBusDaemonProxy::DBusObjectToInterfaceDict ObjectPathsInterfacesAndPropertiesDict;

    objectPathLock_.lock();
    auto registeredObjectsIterator = dbusRegisteredObjectsTable_.begin();

    while(registeredObjectsIterator != dbusRegisteredObjectsTable_.end()) {
        DBusInterfaceHandlerPath handlerPath = registeredObjectsIterator->first;
        auto foundDictEntry = ObjectPathsInterfacesAndPropertiesDict.find(handlerPath.first);

        if (foundDictEntry == ObjectPathsInterfacesAndPropertiesDict.end()) {
            ObjectPathsInterfacesAndPropertiesDict.insert( { handlerPath.first, { { handlerPath.second, {} } } } );
        } else {
            foundDictEntry->second.insert( {handlerPath.second, {} } );
        }

        ++registeredObjectsIterator;
    }
    objectPathLock_.unlock();

    const char* getManagedObjectsDBusSignature = "a{oa{sa{sv}}}";
    DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(getManagedObjectsDBusSignature);
    DBusOutputStream outStream(dbusMessageReply);

    outStream << ObjectPathsInterfacesAndPropertiesDict;
    outStream.flush();

    return dbusConnection->sendDBusMessage(dbusMessageReply);
}

bool DBusObjectManager::onIntrospectableInterfaceDBusMessage(const DBusMessage& dbusMessage) {
    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();

    if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("Introspect")) {
        return false;
    }

    bool foundRegisteredObjects = false;
    std::stringstream xmlData(std::ios_base::out);

    xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\""
                    DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
                    "<node name=\"" << dbusMessage.getObjectPath() << "\">\n"
                        "<interface name=\"org.freedesktop.DBus.Introspectable\">\n"
                            "<method name=\"Introspect\">\n"
                                "<arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n"
                            "</method>\n"
                        "</interface>\n";

    std::unordered_set<std::string> nodeSet;
    for (auto& registeredObjectsIterator : dbusRegisteredObjectsTable_) {
        const DBusInterfaceHandlerPath& handlerPath = registeredObjectsIterator.first;
        const std::string& dbusObjectPath = handlerPath.first;
        const std::string& dbusInterfaceName = handlerPath.second;
        DBusStubAdapter* dbusStubAdapter = registeredObjectsIterator.second;

        if (dbusMessage.hasObjectPath(dbusObjectPath)) {
            foundRegisteredObjects = true;

            xmlData << "<interface name=\"" << dbusInterfaceName << "\">\n"
                            << dbusStubAdapter->getMethodsDBusIntrospectionXmlData() << "\n"
                            "</interface>\n";
        } else {
            std::vector<std::string> elems = CommonAPI::DBus::split(dbusObjectPath, '/');
            if (dbusMessage.hasObjectPath("/") && elems.size() > 1) {
                if (nodeSet.find(elems[1]) == nodeSet.end()) {
                    if (nodeSet.size() == 0) {
                        xmlData.str("");
                        xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\""
                        DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
                        "<node>\n";
                    }
                    xmlData << "    <node name=\"" << elems[1] << "\"/>\n";
                    nodeSet.insert(elems[1]);
                    foundRegisteredObjects = true;
                }
            } else {
                for (int i = 1; i < elems.size() - 1; i++) {
                    std::string build;
                    for (int j = 1; j <= i; j++) {
                        build = build + "/" + elems[j];
                        if (dbusMessage.hasObjectPath(dbusObjectPath)) {
                            if (nodeSet.find(elems[j + 1]) == nodeSet.end()) {
                                if (nodeSet.size() == 0) {
                                    xmlData.str("");
                                    xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\""
                                            DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
                                            "<node>\n";
                                }
                                xmlData << "    <node name=\"" << elems[j + 1] << "\"/>\n";
                                nodeSet.insert(elems[j + 1]);
                                foundRegisteredObjects = true;
                            }
                            break;
                        }
                    }
                }
            }
        }
    }

    if (foundRegisteredObjects) {
        DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("s");
        DBusOutputStream dbusOutputStream(dbusMessageReply);

        xmlData << "</node>"
                        "";

        dbusOutputStream << xmlData.str();
        dbusOutputStream.flush();

        return dbusConnection->sendDBusMessage(dbusMessageReply);
    }

    return false;
}

} // namespace DBus
} // namespace CommonAPI
<commit_msg>object manager: add explicit map instantiation<commit_after>/* Copyright (C) 2013 BMW Group
 * Author: Manfred Bathelt (manfred.bathelt@bmw.de)
 * Author: Juergen Gehring (juergen.gehring@bmw.de)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "DBusObjectManager.h"
#include "DBusDaemonProxy.h"
#include "DBusStubAdapter.h"
#include "DBusOutputStream.h"
#include "DBusUtils.h"

#include <dbus/dbus-protocol.h>

#include <cassert>
#include <sstream>

#include <unordered_set>

namespace CommonAPI {
namespace DBus {

DBusObjectManager::DBusObjectManager(const std::shared_ptr<DBusProxyConnection>& dbusConnection):
        dbusConnection_(dbusConnection) {

    if (!dbusConnection->isObjectPathMessageHandlerSet()) {
        dbusConnection->setObjectPathMessageHandler(
                        std::bind(&DBusObjectManager::handleMessage, this, std::placeholders::_1));
    }
    dbusConnection->registerObjectPath("/");
}

DBusObjectManager::~DBusObjectManager() {
    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();
    if (dbusConnection) {
        dbusConnection->unregisterObjectPath("/");
        dbusConnection->setObjectPathMessageHandler(DBusProxyConnection::DBusObjectPathMessageHandler());
    }
}

DBusInterfaceHandlerToken DBusObjectManager::registerDBusStubAdapter(const std::string& objectPath,
                                                                     const std::string& interfaceName,
                                                                     DBusStubAdapter* dbusStubAdapter) {
    DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName);

    objectPathLock_.lock();
    bool noSuchHandlerRegistered = dbusRegisteredObjectsTable_.find(handlerPath) == dbusRegisteredObjectsTable_.end();

    assert(noSuchHandlerRegistered);

    dbusRegisteredObjectsTable_.insert({handlerPath, dbusStubAdapter});
    objectPathLock_.unlock();

    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();
    if (dbusConnection) {
        dbusConnection->registerObjectPath(objectPath);
    }

    return handlerPath;
}

void DBusObjectManager::unregisterDBusStubAdapter(const DBusInterfaceHandlerToken& dbusInterfaceHandlerToken) {
    objectPathLock_.lock();
    const std::string& objectPath = dbusInterfaceHandlerToken.first;

    std::shared_ptr<DBusProxyConnection> lockedConnection = dbusConnection_.lock();
    if (lockedConnection) {
        lockedConnection->unregisterObjectPath(objectPath);
    }

    dbusRegisteredObjectsTable_.erase(dbusInterfaceHandlerToken);
    objectPathLock_.unlock();
}

bool DBusObjectManager::handleMessage(const DBusMessage& dbusMessage) {
    const char* objectPath = dbusMessage.getObjectPath();
    const char* interfaceName = dbusMessage.getInterfaceName();

    assert(objectPath);
    assert(interfaceName);

    DBusInterfaceHandlerPath handlerPath(objectPath, interfaceName);

    objectPathLock_.lock();
    auto handlerIterator = dbusRegisteredObjectsTable_.find(handlerPath);
    const bool foundDBusInterfaceHandler = handlerIterator != dbusRegisteredObjectsTable_.end();
    bool dbusMessageHandled = false;

    if (foundDBusInterfaceHandler) {
        DBusStubAdapter* dbusStubAdapter = handlerIterator->second;
        dbusMessageHandled = dbusStubAdapter->onInterfaceDBusMessage(dbusMessage);
    } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.Introspectable")) {
        dbusMessageHandled = onIntrospectableInterfaceDBusMessage(dbusMessage);
    } else if (dbusMessage.hasInterfaceName("org.freedesktop.DBus.ObjectManager")) {
        dbusMessageHandled = onObjectManagerInterfaceDBusMessage(dbusMessage);
    }
    objectPathLock_.unlock();

    return dbusMessageHandled;
}

bool DBusObjectManager::onObjectManagerInterfaceDBusMessage(const DBusMessage& dbusMessage) {
    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();

    if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("GetManagedObjects")) {
        return false;
    }

    DBusDaemonProxy::DBusObjectToInterfaceDict resultObjectPathsInterfacesAndPropertiesDict;

    objectPathLock_.lock();
    auto registeredObjectsIterator = dbusRegisteredObjectsTable_.begin();

    while(registeredObjectsIterator != dbusRegisteredObjectsTable_.end()) {
        DBusInterfaceHandlerPath handlerPath = registeredObjectsIterator->first;
        auto foundDictEntry = resultObjectPathsInterfacesAndPropertiesDict.find(handlerPath.first);

        if (foundDictEntry == resultObjectPathsInterfacesAndPropertiesDict.end()) {
            resultObjectPathsInterfacesAndPropertiesDict.insert(
            		{ handlerPath.first, { { handlerPath.second, DBusDaemonProxy::PropertyDictStub() } } } );
        } else {
            foundDictEntry->second.insert( {handlerPath.second, DBusDaemonProxy::PropertyDictStub() } );
        }

        ++registeredObjectsIterator;
    }
    objectPathLock_.unlock();

    const char* getManagedObjectsDBusSignature = "a{oa{sa{sv}}}";
    DBusMessage dbusMessageReply = dbusMessage.createMethodReturn(getManagedObjectsDBusSignature);
    DBusOutputStream outStream(dbusMessageReply);

    outStream << resultObjectPathsInterfacesAndPropertiesDict;
    outStream.flush();

    return dbusConnection->sendDBusMessage(dbusMessageReply);
}

bool DBusObjectManager::onIntrospectableInterfaceDBusMessage(const DBusMessage& dbusMessage) {
    std::shared_ptr<DBusProxyConnection> dbusConnection = dbusConnection_.lock();

    if (!dbusConnection || !dbusMessage.isMethodCallType() || !dbusMessage.hasMemberName("Introspect")) {
        return false;
    }

    bool foundRegisteredObjects = false;
    std::stringstream xmlData(std::ios_base::out);

    xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\""
                    DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
                    "<node name=\"" << dbusMessage.getObjectPath() << "\">\n"
                        "<interface name=\"org.freedesktop.DBus.Introspectable\">\n"
                            "<method name=\"Introspect\">\n"
                                "<arg type=\"s\" name=\"xml_data\" direction=\"out\"/>\n"
                            "</method>\n"
                        "</interface>\n";

    std::unordered_set<std::string> nodeSet;
    for (auto& registeredObjectsIterator : dbusRegisteredObjectsTable_) {
        const DBusInterfaceHandlerPath& handlerPath = registeredObjectsIterator.first;
        const std::string& dbusObjectPath = handlerPath.first;
        const std::string& dbusInterfaceName = handlerPath.second;
        DBusStubAdapter* dbusStubAdapter = registeredObjectsIterator.second;

        if (dbusMessage.hasObjectPath(dbusObjectPath)) {
            foundRegisteredObjects = true;

            xmlData << "<interface name=\"" << dbusInterfaceName << "\">\n"
                            << dbusStubAdapter->getMethodsDBusIntrospectionXmlData() << "\n"
                            "</interface>\n";
        } else {
            std::vector<std::string> elems = CommonAPI::DBus::split(dbusObjectPath, '/');
            if (dbusMessage.hasObjectPath("/") && elems.size() > 1) {
                if (nodeSet.find(elems[1]) == nodeSet.end()) {
                    if (nodeSet.size() == 0) {
                        xmlData.str("");
                        xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\""
                        DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
                        "<node>\n";
                    }
                    xmlData << "    <node name=\"" << elems[1] << "\"/>\n";
                    nodeSet.insert(elems[1]);
                    foundRegisteredObjects = true;
                }
            } else {
                for (int i = 1; i < elems.size() - 1; i++) {
                    std::string build;
                    for (int j = 1; j <= i; j++) {
                        build = build + "/" + elems[j];
                        if (dbusMessage.hasObjectPath(dbusObjectPath)) {
                            if (nodeSet.find(elems[j + 1]) == nodeSet.end()) {
                                if (nodeSet.size() == 0) {
                                    xmlData.str("");
                                    xmlData << "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\""
                                            DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER"\">\n"
                                            "<node>\n";
                                }
                                xmlData << "    <node name=\"" << elems[j + 1] << "\"/>\n";
                                nodeSet.insert(elems[j + 1]);
                                foundRegisteredObjects = true;
                            }
                            break;
                        }
                    }
                }
            }
        }
    }

    if (foundRegisteredObjects) {
        DBusMessage dbusMessageReply = dbusMessage.createMethodReturn("s");
        DBusOutputStream dbusOutputStream(dbusMessageReply);

        xmlData << "</node>"
                        "";

        dbusOutputStream << xmlData.str();
        dbusOutputStream.flush();

        return dbusConnection->sendDBusMessage(dbusMessageReply);
    }

    return false;
}

} // namespace DBus
} // namespace CommonAPI
<|endoftext|>


<commit_before>// ========================================================================== //
// This file is part of DO-CV, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2014 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#ifndef DO_SARA_GEOMETRY_POLYGON_HPP
#define DO_SARA_GEOMETRY_POLYGON_HPP

#include <vector>

#include <DO/Sara/Geometry/Tools/Projective.hpp>

namespace DO { namespace Sara {

  template <int N>
  class SmallPolygon
  {
  public:
    typedef Point2d Point;
    typedef Vector3d Line;
    typedef Point * iterator;
    typedef const Point * const_iterator;

    //! Constructors
    inline SmallPolygon()
    {
    }

    inline SmallPolygon(const Point *vertices)
    {
      copy_vertices(vertices);
    }

    inline SmallPolygon(const SmallPolygon& other)
    {
      copy(other);
    }

    //! Assignment operator
    inline SmallPolygon& operator=(const SmallPolygon& other)
    {
      copy(other);
      return *this;
    }

    //! Mutable point accessors.
    inline Point& operator[](int i)
    {
      return v_[i];
    }

    //! Immutable point accessor
    inline const Point& operator[](int i) const
    {
      return v_[i];
    }

    //! iterators
    inline Point * begin()
    {
      return v_;
    }

    inline Point * end()
    {
      return v_+N;
    }

    inline const Point * begin() const
    {
      return v_;
    }

    inline const Point * end() const
    {
      return v_+N;
    }

    inline int num_vertices() const
    {
      return N;
    }

  protected:
    inline void copy_vertices(const Point2d *vertices)
    {
      std::copy(vertices, vertices+N, v_);
    }

    inline void copy(const SmallPolygon& other)
    {
      copy_vertices(other.v_);
    }

  protected:
    Point v_[N];
  };

  //! I/O ostream operator.
  template <int N>
  std::ostream& operator<<(std::ostream& os, const SmallPolygon<N>& poly)
  {
    typename SmallPolygon<N>::const_iterator p = poly.begin();
    for ( ; p != poly.end(); ++p)
      os << "[ " << p->transpose() << " ] ";
    return os;
  }

  //! Utility functions.
  template <int N>
  double signed_area(const SmallPolygon<N>& polygon)
  {
    // Computation derived from Green's formula
    double A = 0.;
    for (int i1 = N-1, i2 = 0; i2 < N; i1=i2++)
    {
      Matrix2d M;
      M.col(0) = polygon[i1];
      M.col(1) = polygon[i2];
      A += M.determinant();
    }
    return 0.5*A;
  }

  template <int N>
  inline double area(const SmallPolygon<N>& polygon)
  {
    return std::abs(signed_area(polygon));
  }

  //! Even-odd rule implementation.
  template <int N>
  bool inside(const Point2d& p, const SmallPolygon<N>& poly)
  {
    bool c = false;
    for (int i = 0, j = N-1; i < N; j = i++)
    {
      if ( (poly[i].y() > p.y()) != (poly[j].y() > p.y()) &&
           (p.x() <   (poly[j].x()-poly[i].x()) * (p.y()-poly[i].y())
                    / (poly[j].y()-poly[i].y()) + poly[i].x()) )
        c = !c;
    }
    return c;
  }

  template <int N>
  bool degenerate(const SmallPolygon<N>& poly,
                  double eps = std::numeric_limits<double>::epsilon())
  {
    return area(poly) < eps;
  }

  double area(const std::vector<Point2d>& polygon);

} /* namespace Sara */
} /* namespace DO */

#endif /* DO_SARA_GEOMETRY_POLYGON_HPP */
<commit_msg>ENH: add equality comparison operator for the `Quad` class.<commit_after>// ========================================================================== //
// This file is part of DO-CV, a basic set of libraries in C++ for computer
// vision.
//
// Copyright (C) 2014 David Ok <david.ok8@gmail.com>
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License v. 2.0. If a copy of the MPL was not distributed with this file,
// you can obtain one at http://mozilla.org/MPL/2.0/.
// ========================================================================== //

#ifndef DO_SARA_GEOMETRY_POLYGON_HPP
#define DO_SARA_GEOMETRY_POLYGON_HPP

#include <vector>

#include <DO/Sara/Geometry/Tools/Projective.hpp>

namespace DO { namespace Sara {

  template <std::size_t N>
  class SmallPolygon
  {
    using self_type = SmallPolygon;

  public:
    using point_type = Point2d;
    using line_type = Vector3d;
    using iterator =  point_type *;
    using const_iterator = const point_type *;

    //! @{
    //! Constructors
    SmallPolygon() = default;

    inline SmallPolygon(const point_type *vertices)
    {
      copy_vertices(vertices);
    }

    inline SmallPolygon(const SmallPolygon& other)
    {
      copy(other);
    }
    //! @}

    //! \brief Assignment operator
    inline SmallPolygon& operator=(const SmallPolygon& other)
    {
      copy(other);
      return *this;
    }

    //! @{
    //! \brief Point accessors.
    inline point_type& operator[](int i)
    {
      return _v[i];
    }

    inline const point_type& operator[](int i) const
    {
      return _v[i];
    }
    //! @}

    //! @{
    //! \brief iterators.
    inline point_type * begin()
    {
      return _v;
    }

    inline point_type * end()
    {
      return _v+N;
    }

    inline const point_type * begin() const
    {
      return _v;
    }

    inline const point_type * end() const
    {
      return _v+N;
    }
    //! @}

    //! \brief return the number of vertices.
    inline std::size_t num_vertices() const
    {
      return N;
    }

    //! \brief Equality comparison.
    inline bool operator==(const self_type& other) const
    {
      return std::equal(_v, _v + N, other._v);
    }

    //! \brief Inequality comparison.
    inline bool operator!=(const self_type& other) const
    {
      return !this->operator==(other);
    }

  protected:
    inline void copy_vertices(const_iterator vertices)
    {
      std::copy(vertices, vertices+N, _v);
    }

    inline void copy(const self_type& other)
    {
      copy_vertices(other._v);
    }

  protected:
    point_type _v[N];
  };

  //! I/O ostream operator.
  template <int N>
  std::ostream& operator<<(std::ostream& os, const SmallPolygon<N>& poly)
  {
    typename SmallPolygon<N>::const_iterator p = poly.begin();
    for ( ; p != poly.end(); ++p)
      os << "[ " << p->transpose() << " ] ";
    return os;
  }

  //! Utility functions.
  template <int N>
  double signed_area(const SmallPolygon<N>& polygon)
  {
    // Computation derived from Green's formula
    double A = 0.;
    for (int i1 = N-1, i2 = 0; i2 < N; i1=i2++)
    {
      Matrix2d M;
      M.col(0) = polygon[i1];
      M.col(1) = polygon[i2];
      A += M.determinant();
    }
    return 0.5*A;
  }

  template <int N>
  inline double area(const SmallPolygon<N>& polygon)
  {
    return std::abs(signed_area(polygon));
  }

  //! Even-odd rule implementation.
  template <int N>
  bool inside(const Point2d& p, const SmallPolygon<N>& poly)
  {
    bool c = false;
    for (int i = 0, j = N-1; i < N; j = i++)
    {
      if ( (poly[i].y() > p.y()) != (poly[j].y() > p.y()) &&
           (p.x() <   (poly[j].x()-poly[i].x()) * (p.y()-poly[i].y())
                    / (poly[j].y()-poly[i].y()) + poly[i].x()) )
        c = !c;
    }
    return c;
  }

  template <int N>
  bool degenerate(const SmallPolygon<N>& poly,
                  double eps = std::numeric_limits<double>::epsilon())
  {
    return area(poly) < eps;
  }

  double area(const std::vector<Point2d>& polygon);

} /* namespace Sara */
} /* namespace DO */

#endif /* DO_SARA_GEOMETRY_POLYGON_HPP */
<|endoftext|>


<commit_before>/* -*- mode: c++; c-basic-offset:4 -*-
    utils/output.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "output.h"

#include "detail_p.h"
#include "kleo_assert.h"
#include "exception.h"
#include "kdpipeiodevice.h"
#include "log.h"

#include <KLocale>
#include <KMessageBox>

#include <QTemporaryFile>
#include <QString>
#include <QClipboard>
#include <QApplication>
#include <QBuffer>

#include <errno.h>

using namespace Kleo;
using namespace Kleo::_detail;
using namespace boost;

namespace {

    class TemporaryFile : public QTemporaryFile {
    public:
        explicit TemporaryFile() : QTemporaryFile() {}
        explicit TemporaryFile( const QString & templateName ) : QTemporaryFile( templateName ) {}
        explicit TemporaryFile( QObject * parent ) : QTemporaryFile( parent ) {}
        explicit TemporaryFile( const QString & templateName, QObject * parent ) : QTemporaryFile( templateName, parent ) {}

        /* reimp */ void close() {
            if ( isOpen() )
                m_oldFileName = fileName();
            QTemporaryFile::close();
        }

        QString oldFileName() const { return m_oldFileName; }

    private:
        QString m_oldFileName;
    };

    template <typename T_IODevice>
    struct inhibit_close : T_IODevice {
        explicit inhibit_close() : T_IODevice() {}
        template <typename T1>
        explicit inhibit_close( T1 & t1 ) : T_IODevice( t1 ) {}

        /* reimp */ void close() {}
        void reallyClose() { T_IODevice::close(); }
    };

    class OutputImplBase : public Output {
    public:
        OutputImplBase()
            : Output(),
              m_label(),
              m_isFinalized( false ),
              m_isFinalizing( false ),
              m_cancelPending( false ),
              m_canceled( false )
        {

        }

        /* reimp */ QString label() const { return m_label; }
        void setLabel( const QString & l ) { m_label = l; }

        /* reimp */ bool isFinalized() const { return m_isFinalized; }
        /* reimp */ void finalize() {
            if ( m_isFinalized || m_isFinalizing )
                return;
            m_isFinalizing = true;
            try { doFinalize(); } catch ( ... ) { m_isFinalizing = false; throw; }
            m_isFinalizing = false;
            m_isFinalized = true;
            if ( m_cancelPending )
                cancel();
        }

        /* reimp */ void cancel() {
            if ( m_isFinalizing ) {
                m_cancelPending = true;
            } else if ( !m_canceled ) {
                m_isFinalizing = true;
                try { doCancel(); } catch ( ... ) {}
                m_isFinalizing = false;
                m_isFinalized = true;
                m_canceled = true;
            }
        }
    private:
        virtual void doFinalize() = 0;
        virtual void doCancel() = 0;
    private:
        QString m_label;
        bool m_isFinalized   : 1;
        bool m_isFinalizing  : 1;
        bool m_cancelPending : 1;
        bool m_canceled      : 1;
    };

    class PipeOutput : public OutputImplBase {
    public:
        explicit PipeOutput( assuan_fd_t fd );

        /* reimp */ shared_ptr<QIODevice> ioDevice() const { return m_io; }
        /* reimp */ void doFinalize() { m_io->reallyClose(); }
        /* reimp */ void doCancel() { doFinalize(); }
    private:
        shared_ptr< inhibit_close<KDPipeIODevice> > m_io;
    };

    class FileOutput : public OutputImplBase {
    public:
        explicit FileOutput( const QString & fileName );

        enum OverwritePolicy {
            Allow = true,
            Deny = false,
            Ask
        };
        void setOverwritePolicy( OverwritePolicy overwrite ) { m_overwrite = overwrite; }

        /* reimp */ QString label() const { return m_fileName; }
        /* reimp */ shared_ptr<QIODevice> ioDevice() const { return m_tmpFile; }
        /* reimp */ void doFinalize();
        /* reimp */ void doCancel() {}
    private:
        const QString m_fileName;
        shared_ptr< TemporaryFile > m_tmpFile;
        OverwritePolicy m_overwrite;
    };

    class ClipboardOutput : public OutputImplBase {
    public:
        explicit ClipboardOutput( QClipboard::Mode mode );

        /* reimp */ QString label() const;
        /* reimp */ shared_ptr<QIODevice> ioDevice() const { return m_buffer; }
        /* reimp */ void doFinalize();
        /* reimp */ void doCancel() {}
    private:
        const QClipboard::Mode m_mode;
        shared_ptr<QBuffer> m_buffer;
    };

}

shared_ptr<Output> Output::createFromPipeDevice( assuan_fd_t fd, const QString & label ) {
    shared_ptr<PipeOutput> po( new PipeOutput( fd ) );
    po->setLabel( label );
    return po;
}

PipeOutput::PipeOutput( assuan_fd_t fd )
    : OutputImplBase(),
      m_io( new inhibit_close<KDPipeIODevice> )
{
    errno = 0;
    if ( !m_io->open( fd, QIODevice::WriteOnly ) )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't open FD %1 for writing",
                               assuanFD2int( fd ) ) );
}

shared_ptr<Output> Output::createFromFile( const QString & fileName, bool allowOverwrite ) {
    shared_ptr<FileOutput> fo( new FileOutput( fileName ) );
    if ( allowOverwrite )
        fo->setOverwritePolicy( FileOutput::Allow );
    return fo;
}

FileOutput::FileOutput( const QString & fileName )
    : OutputImplBase(),
      m_fileName( fileName ),
      m_tmpFile( new TemporaryFile( fileName ) ),
      m_overwrite( Ask )
{
    errno = 0;
    if ( !m_tmpFile->open() )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't create temporary file for output \"%1\"", fileName ) );
}

static bool obtainOverwritePermission( const QString & fileName, QWidget * parent ) {
    return KMessageBox::questionYesNo( parent, i18n("The file %1 already exists.\n"
                                                    "Overwrite?", fileName ),
                                       i18n("Overwrite Existing File?"), KStandardGuiItem::overwrite(), KStandardGuiItem::cancel() ) == KMessageBox::Yes ;
}

void FileOutput::doFinalize() {

    kleo_assert( m_tmpFile );

    if ( m_tmpFile->isOpen() )
        m_tmpFile->close();

    const QString tmpFileName = m_tmpFile->oldFileName();

    if ( QFile::rename( tmpFileName, m_fileName ) ) {
        m_tmpFile->setAutoRemove( false );
        return;
    }

    if ( !obtainOverwritePermission( m_fileName, 0 ) )
        throw Exception( gpg_error( GPG_ERR_CANCELED ),
                         i18n( "Overwriting declined" ) );

    if ( !QFile::remove( m_fileName ) )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n("Couldn't remove file \"%1\" for overwriting.", m_fileName ) );

    if ( QFile::rename( tmpFileName, m_fileName ) ) {
        m_tmpFile->setAutoRemove( false );
        return;
    }

    throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                     i18n( "Couldn't rename file \"%1\" to \"%2\"",
                           tmpFileName, m_fileName ) );
}

shared_ptr<Output> Output::createFromClipboard() {
    return shared_ptr<Output>( new ClipboardOutput( QClipboard::Clipboard ) );
}

ClipboardOutput::ClipboardOutput( QClipboard::Mode mode )
    : OutputImplBase(),
      m_mode( mode ),
      m_buffer( new QBuffer )
{
    errno = 0;
    if ( !m_buffer->open( QIODevice::WriteOnly ) )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't write to clipboard" ) );
}

QString ClipboardOutput::label() const {
    switch ( m_mode ) {
    case QClipboard::Clipboard:
        return i18n( "Clipboard" );
    case QClipboard::FindBuffer:
        return i18n( "Find buffer" );
    case QClipboard::Selection:
        return i18n( "Selection" );
    }
    return QString();
}

void ClipboardOutput::doFinalize() {
    m_buffer->close();
    if ( QClipboard * const cb = QApplication::clipboard() )
        cb->setText( QString::fromUtf8( m_buffer->data() ) );
    else
        throw Exception( gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't find clipboard" ) );
}

Output::~Output() {}
<commit_msg>Better safe than sorry.<commit_after>/* -*- mode: c++; c-basic-offset:4 -*-
    utils/output.cpp

    This file is part of Kleopatra, the KDE keymanager
    Copyright (c) 2007 Klarälvdalens Datakonsult AB

    Kleopatra is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    Kleopatra is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <config-kleopatra.h>

#include "output.h"

#include "detail_p.h"
#include "kleo_assert.h"
#include "exception.h"
#include "kdpipeiodevice.h"
#include "log.h"

#include <KLocale>
#include <KMessageBox>

#include <QTemporaryFile>
#include <QString>
#include <QClipboard>
#include <QApplication>
#include <QBuffer>

#include <errno.h>

using namespace Kleo;
using namespace Kleo::_detail;
using namespace boost;

namespace {

    class TemporaryFile : public QTemporaryFile {
    public:
        explicit TemporaryFile() : QTemporaryFile() {}
        explicit TemporaryFile( const QString & templateName ) : QTemporaryFile( templateName ) {}
        explicit TemporaryFile( QObject * parent ) : QTemporaryFile( parent ) {}
        explicit TemporaryFile( const QString & templateName, QObject * parent ) : QTemporaryFile( templateName, parent ) {}

        /* reimp */ void close() {
            if ( isOpen() )
                m_oldFileName = fileName();
            QTemporaryFile::close();
        }

        QString oldFileName() const { return m_oldFileName; }

    private:
        QString m_oldFileName;
    };

    template <typename T_IODevice>
    struct inhibit_close : T_IODevice {
        explicit inhibit_close() : T_IODevice() {}
        template <typename T1>
        explicit inhibit_close( T1 & t1 ) : T_IODevice( t1 ) {}

        /* reimp */ void close() {}
        void reallyClose() { T_IODevice::close(); }
    };

    class OutputImplBase : public Output {
    public:
        OutputImplBase()
            : Output(),
              m_label(),
              m_isFinalized( false ),
              m_isFinalizing( false ),
              m_cancelPending( false ),
              m_canceled( false )
        {

        }

        /* reimp */ QString label() const { return m_label; }
        void setLabel( const QString & l ) { m_label = l; }

        /* reimp */ bool isFinalized() const { return m_isFinalized; }
        /* reimp */ void finalize() {
            if ( m_isFinalized || m_isFinalizing )
                return;
            m_isFinalizing = true;
            try { doFinalize(); } catch ( ... ) { m_isFinalizing = false; throw; }
            m_isFinalizing = false;
            m_isFinalized = true;
            if ( m_cancelPending )
                cancel();
        }

        /* reimp */ void cancel() {
            if ( m_isFinalizing ) {
                m_cancelPending = true;
            } else if ( !m_canceled ) {
                m_isFinalizing = true;
                try { doCancel(); } catch ( ... ) {}
                m_isFinalizing = false;
                m_isFinalized = true;
                m_canceled = true;
            }
        }
    private:
        virtual void doFinalize() = 0;
        virtual void doCancel() = 0;
    private:
        QString m_label;
        bool m_isFinalized   : 1;
        bool m_isFinalizing  : 1;
        bool m_cancelPending : 1;
        bool m_canceled      : 1;
    };

    class PipeOutput : public OutputImplBase {
    public:
        explicit PipeOutput( assuan_fd_t fd );

        /* reimp */ shared_ptr<QIODevice> ioDevice() const { return m_io; }
        /* reimp */ void doFinalize() { m_io->reallyClose(); }
        /* reimp */ void doCancel() { doFinalize(); }
    private:
        shared_ptr< inhibit_close<KDPipeIODevice> > m_io;
    };

    class FileOutput : public OutputImplBase {
    public:
        explicit FileOutput( const QString & fileName );

        enum OverwritePolicy {
            Allow = true,
            Deny = false,
            Ask
        };
        void setOverwritePolicy( OverwritePolicy overwrite ) { m_overwrite = overwrite; }

        /* reimp */ QString label() const { return m_fileName; }
        /* reimp */ shared_ptr<QIODevice> ioDevice() const { return m_tmpFile; }
        /* reimp */ void doFinalize();
        /* reimp */ void doCancel() {}
    private:
        const QString m_fileName;
        shared_ptr< TemporaryFile > m_tmpFile;
        OverwritePolicy m_overwrite;
    };

    class ClipboardOutput : public OutputImplBase {
    public:
        explicit ClipboardOutput( QClipboard::Mode mode );

        /* reimp */ QString label() const;
        /* reimp */ shared_ptr<QIODevice> ioDevice() const { return m_buffer; }
        /* reimp */ void doFinalize();
        /* reimp */ void doCancel() {}
    private:
        const QClipboard::Mode m_mode;
        shared_ptr<QBuffer> m_buffer;
    };

}

shared_ptr<Output> Output::createFromPipeDevice( assuan_fd_t fd, const QString & label ) {
    shared_ptr<PipeOutput> po( new PipeOutput( fd ) );
    po->setLabel( label );
    return po;
}

PipeOutput::PipeOutput( assuan_fd_t fd )
    : OutputImplBase(),
      m_io( new inhibit_close<KDPipeIODevice> )
{
    errno = 0;
    if ( !m_io->open( fd, QIODevice::WriteOnly ) )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't open FD %1 for writing",
                               assuanFD2int( fd ) ) );
}

shared_ptr<Output> Output::createFromFile( const QString & fileName, bool allowOverwrite ) {
    shared_ptr<FileOutput> fo( new FileOutput( fileName ) );
    if ( allowOverwrite )
        fo->setOverwritePolicy( FileOutput::Allow );
    return fo;
}

FileOutput::FileOutput( const QString & fileName )
    : OutputImplBase(),
      m_fileName( fileName ),
      m_tmpFile( new TemporaryFile( fileName ) ),
      m_overwrite( Ask )
{
    errno = 0;
    if ( !m_tmpFile->open() )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't create temporary file for output \"%1\"", fileName ) );
}

static bool obtainOverwritePermission( const QString & fileName, QWidget * parent ) {
    return KMessageBox::questionYesNo( parent, i18n("The file %1 already exists.\n"
                                                    "Overwrite?", fileName ),
                                       i18n("Overwrite Existing File?"), KStandardGuiItem::overwrite(), KStandardGuiItem::cancel() ) == KMessageBox::Yes ;
}

void FileOutput::doFinalize() {

    kleo_assert( m_tmpFile );

    if ( m_tmpFile->isOpen() )
        m_tmpFile->close();

    const QString tmpFileName = m_tmpFile->oldFileName();

    if ( QFile::rename( tmpFileName, m_fileName ) ) {
        m_tmpFile->setAutoRemove( false );
        return;
    }

    if ( !obtainOverwritePermission( m_fileName, 0 ) )
        throw Exception( gpg_error( GPG_ERR_CANCELED ),
                         i18n( "Overwriting declined" ) );

    if ( !QFile::remove( m_fileName ) )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n("Couldn't remove file \"%1\" for overwriting.", m_fileName ) );

    if ( QFile::rename( tmpFileName, m_fileName ) ) {
        m_tmpFile->setAutoRemove( false );
        return;
    }

    throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                     i18n( "Couldn't rename file \"%1\" to \"%2\"",
                           tmpFileName, m_fileName ) );
}

shared_ptr<Output> Output::createFromClipboard() {
    return shared_ptr<Output>( new ClipboardOutput( QClipboard::Clipboard ) );
}

ClipboardOutput::ClipboardOutput( QClipboard::Mode mode )
    : OutputImplBase(),
      m_mode( mode ),
      m_buffer( new QBuffer )
{
    errno = 0;
    if ( !m_buffer->open( QIODevice::WriteOnly ) )
        throw Exception( errno ? gpg_error_from_errno( errno ) : gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't write to clipboard" ) );
}

QString ClipboardOutput::label() const {
    switch ( m_mode ) {
    case QClipboard::Clipboard:
        return i18n( "Clipboard" );
    case QClipboard::FindBuffer:
        return i18n( "Find buffer" );
    case QClipboard::Selection:
        return i18n( "Selection" );
    }
    return QString();
}

void ClipboardOutput::doFinalize() {
    if ( m_buffer->isOpen() )
        m_buffer->close();
    if ( QClipboard * const cb = QApplication::clipboard() )
        cb->setText( QString::fromUtf8( m_buffer->data() ) );
    else
        throw Exception( gpg_error( GPG_ERR_EIO ),
                         i18n( "Couldn't find clipboard" ) );
}

Output::~Output() {}
<|endoftext|>


<commit_before>/**
 * kmeditor.cpp
 *
 * Copyright (C)  2007 Laurent Montel <montel@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "kmcomposereditor.h"
#include "kmcomposewin.h"
#include "kemailquotinghighter.h"
#include "kmcommands.h"
#include "kmmsgdict.h"
#include "kmfolder.h"
#include "maillistdrag.h"

#include <klocale.h>
#include <kmenu.h>

#include <QBuffer>

KMComposerEditor::KMComposerEditor( KMComposeWin *win,QWidget *parent)
 :KMeditor(parent),m_composerWin(win)
{
  QColor defaultColor1( 0x00, 0x80, 0x00 ); // defaults from kmreaderwin.cpp
  QColor defaultColor2( 0x00, 0x70, 0x00 );
  QColor defaultColor3( 0x00, 0x60, 0x00 );
  QColor defaultForeground( qApp->palette().color( QPalette::Text ) );

  //TODO look at background color
  QColor c = Qt::red;
  KConfigGroup readerConfig( KMKernel::config(), "Reader" );
  QColor col1;
  if ( !readerConfig.readEntry(  "defaultColors", true ) )
      col1 = readerConfig.readEntry( "ForegroundColor", defaultForeground );
  else
      col1 = defaultForeground;
  QColor col2 = readerConfig.readEntry( "QuotedText3", defaultColor3  );
  QColor col3 = readerConfig.readEntry( "QuotedText2", defaultColor2  );
  QColor col4 = readerConfig.readEntry( "QuotedText1", defaultColor1  );
  QColor misspelled = readerConfig.readEntry( "MisspelledColor", c  );
  //TODO add it
  //static_cast<Sonnet::KEMailQuotingHighlighter*>(hightighter())->setQuoteColor(col1, col2, col3, col4);

  switchTextMode( false );
  mHtmlMode = false;
}

KMComposerEditor::~KMComposerEditor()
{
}

QString KMComposerEditor::smartQuote( const QString & msg )
{
  return m_composerWin->smartQuote(msg);
}

QString KMComposerEditor::quotePrefixName() const
{
   return m_composerWin->quotePrefixName();
}

void KMComposerEditor::dropEvent( QDropEvent *e )
{
  const QMimeData *md = e->mimeData();
  if ( KPIM::MailList::canDecode( md ) ) {
    e->accept();
    // Decode the list of serial numbers stored as the drag data
    QByteArray serNums = KPIM::MailList::serialsFromMimeData( md );
    QBuffer serNumBuffer( &serNums );
    serNumBuffer.open( QIODevice::ReadOnly );
    QDataStream serNumStream( &serNumBuffer );
    quint32 serNum;
    KMFolder *folder = 0;
    int idx;
    QList<KMMsgBase*> messageList;
    while ( !serNumStream.atEnd() ) {
      KMMsgBase *msgBase = 0;
      serNumStream >> serNum;
      KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
      if ( folder ) {
        msgBase = folder->getMsgBase( idx );
      }
      if ( msgBase ) {
        messageList.append( msgBase );
      }
    }
    serNumBuffer.close();
    uint identity = folder ? folder->identity() : 0;
    KMCommand *command = new KMForwardAttachedCommand( m_composerWin, messageList,
                                                       identity, m_composerWin );
    command->start();
  } else if ( md->hasFormat( "image/png" ) ) {
    emit attachPNGImageData( e->encodedData( "image/png" ) );
  } else {
    KUrl::List urlList = KUrl::List::fromMimeData( md );
    if ( !urlList.isEmpty() ) {
      e->accept();
      KMenu p;
      const QAction *addAsTextAction = p.addAction( i18n("Add as Text") );
      const QAction *addAsAtmAction = p.addAction( i18n("Add as Attachment") );
      const QAction *selectedAction = p.exec( mapToGlobal( e->pos() ) );
      if ( selectedAction == addAsTextAction ) {
        for ( KUrl::List::Iterator it = urlList.begin();
              it != urlList.end(); ++it ) {
          textCursor().insertText( (*it).url() );
        }
      } else if ( selectedAction == addAsAtmAction ) {
        for ( KUrl::List::Iterator it = urlList.begin();
              it != urlList.end(); ++it ) {
          m_composerWin->addAttach( *it );
        }
      }
    } else if ( md->hasText() ) {
      textCursor().insertText( md->text() );
      e->accept();
    } else {
      kDebug(5006) <<"KMComposerEditor::dropEvent, unable to add dropped object";
      return KMeditor::dropEvent( e );
    }
  }
}

bool KMComposerEditor::canInsertFromMimeData( const QMimeData *source ) const
{
  if ( source->hasFormat( "text/x-kmail-textsnippet" ) )
    return true;
  return KMeditor::canInsertFromMimeData( source );
}

void KMComposerEditor::insertFromMimeData( const QMimeData *source )
{
  if ( source->hasFormat( "text/x-kmail-textsnippet" ) )
    emit insertSnippet();
  KMeditor::insertFromMimeData( source );
}

QString KMComposerEditor::brokenText() const
{
  QString temp;
  QTextDocument* doc = document();
  QTextBlock block = doc->begin();
  while ( block.isValid() ) {
    QTextLayout* layout = block.layout();
    for ( int i = 0; i < layout->lineCount(); i++ ) {
      QTextLine line = layout->lineAt( i );
      temp += block.text().mid( line.textStart(), line.textLength() ) + '\n';
    }
    block = block.next();
  }
  return temp;
}

void KMComposerEditor::setHtmlMode( bool mode )
{
  if ( mode ) {
    if ( ! mHtmlMode ) {
      mHtmlMode = true;

      // set all highlighted text caused by spelling back to black
      //int paraFrom, indexFrom, paraTo, indexTo;
      // set all highlighted text caused by spelling back to black
      // for the case we're in textmode, the user selects some text and decides to format this selected text
      //int startpos = textCursor().selectionStart();
      //int endpos = textCursor().selectionEnd();
      //selectAll();
      //setTextColor(QColor(0,0,0));

      //Laurent fix me
      //mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo );
      switchTextMode( true );
    }
  }
  else {
    mHtmlMode = false;
    // like the next 2 lines, or should we selectAll and apply the default font?

    selectAll();
    setTextColor(QColor(0,0,0));
    switchTextMode( false );
  }
  document()->setModified( true );
}

bool KMComposerEditor::htmlMode()
{
  return mHtmlMode;
}

QString KMComposerEditor::text()
{
  if ( mHtmlMode )
    return toHtml();
  else
    return toPlainText();
}

#include "kmcomposereditor.moc"
<commit_msg>Need to fix it<commit_after>/**
 * kmeditor.cpp
 *
 * Copyright (C)  2007 Laurent Montel <montel@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "kmcomposereditor.h"
#include "kmcomposewin.h"
#include "kemailquotinghighter.h"
#include "kmcommands.h"
#include "kmmsgdict.h"
#include "kmfolder.h"
#include "maillistdrag.h"

#include <klocale.h>
#include <kmenu.h>

#include <QBuffer>

KMComposerEditor::KMComposerEditor( KMComposeWin *win,QWidget *parent)
 :KMeditor(parent),m_composerWin(win)
{
  QColor defaultColor1( 0x00, 0x80, 0x00 ); // defaults from kmreaderwin.cpp
  QColor defaultColor2( 0x00, 0x70, 0x00 );
  QColor defaultColor3( 0x00, 0x60, 0x00 );
  QColor defaultForeground( qApp->palette().color( QPalette::Text ) );

  //TODO look at background color
  QColor c = Qt::red;
  KConfigGroup readerConfig( KMKernel::config(), "Reader" );
  QColor col1;
  if ( !readerConfig.readEntry(  "defaultColors", true ) )
      col1 = readerConfig.readEntry( "ForegroundColor", defaultForeground );
  else
      col1 = defaultForeground;
  QColor col2 = readerConfig.readEntry( "QuotedText3", defaultColor3  );
  QColor col3 = readerConfig.readEntry( "QuotedText2", defaultColor2  );
  QColor col4 = readerConfig.readEntry( "QuotedText1", defaultColor1  );
  QColor misspelled = readerConfig.readEntry( "MisspelledColor", c  );
  //TODO add it
  //static_cast<KPIM::KEMailQuotingHighlighter*>(highlighter())->setQuoteColor(col1, col2, col3, col4);

  switchTextMode( false );
  mHtmlMode = false;
}

KMComposerEditor::~KMComposerEditor()
{
}

QString KMComposerEditor::smartQuote( const QString & msg )
{
  return m_composerWin->smartQuote(msg);
}

QString KMComposerEditor::quotePrefixName() const
{
   return m_composerWin->quotePrefixName();
}

void KMComposerEditor::dropEvent( QDropEvent *e )
{
  const QMimeData *md = e->mimeData();
  if ( KPIM::MailList::canDecode( md ) ) {
    e->accept();
    // Decode the list of serial numbers stored as the drag data
    QByteArray serNums = KPIM::MailList::serialsFromMimeData( md );
    QBuffer serNumBuffer( &serNums );
    serNumBuffer.open( QIODevice::ReadOnly );
    QDataStream serNumStream( &serNumBuffer );
    quint32 serNum;
    KMFolder *folder = 0;
    int idx;
    QList<KMMsgBase*> messageList;
    while ( !serNumStream.atEnd() ) {
      KMMsgBase *msgBase = 0;
      serNumStream >> serNum;
      KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
      if ( folder ) {
        msgBase = folder->getMsgBase( idx );
      }
      if ( msgBase ) {
        messageList.append( msgBase );
      }
    }
    serNumBuffer.close();
    uint identity = folder ? folder->identity() : 0;
    KMCommand *command = new KMForwardAttachedCommand( m_composerWin, messageList,
                                                       identity, m_composerWin );
    command->start();
  } else if ( md->hasFormat( "image/png" ) ) {
    emit attachPNGImageData( e->encodedData( "image/png" ) );
  } else {
    KUrl::List urlList = KUrl::List::fromMimeData( md );
    if ( !urlList.isEmpty() ) {
      e->accept();
      KMenu p;
      const QAction *addAsTextAction = p.addAction( i18n("Add as Text") );
      const QAction *addAsAtmAction = p.addAction( i18n("Add as Attachment") );
      const QAction *selectedAction = p.exec( mapToGlobal( e->pos() ) );
      if ( selectedAction == addAsTextAction ) {
        for ( KUrl::List::Iterator it = urlList.begin();
              it != urlList.end(); ++it ) {
          textCursor().insertText( (*it).url() );
        }
      } else if ( selectedAction == addAsAtmAction ) {
        for ( KUrl::List::Iterator it = urlList.begin();
              it != urlList.end(); ++it ) {
          m_composerWin->addAttach( *it );
        }
      }
    } else if ( md->hasText() ) {
      textCursor().insertText( md->text() );
      e->accept();
    } else {
      kDebug(5006) <<"KMComposerEditor::dropEvent, unable to add dropped object";
      return KMeditor::dropEvent( e );
    }
  }
}

bool KMComposerEditor::canInsertFromMimeData( const QMimeData *source ) const
{
  if ( source->hasFormat( "text/x-kmail-textsnippet" ) )
    return true;
  return KMeditor::canInsertFromMimeData( source );
}

void KMComposerEditor::insertFromMimeData( const QMimeData *source )
{
  if ( source->hasFormat( "text/x-kmail-textsnippet" ) )
    emit insertSnippet();
  KMeditor::insertFromMimeData( source );
}

QString KMComposerEditor::brokenText() const
{
  QString temp;
  QTextDocument* doc = document();
  QTextBlock block = doc->begin();
  while ( block.isValid() ) {
    QTextLayout* layout = block.layout();
    for ( int i = 0; i < layout->lineCount(); i++ ) {
      QTextLine line = layout->lineAt( i );
      temp += block.text().mid( line.textStart(), line.textLength() ) + '\n';
    }
    block = block.next();
  }
  return temp;
}

void KMComposerEditor::setHtmlMode( bool mode )
{
  if ( mode ) {
    if ( ! mHtmlMode ) {
      mHtmlMode = true;

      // set all highlighted text caused by spelling back to black
      //int paraFrom, indexFrom, paraTo, indexTo;
      // set all highlighted text caused by spelling back to black
      // for the case we're in textmode, the user selects some text and decides to format this selected text
      //int startpos = textCursor().selectionStart();
      //int endpos = textCursor().selectionEnd();
      //selectAll();
      //setTextColor(QColor(0,0,0));

      //Laurent fix me
      //mEditor->setSelection ( paraFrom, indexFrom, paraTo, indexTo );
      switchTextMode( true );
    }
  }
  else {
    mHtmlMode = false;
    // like the next 2 lines, or should we selectAll and apply the default font?

    selectAll();
    setTextColor(QColor(0,0,0));
    switchTextMode( false );
  }
  document()->setModified( true );
}

bool KMComposerEditor::htmlMode()
{
  return mHtmlMode;
}

QString KMComposerEditor::text()
{
  if ( mHtmlMode )
    return toHtml();
  else
    return toPlainText();
}

#include "kmcomposereditor.moc"
<|endoftext|>


<commit_before><commit_msg>Added quality to audio rendering<commit_after><|endoftext|>