<commit_before>/**
 * @file win32/net.cpp
 * @brief Win32 network access layer (using WinHTTP)
 *
 * (c) 2013-2014 by Mega Limited, Wellsford, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "meganet.h"

namespace mega {
WinHttpIO::WinHttpIO()
{
    InitializeCriticalSection(&csHTTP);
    EnterCriticalSection(&csHTTP);

    hWakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    waiter = NULL;
}

WinHttpIO::~WinHttpIO()
{
    WinHttpCloseHandle(hSession);
    LeaveCriticalSection(&csHTTP);
}

void WinHttpIO::setuseragent(string* useragent)
{
    string wuseragent;

    wuseragent.resize((useragent->size() + 1) * sizeof(wchar_t));
    wuseragent.resize(sizeof(wchar_t)
                      * (MultiByteToWideChar(CP_UTF8, 0, useragent->c_str(),
                                              -1, (wchar_t*)wuseragent.data(),
                                              wuseragent.size() / sizeof(wchar_t) + 1)
                          - 1));

    // create the session handle using the default settings.
    hSession = WinHttpOpen((LPCWSTR)wuseragent.data(),
                           WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                           WINHTTP_NO_PROXY_NAME,
                           WINHTTP_NO_PROXY_BYPASS,
                           WINHTTP_FLAG_ASYNC);
}

// trigger wakeup
void WinHttpIO::httpevent()
{
    SetEvent(hWakeupEvent);
}

// (WinHTTP unfortunately uses threads, hence the need for a mutex)
void WinHttpIO::entercs()
{
    EnterCriticalSection(&csHTTP);
}

void WinHttpIO::leavecs()
{
    LeaveCriticalSection(&csHTTP);
}

// ensure wakeup from WinHttpIO events
void WinHttpIO::addevents(Waiter* cwaiter, int flags)
{
    waiter = (WinWaiter*)cwaiter;

    waiter->addhandle(hWakeupEvent, flags);
    waiter->pcsHTTP = &csHTTP;
}

// handle WinHTTP callbacks (which can be in a worker thread context)
VOID CALLBACK WinHttpIO::asynccallback(HINTERNET hInternet, DWORD_PTR dwContext,
                                       DWORD dwInternetStatus,
                                       LPVOID lpvStatusInformation,
                                       DWORD dwStatusInformationLength)
{
    WinHttpContext* httpctx = (WinHttpContext*)dwContext;
    WinHttpIO* httpio = (WinHttpIO*)httpctx->httpio;

    if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING)
    {
        assert(!httpctx->req);

        if (httpctx->gzip)
        {
            inflateEnd(&httpctx->z);
        }

        delete httpctx;
        return;
    }

    httpio->entercs();

    HttpReq* req = httpctx->req;

    // request cancellations that occured after asynccallback() was entered are caught here
    if (!req)
    {
        httpio->leavecs();
        return;
    }

    switch (dwInternetStatus)
    {
        case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
        {
            DWORD size = *(DWORD*)lpvStatusInformation;

            if (!size)
            {
                if (debug)
                {
                    if (req->binary)
                    {
                        cout << "[received " << req->bufpos << " bytes of raw data]" << endl;
                    }
                    else
                    {
                        cout << "Received: " << req->in.c_str() << endl;
                    }
                }

                req->status = req->httpstatus == 200 ? REQ_SUCCESS : REQ_FAILURE;
                httpio->success = true;
                httpio->httpevent();
            }
            else
            {
                char* ptr;

                if (httpctx->gzip)
                {
                    m_off_t zprevsize = httpctx->zin.size();
                    httpctx->zin.resize(zprevsize + size);
                    ptr = (char*) httpctx->zin.data() + zprevsize;
                }
                else
                {
                    ptr = (char*)req->reserveput((unsigned*)&size);
                    req->bufpos += size;
                }

                if (!WinHttpReadData(hInternet, ptr, size, NULL))
                {
                    httpio->cancel(req);
                }
            }

            httpio->httpevent();
            break;
        }

        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
            if (dwStatusInformationLength)
            {
                if (httpctx->gzip)
                {
                    httpctx->z.next_in = (Bytef*)lpvStatusInformation;
                    httpctx->z.avail_in = dwStatusInformationLength;

                    req->bufpos += httpctx->z.avail_out;
                    int t = inflate(&httpctx->z, Z_SYNC_FLUSH);
                    req->bufpos -= httpctx->z.avail_out;

                    if (((char *)lpvStatusInformation + dwStatusInformationLength) ==
                             (httpctx->zin.data() + httpctx->zin.size()))
                    {
                        httpctx->zin.clear();
                    }

                    if (t != Z_OK && (t != Z_STREAM_END || httpctx->z.avail_out))
                    {
                        httpio->cancel(req);
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                }
            }
            break;

        case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
        {
            DWORD statusCode;
            DWORD statusCodeSize = sizeof(statusCode);

            if (!WinHttpQueryHeaders(httpctx->hRequest,
                                     WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
                                     WINHTTP_HEADER_NAME_BY_INDEX,
                                     &statusCode,
                                     &statusCodeSize,
                                     WINHTTP_NO_HEADER_INDEX))
            {
                httpio->cancel(req);
                httpio->httpevent();
            }
            else
            {
                req->httpstatus = statusCode;

                if (!req->buf)
                {
                    // obtain original content length - always present if gzip is in use
                    DWORD contentLength;
                    DWORD contentLengthSize = sizeof(contentLength);

                    if (WinHttpQueryHeaders(httpctx->hRequest,
                                            WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER,
                                            L"Original-Content-Length",
                                            &contentLength,
                                            &contentLengthSize,
                                            WINHTTP_NO_HEADER_INDEX))
                    {
                        req->setcontentlength(contentLength);

                        // check for gzip content encoding
                        WCHAR contentEncoding[16];
                        DWORD contentEncodingSize = sizeof(contentEncoding);

                        httpctx->gzip = WinHttpQueryHeaders(httpctx->hRequest,
                                                WINHTTP_QUERY_CONTENT_ENCODING,
                                                WINHTTP_HEADER_NAME_BY_INDEX,
                                                &contentEncoding,
                                                &contentEncodingSize,
                                                WINHTTP_NO_HEADER_INDEX)
                                    && !wcscmp(contentEncoding,L"gzip");

                        if (httpctx->gzip)
                        {
                            httpctx->z.zalloc = Z_NULL;
                            httpctx->z.zfree = Z_NULL;
                            httpctx->z.opaque = Z_NULL;
                            httpctx->z.avail_in = 0;
                            httpctx->z.next_in = Z_NULL;

                            inflateInit2(&httpctx->z, MAX_WBITS+16);

                            req->in.resize(contentLength);
                            httpctx->z.avail_out = contentLength;
                            httpctx->z.next_out = (unsigned char*)req->in.data();
                        }
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                }
                else if (httpio->waiter && httpio->noinetds)
                {
                    httpio->inetstatus(true);
                }
            }
        }
        break;

        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
            if (httpio->waiter && GetLastError() != ERROR_WINHTTP_TIMEOUT)
            {
                httpio->inetstatus(false);
            }

        // fall through
        case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
            httpio->cancel(req);
            httpio->httpevent();
            break;

        case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
        case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
            if (httpctx->postpos < httpctx->postlen)
            {
                unsigned pos = httpctx->postpos;
                unsigned t = httpctx->postlen - pos;

                if (t > HTTP_POST_CHUNK_SIZE)
                {
                    t = HTTP_POST_CHUNK_SIZE;
                }

                httpctx->postpos += t;

                if (!WinHttpWriteData(httpctx->hRequest, (LPVOID)(httpctx->postdata + pos), t, NULL))
                {
                    req->httpio->cancel(req);
                }

                httpio->httpevent();
            }
            else
            {
                if (!WinHttpReceiveResponse(httpctx->hRequest, NULL))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                }
            }
    }

    httpio->leavecs();
}

// POST request to URL
void WinHttpIO::post(HttpReq* req, const char* data, unsigned len)
{
    if (debug)
    {
        cout << "POST target URL: " << req->posturl << endl;

        if (req->binary)
        {
            cout << "[sending " << req->out->size() << " bytes of raw data]" << endl;
        }
        else
        {
            cout << "Sending: " << *req->out << endl;
        }
    }

    WinHttpContext* httpctx;

    WCHAR szURL[8192];
    WCHAR szHost[256];
    URL_COMPONENTS urlComp = { sizeof urlComp };

    urlComp.lpszHostName = szHost;
    urlComp.dwHostNameLength = sizeof szHost / sizeof *szHost;
    urlComp.dwUrlPathLength = (DWORD)-1;
    urlComp.dwSchemeLength = (DWORD)-1;

    httpctx = new WinHttpContext;

    httpctx->httpio = this;
    httpctx->req = req;
    httpctx->gzip = false;

    req->httpiohandle = (void*)httpctx;

    if (MultiByteToWideChar(CP_UTF8, 0, req->posturl.c_str(), -1, szURL,
                            sizeof szURL / sizeof *szURL)
            && WinHttpCrackUrl(szURL, 0, 0, &urlComp))
    {
        if ((httpctx->hConnect = WinHttpConnect(hSession, szHost, urlComp.nPort, 0)))
        {
            httpctx->hRequest = WinHttpOpenRequest(httpctx->hConnect, L"POST",
                                                   urlComp.lpszUrlPath, NULL,
                                                   WINHTTP_NO_REFERER,
                                                   WINHTTP_DEFAULT_ACCEPT_TYPES,
                                                   (urlComp.nScheme == INTERNET_SCHEME_HTTPS)
                                                   ? WINHTTP_FLAG_SECURE
                                                   : 0);

            if (httpctx->hRequest)
            {
                WinHttpSetTimeouts(httpctx->hRequest, 0, 20000, 20000, 1800000);

                WinHttpSetStatusCallback(httpctx->hRequest, asynccallback,
                                         WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE
                                         | WINHTTP_CALLBACK_FLAG_READ_COMPLETE
                                         | WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE
                                         | WINHTTP_CALLBACK_FLAG_REQUEST_ERROR
                                         | WINHTTP_CALLBACK_FLAG_SECURE_FAILURE
                                         | WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE
                                         | WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE
                                         | WINHTTP_CALLBACK_FLAG_HANDLES,
                                         0);

                LPCWSTR pwszHeaders = (req->type == REQ_JSON || !req->buf)
                                      ? L"Content-Type: application/json\r\nAccept-Encoding: gzip"
                                      : L"Content-Type: application/octet-stream";

                // data is sent in HTTP_POST_CHUNK_SIZE instalments to ensure
                // semi-smooth UI progress info
                httpctx->postlen = data ? len : req->out->size();
                httpctx->postdata = data ? data : req->out->data();
                httpctx->postpos = (httpctx->postlen < HTTP_POST_CHUNK_SIZE)
                                   ? httpctx->postlen
                                   : HTTP_POST_CHUNK_SIZE;

                if (WinHttpSendRequest(httpctx->hRequest, pwszHeaders,
                                       wcslen(pwszHeaders),
                                       (LPVOID)httpctx->postdata,
                                       httpctx->postpos,
                                       httpctx->postlen,
                                       (DWORD_PTR)httpctx))
                {
                    req->status = REQ_INFLIGHT;
                    return;
                }
            }
        }
        else
        {
            httpctx->hRequest = NULL;
        }
    }
    else
    {
        httpctx->hRequest = NULL;
        httpctx->hConnect = NULL;
    }

    req->status = REQ_FAILURE;
}

// cancel pending HTTP request
void WinHttpIO::cancel(HttpReq* req)
{
    WinHttpContext* httpctx;

    if ((httpctx = (WinHttpContext*)req->httpiohandle))
    {
        httpctx->req = NULL;

        req->httpstatus = 0;
        req->status = REQ_FAILURE;
        req->httpiohandle = NULL;

        if (httpctx->hConnect)
        {
            WinHttpCloseHandle(httpctx->hConnect);
        }

        if (httpctx->hRequest)
        {
            WinHttpCloseHandle(httpctx->hRequest);
        }
    }
}

// supply progress information on POST data
m_off_t WinHttpIO::postpos(void* handle)
{
    return ((WinHttpContext*)handle)->postpos;
}

// process events
bool WinHttpIO::doio()
{
    return false;
}
} // namespace
<commit_msg>Win32/Net: SSL public key pinning<commit_after>/**
 * @file win32/net.cpp
 * @brief Win32 network access layer (using WinHTTP)
 *
 * (c) 2013-2014 by Mega Limited, Wellsford, New Zealand
 *
 * This file is part of the MEGA SDK - Client Access Engine.
 *
 * Applications using the MEGA API must present a valid application key
 * and comply with the the rules set forth in the Terms of Service.
 *
 * The MEGA SDK 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.
 *
 * @copyright Simplified (2-clause) BSD License.
 *
 * You should have received a copy of the license along with this
 * program.
 */

#include "meganet.h"

namespace mega {
WinHttpIO::WinHttpIO()
{
    InitializeCriticalSection(&csHTTP);
    EnterCriticalSection(&csHTTP);

    hWakeupEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    waiter = NULL;
}

WinHttpIO::~WinHttpIO()
{
    WinHttpCloseHandle(hSession);
    LeaveCriticalSection(&csHTTP);
}

void WinHttpIO::setuseragent(string* useragent)
{
    string wuseragent;

    wuseragent.resize((useragent->size() + 1) * sizeof(wchar_t));
    wuseragent.resize(sizeof(wchar_t)
                      * (MultiByteToWideChar(CP_UTF8, 0, useragent->c_str(),
                                              -1, (wchar_t*)wuseragent.data(),
                                              wuseragent.size() / sizeof(wchar_t) + 1)
                          - 1));

    // create the session handle using the default settings.
    hSession = WinHttpOpen((LPCWSTR)wuseragent.data(),
                           WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                           WINHTTP_NO_PROXY_NAME,
                           WINHTTP_NO_PROXY_BYPASS,
                           WINHTTP_FLAG_ASYNC);
}

// trigger wakeup
void WinHttpIO::httpevent()
{
    SetEvent(hWakeupEvent);
}

// (WinHTTP unfortunately uses threads, hence the need for a mutex)
void WinHttpIO::entercs()
{
    EnterCriticalSection(&csHTTP);
}

void WinHttpIO::leavecs()
{
    LeaveCriticalSection(&csHTTP);
}

// ensure wakeup from WinHttpIO events
void WinHttpIO::addevents(Waiter* cwaiter, int flags)
{
    waiter = (WinWaiter*)cwaiter;

    waiter->addhandle(hWakeupEvent, flags);
    waiter->pcsHTTP = &csHTTP;
}

// handle WinHTTP callbacks (which can be in a worker thread context)
VOID CALLBACK WinHttpIO::asynccallback(HINTERNET hInternet, DWORD_PTR dwContext,
                                       DWORD dwInternetStatus,
                                       LPVOID lpvStatusInformation,
                                       DWORD dwStatusInformationLength)
{
    WinHttpContext* httpctx = (WinHttpContext*)dwContext;
    WinHttpIO* httpio = (WinHttpIO*)httpctx->httpio;

    if (dwInternetStatus == WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING)
    {
        assert(!httpctx->req);

        if (httpctx->gzip)
        {
            inflateEnd(&httpctx->z);
        }

        delete httpctx;
        return;
    }

    httpio->entercs();

    HttpReq* req = httpctx->req;

    // request cancellations that occured after asynccallback() was entered are caught here
    if (!req)
    {
        httpio->leavecs();
        return;
    }

    switch (dwInternetStatus)
    {
        case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE:
        {
            DWORD size = *(DWORD*)lpvStatusInformation;

            if (!size)
            {
                if (debug)
                {
                    if (req->binary)
                    {
                        cout << "[received " << req->bufpos << " bytes of raw data]" << endl;
                    }
                    else
                    {
                        cout << "Received: " << req->in.c_str() << endl;
                    }
                }

                req->status = req->httpstatus == 200 ? REQ_SUCCESS : REQ_FAILURE;
                httpio->success = true;
            }
            else
            {
                char* ptr;

                if (httpctx->gzip)
                {
                    m_off_t zprevsize = httpctx->zin.size();
                    httpctx->zin.resize(zprevsize + size);
                    ptr = (char*) httpctx->zin.data() + zprevsize;
                }
                else
                {
                    ptr = (char*)req->reserveput((unsigned*)&size);
                    req->bufpos += size;
                }

                if (!WinHttpReadData(hInternet, ptr, size, NULL))
                {
                    httpio->cancel(req);
                }
            }

            httpio->httpevent();
            break;
        }

        case WINHTTP_CALLBACK_STATUS_READ_COMPLETE:
            if (dwStatusInformationLength)
            {
                if (httpctx->gzip)
                {
                    httpctx->z.next_in = (Bytef*)lpvStatusInformation;
                    httpctx->z.avail_in = dwStatusInformationLength;

                    req->bufpos += httpctx->z.avail_out;
                    int t = inflate(&httpctx->z, Z_SYNC_FLUSH);
                    req->bufpos -= httpctx->z.avail_out;

                    if (((char *)lpvStatusInformation + dwStatusInformationLength) ==
                             (httpctx->zin.data() + httpctx->zin.size()))
                    {
                        httpctx->zin.clear();
                    }

                    if (t != Z_OK && (t != Z_STREAM_END || httpctx->z.avail_out))
                    {
                        httpio->cancel(req);
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                }
            }
            break;

        case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE:
        {
            DWORD statusCode;
            DWORD statusCodeSize = sizeof(statusCode);

            if (!WinHttpQueryHeaders(httpctx->hRequest,
                                     WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER,
                                     WINHTTP_HEADER_NAME_BY_INDEX,
                                     &statusCode,
                                     &statusCodeSize,
                                     WINHTTP_NO_HEADER_INDEX))
            {
                httpio->cancel(req);
                httpio->httpevent();
            }
            else
            {
                req->httpstatus = statusCode;

                if (!req->buf)
                {
                    // obtain original content length - always present if gzip is in use
                    DWORD contentLength;
                    DWORD contentLengthSize = sizeof(contentLength);

                    if (WinHttpQueryHeaders(httpctx->hRequest,
                                            WINHTTP_QUERY_CUSTOM | WINHTTP_QUERY_FLAG_NUMBER,
                                            L"Original-Content-Length",
                                            &contentLength,
                                            &contentLengthSize,
                                            WINHTTP_NO_HEADER_INDEX))
                    {
                        req->setcontentlength(contentLength);

                        // check for gzip content encoding
                        WCHAR contentEncoding[16];
                        DWORD contentEncodingSize = sizeof(contentEncoding);

                        httpctx->gzip = WinHttpQueryHeaders(httpctx->hRequest,
                                                WINHTTP_QUERY_CONTENT_ENCODING,
                                                WINHTTP_HEADER_NAME_BY_INDEX,
                                                &contentEncoding,
                                                &contentEncodingSize,
                                                WINHTTP_NO_HEADER_INDEX)
                                    && !wcscmp(contentEncoding, L"gzip");

                        if (httpctx->gzip)
                        {
                            httpctx->z.zalloc = Z_NULL;
                            httpctx->z.zfree = Z_NULL;
                            httpctx->z.opaque = Z_NULL;
                            httpctx->z.avail_in = 0;
                            httpctx->z.next_in = Z_NULL;

                            inflateInit2(&httpctx->z, MAX_WBITS+16);

                            req->in.resize(contentLength);
                            httpctx->z.avail_out = contentLength;
                            httpctx->z.next_out = (unsigned char*)req->in.data();
                        }
                    }
                }

                if (!WinHttpQueryDataAvailable(httpctx->hRequest, NULL))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                }
                else if (httpio->waiter && httpio->noinetds)
                {
                    httpio->inetstatus(true);
                }
            }

            break;
        }

        case WINHTTP_CALLBACK_STATUS_REQUEST_ERROR:
            if (httpio->waiter && GetLastError() != ERROR_WINHTTP_TIMEOUT)
            {
                httpio->inetstatus(false);
            }
            // fall through
        case WINHTTP_CALLBACK_STATUS_SECURE_FAILURE:
            httpio->cancel(req);
            httpio->httpevent();
            break;

        case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE:
        {
            PCCERT_CONTEXT cert;
            DWORD len = sizeof cert;

            if (WinHttpQueryOption(httpctx->hRequest, WINHTTP_OPTION_SERVER_CERT_CONTEXT, &cert, &len))
            {
                CRYPT_BIT_BLOB* pkey = &cert->pCertInfo->SubjectPublicKeyInfo.PublicKey;

                // this is an SSL connection: prevent MITM
                if (pkey->cbData != 270 || memcmp(pkey->pbData, "\x30\x82\x01\x0a\x02\x82\x01\x01"
                                                                "\x00\xb6\x61\xe7\xcf\x69\x2a\x84"
                                                                "\x35\x05\xc3\x14\xbc\x95\xcf\x94"
                                                                "\x33\x1c\x82\x67\x3b\x04\x35\x11"
                                                                "\xa0\x8d\xc8\x9d\xbb\x9c\x79\x65"
                                                                "\xe7\x10\xd9\x91\x80\xc7\x81\x0c"
                                                                "\xf4\x95\xbb\xb3\x26\x9b\x97\xd2"
                                                                "\x14\x0f\x0b\xca\xf0\x5e\x45\x7b"
                                                                "\x32\xc6\xa4\x7d\x7a\xfe\x11\xe7"
                                                                "\xb2\x5e\x21\x55\x23\x22\x1a\xca"
                                                                "\x1a\xf9\x21\xe1\x4e\xb7\x82\x0d"
                                                                "\xeb\x9d\xcb\x4e\x3d\x0b\xe4\xed"
                                                                "\x4a\xef\xe4\xab\x0c\xec\x09\x69"
                                                                "\xfe\xae\x43\xec\x19\x04\x3d\x5b"
                                                                "\x68\x0f\x67\xe8\x80\xff\x9b\x03"
                                                                "\xea\x50\xab\x16\xd7\xe0\x4c\xb4"
                                                                "\x42\xef\x31\xe2\x32\x9f\xe4\xd5"
                                                                "\xf4\xd8\xfd\x82\xcc\xc4\x50\xd9"
                                                                "\x4d\xb5\xfb\x6d\xa2\xf3\xaf\x37"
                                                                "\x67\x7f\x96\x4c\x54\x3d\x9b\x1c"
                                                                "\xbd\x5c\x31\x6d\x10\x43\xd8\x22"
                                                                "\x21\x01\x87\x63\x22\x89\x17\xca"
                                                                "\x92\xcb\xcb\xec\xe8\xc7\xff\x58"
                                                                "\xe8\x18\xc4\xce\x1b\xe5\x4f\x20"
                                                                "\xa8\xcf\xd3\xb9\x9d\x5a\x7a\x69"
                                                                "\xf2\xca\x48\xf8\x87\x95\x3a\x32"
                                                                "\x70\xb3\x1a\xf0\xc4\x45\x70\x43"
                                                                "\x58\x18\xda\x85\x29\x1d\xaf\x83"
                                                                "\xc2\x35\xa9\xc1\x73\x76\xb4\x47"
                                                                "\x22\x2b\x42\x9f\x93\x72\x3f\x9d"
                                                                "\x3d\xa1\x47\x3d\xb0\x46\x37\x1b"
                                                                "\xfd\x0e\x28\x68\xa0\xf6\x1d\x62"
                                                                "\xb2\xdc\x69\xc7\x9b\x09\x1e\xb5"
                                                                "\x47\x02\x03\x01\x00\x01",270))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                    break;
                }
            }
        }
        case WINHTTP_CALLBACK_STATUS_WRITE_COMPLETE:
            if (httpctx->postpos < httpctx->postlen)
            {
                unsigned pos = httpctx->postpos;
                unsigned t = httpctx->postlen - pos;

                if (t > HTTP_POST_CHUNK_SIZE)
                {
                    t = HTTP_POST_CHUNK_SIZE;
                }

                httpctx->postpos += t;

                if (!WinHttpWriteData(httpctx->hRequest, (LPVOID)(httpctx->postdata + pos), t, NULL))
                {
                    req->httpio->cancel(req);
                }

                httpio->httpevent();
            }
            else
            {
                if (!WinHttpReceiveResponse(httpctx->hRequest, NULL))
                {
                    httpio->cancel(req);
                    httpio->httpevent();
                }
            }
    }

    httpio->leavecs();
}

// POST request to URL
void WinHttpIO::post(HttpReq* req, const char* data, unsigned len)
{
    if (debug)
    {
        cout << "POST target URL: " << req->posturl << endl;

        if (req->binary)
        {
            cout << "[sending " << req->out->size() << " bytes of raw data]" << endl;
        }
        else
        {
            cout << "Sending: " << *req->out << endl;
        }
    }

    WinHttpContext* httpctx;

    WCHAR szURL[8192];
    WCHAR szHost[256];
    URL_COMPONENTS urlComp = { sizeof urlComp };

    urlComp.lpszHostName = szHost;
    urlComp.dwHostNameLength = sizeof szHost / sizeof *szHost;
    urlComp.dwUrlPathLength = (DWORD)-1;
    urlComp.dwSchemeLength = (DWORD)-1;

    httpctx = new WinHttpContext;

    httpctx->httpio = this;
    httpctx->req = req;
    httpctx->gzip = false;

    req->httpiohandle = (void*)httpctx;

    if (MultiByteToWideChar(CP_UTF8, 0, req->posturl.c_str(), -1, szURL,
                            sizeof szURL / sizeof *szURL)
            && WinHttpCrackUrl(szURL, 0, 0, &urlComp))
    {
        if ((httpctx->hConnect = WinHttpConnect(hSession, szHost, urlComp.nPort, 0)))
        {
            httpctx->hRequest = WinHttpOpenRequest(httpctx->hConnect, L"POST",
                                                   urlComp.lpszUrlPath, NULL,
                                                   WINHTTP_NO_REFERER,
                                                   WINHTTP_DEFAULT_ACCEPT_TYPES,
                                                   (urlComp.nScheme == INTERNET_SCHEME_HTTPS)
                                                   ? WINHTTP_FLAG_SECURE
                                                   : 0);

            if (httpctx->hRequest)
            {
                WinHttpSetTimeouts(httpctx->hRequest, 0, 20000, 20000, 1800000);

                WinHttpSetStatusCallback(httpctx->hRequest, asynccallback,
                                         WINHTTP_CALLBACK_FLAG_DATA_AVAILABLE
                                         | WINHTTP_CALLBACK_FLAG_READ_COMPLETE
                                         | WINHTTP_CALLBACK_FLAG_HEADERS_AVAILABLE
                                         | WINHTTP_CALLBACK_FLAG_REQUEST_ERROR
                                         | WINHTTP_CALLBACK_FLAG_SECURE_FAILURE
                                         | WINHTTP_CALLBACK_FLAG_SENDREQUEST_COMPLETE
                                         | WINHTTP_CALLBACK_FLAG_WRITE_COMPLETE
                                         | WINHTTP_CALLBACK_FLAG_HANDLES,
                                         0);

                LPCWSTR pwszHeaders = (req->type == REQ_JSON || !req->buf)
                                      ? L"Content-Type: application/json\r\nAccept-Encoding: gzip"
                                      : L"Content-Type: application/octet-stream";

                // data is sent in HTTP_POST_CHUNK_SIZE instalments to ensure
                // semi-smooth UI progress info
                httpctx->postlen = data ? len : req->out->size();
                httpctx->postdata = data ? data : req->out->data();
                httpctx->postpos = (urlComp.nPort == 80)
                                   ? ((httpctx->postlen < HTTP_POST_CHUNK_SIZE)
                                      ? httpctx->postlen
                                      : HTTP_POST_CHUNK_SIZE)
                                   : 0;

                if (WinHttpSendRequest(httpctx->hRequest, pwszHeaders,
                                       wcslen(pwszHeaders),
                                       (LPVOID)httpctx->postdata,
                                       httpctx->postpos,
                                       httpctx->postlen,
                                       (DWORD_PTR)httpctx))
                {
                    req->status = REQ_INFLIGHT;
                    return;
                }
            }
        }
        else
        {
            httpctx->hRequest = NULL;
        }
    }
    else
    {
        httpctx->hRequest = NULL;
        httpctx->hConnect = NULL;
    }

    req->status = REQ_FAILURE;
}

// cancel pending HTTP request
void WinHttpIO::cancel(HttpReq* req)
{
    WinHttpContext* httpctx;

    if ((httpctx = (WinHttpContext*)req->httpiohandle))
    {
        httpctx->req = NULL;

        req->httpstatus = 0;
        req->status = REQ_FAILURE;
        req->httpiohandle = NULL;

        if (httpctx->hConnect)
        {
            WinHttpCloseHandle(httpctx->hConnect);
        }

        if (httpctx->hRequest)
        {
            WinHttpCloseHandle(httpctx->hRequest);
        }
    }
}

// supply progress information on POST data
m_off_t WinHttpIO::postpos(void* handle)
{
    return ((WinHttpContext*)handle)->postpos;
}

// process events
bool WinHttpIO::doio()
{
    return false;
}
} // namespace
<|endoftext|>


<commit_before>/* <x0/server.hpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#ifndef sw_x0_server_hpp
#define sw_x0_server_hpp (1)

#include <x0/datetime.hpp>
#include <x0/settings.hpp>
#include <x0/logger.hpp>
#include <x0/listener.hpp>
#include <x0/handler.hpp>
#include <x0/context.hpp>
#include <x0/plugin.hpp>
#include <x0/types.hpp>
#include <x0/property.hpp>
#include <x0/fileinfo_service.hpp>
#include <x0/api.hpp>
#include <boost/signals.hpp>
#include <boost/asio/io_service.hpp>
#include <cstring>
#include <string>
#include <list>
#include <map>

namespace x0 {

class host_not_found
	: public std::runtime_error
{
public:
	host_not_found(const std::string& hostname)
		: std::runtime_error(hostname)
	{
	}
};

/**
 * \ingroup core
 * \brief implements the x0 web server.
 *
 * \see connection, request, response, plugin
 * \see server::run(), server::stop()
 */
class server :
	public boost::noncopyable
{
private:
	typedef std::pair<plugin_ptr, void *> plugin_value_t;
	typedef std::map<std::string, plugin_value_t> plugin_map_t;

public:
	server();
	~server();

	// {{{ service control
	/** configures this server as defined in the configuration section(s). */
	void configure(const std::string& configfile);
	/** starts this server object by listening on new connections and processing them. */
	void run();
	/** pauses an already active server by not accepting further new connections until resumed. */
	void pause();
	/** resumes a currently paused server by continueing processing new connections. */
	void resume();
	/** reloads server configuration */
	void reload();
	/** gracefully stops a running server */
	void stop();
	// }}}

	// {{{ signals raised on request in order
	/** is invoked once a new client connection is established */
	boost::signal<void(connection_ptr)> connection_open;

	/** is called at the very beginning of a request. */
	boost::signal<void(request&)> pre_process;

	/** resolves document_root to use for this request. */
	boost::signal<void(request&)> resolve_document_root;

	/** resolves request's physical filename (maps URI to physical path). */
	boost::signal<void(request&)> resolve_entity;

	/** generates response content for this request being processed. */
	handler generate_content;

	/** hook for generating accesslog logs and other things to be done after the request has been served. */
	boost::signal<void(request&, response&)> request_done;

	/** is called at the very end of a request. */
	boost::signal<void(request&, response&)> post_process;

	/** is called before a connection gets closed / or has been closed by remote point. */
	boost::signal<void(connection *)> connection_close;
	// }}}

	// {{{ context management
	/** create server context data for given plugin. */
	template<typename T>
	T& create_context(plugin *plug)
	{
		context_.set(plug, new T);
		return context_.get<T>(plug);
	}

	/** creates a virtual-host context for given plugin. */
	template<typename T>
	T& create_context(plugin *plug, const std::string& vhost)
	{
		vhosts_[vhost].set(plug, new T);
		return vhosts_[vhost].get<T>(plug);
	}

	/** retrieve the server configuration context. */
	x0::context& context()
	{
		return context_;
	}

	/** retrieve server context data for given plugin
	 * \param plug plugin data for which we want to retrieve the data for.
	 */
	template<typename T>
	T& context(plugin *plug)
	{
		return context_.get<T>(plug);
	}

	/** retrieve virtual-host context data for given plugin
	 * \param plug plugin data for which we want to retrieve the data for.
	 */
	template<typename T>
	T& context(plugin *plug, const std::string& vhostname)
	{
		auto vhost = vhosts_.find(vhostname);

		if (vhost == vhosts_.end())
			throw host_not_found(vhostname);

		auto data = vhost->second.find(plug);
		if (data != vhost->second.end())
			return *static_cast<T *>(data->second);

		vhost->second.set<T>(plug, new T);
		return vhost->second.get<T>(plug);
	}

	template<typename T>
	T *free_context(plugin *plug)
	{
		/// \todo free all contexts owned by given plugin
		return context_.free<T>(plug);
	}
	// }}}

	/**
	 * retrieves reference to server currently loaded configuration.
	 */
	x0::settings& config();

	/**
	 * writes a log entry into the server's error log.
	 */
	void log(severity s, const char *msg, ...);

	/**
	 * sets up a TCP/IP listener on given bind_address and port.
	 *
	 * If there is already a listener on this bind_address:port pair
	 * then no error will be raised.
	 */
	void setup_listener(int port, const std::string& bind_address = "0::0");

	/**
	 * loads a plugin into the server.
	 *
	 * \see plugin, unload_plugin(), loaded_plugins()
	 */
	void load_plugin(const std::string& name);

	/** safely unloads a plugin. */
	void unload_plugin(const std::string& name);

	/** retrieves a list of currently loaded plugins */
	std::vector<std::string> loaded_plugins() const;

	void handle_request(request& in, response& out);

	boost::asio::io_service& io_service();

	/** retrieves the current server time. */
	const datetime& now() const;

private:
	long long getrlimit(int resource);
	long long setrlimit(int resource, long long max);

	void drop_privileges(const std::string& user, const std::string& group);

	listener_ptr listener_by_port(int port);

private:
	x0::context context_;							//!< server context
	std::map<std::string, x0::context>	vhosts_;	//!< vhost contexts
	std::list<listener_ptr> listeners_;
	boost::asio::io_service io_service_;
	bool paused_;
	x0::settings settings_;
	std::string configfile_;
	logger_ptr logger_;
	plugin_map_t plugins_;
	datetime now_;

public:
	value_property<int> max_connections;
	value_property<int> max_keep_alive_requests;
	value_property<int> max_keep_alive_idle;
	value_property<int> max_read_idle;
	value_property<int> max_write_idle;
	value_property<std::string> tag;
	fileinfo_service fileinfo;

	property<unsigned long long> max_fds;
};

// {{{ inlines
inline boost::asio::io_service& server::io_service()
{
	return io_service_;
}

inline const x0::datetime& server::now() const
{
	return now_;
}
// }}}

} // namespace x0

#endif
// vim:syntax=cpp
<commit_msg>core: vhost contexts are shared_ptr managed now.<commit_after>/* <x0/server.hpp>
 *
 * This file is part of the x0 web server project and is released under LGPL-3.
 *
 * (c) 2009 Chrisitan Parpart <trapni@gentoo.org>
 */

#ifndef sw_x0_server_hpp
#define sw_x0_server_hpp (1)

#include <x0/datetime.hpp>
#include <x0/settings.hpp>
#include <x0/logger.hpp>
#include <x0/listener.hpp>
#include <x0/handler.hpp>
#include <x0/context.hpp>
#include <x0/plugin.hpp>
#include <x0/types.hpp>
#include <x0/property.hpp>
#include <x0/fileinfo_service.hpp>
#include <x0/api.hpp>
#include <boost/signals.hpp>
#include <boost/asio/io_service.hpp>
#include <cstring>
#include <string>
#include <list>
#include <map>

namespace x0 {

class host_not_found
	: public std::runtime_error
{
public:
	host_not_found(const std::string& hostname)
		: std::runtime_error(hostname)
	{
	}
};

/**
 * \ingroup core
 * \brief implements the x0 web server.
 *
 * \see connection, request, response, plugin
 * \see server::run(), server::stop()
 */
class server :
	public boost::noncopyable
{
private:
	typedef std::pair<plugin_ptr, void *> plugin_value_t;
	typedef std::map<std::string, plugin_value_t> plugin_map_t;

public:
	server();
	~server();

	// {{{ service control
	/** configures this server as defined in the configuration section(s). */
	void configure(const std::string& configfile);
	/** starts this server object by listening on new connections and processing them. */
	void run();
	/** pauses an already active server by not accepting further new connections until resumed. */
	void pause();
	/** resumes a currently paused server by continueing processing new connections. */
	void resume();
	/** reloads server configuration */
	void reload();
	/** gracefully stops a running server */
	void stop();
	// }}}

	// {{{ signals raised on request in order
	/** is invoked once a new client connection is established */
	boost::signal<void(connection_ptr)> connection_open;

	/** is called at the very beginning of a request. */
	boost::signal<void(request&)> pre_process;

	/** resolves document_root to use for this request. */
	boost::signal<void(request&)> resolve_document_root;

	/** resolves request's physical filename (maps URI to physical path). */
	boost::signal<void(request&)> resolve_entity;

	/** generates response content for this request being processed. */
	handler generate_content;

	/** hook for generating accesslog logs and other things to be done after the request has been served. */
	boost::signal<void(request&, response&)> request_done;

	/** is called at the very end of a request. */
	boost::signal<void(request&, response&)> post_process;

	/** is called before a connection gets closed / or has been closed by remote point. */
	boost::signal<void(connection *)> connection_close;
	// }}}

	// {{{ context management
	/** create server context data for given plugin. */
	template<typename T>
	T& create_context(plugin *plug)
	{
		context_.set(plug, new T);
		return context_.get<T>(plug);
	}

	/** creates a virtual-host context for given plugin. */
	template<typename T>
	T& create_context(plugin *plug, const std::string& vhost)
	{
		auto i = vhosts_.find(vhost);
		if (i == vhosts_.end())
			vhosts_[vhost] = std::shared_ptr<x0::context>(new x0::context);

		vhosts_[vhost]->set(plug, new T);

		return vhosts_[vhost]->get<T>(plug);
	}

	void link_context(const std::string& master, const std::string& alias)
	{
		vhosts_[alias] = vhosts_[master];
	}

	/** retrieve the server configuration context. */
	x0::context& context()
	{
		return context_;
	}

	/** retrieve server context data for given plugin
	 * \param plug plugin data for which we want to retrieve the data for.
	 */
	template<typename T>
	T& context(plugin *plug)
	{
		return context_.get<T>(plug);
	}

	/** retrieve virtual-host context data for given plugin
	 * \param plug plugin data for which we want to retrieve the data for.
	 */
	template<typename T>
	T& context(plugin *plug, const std::string& vhostname)
	{
		auto vhost = vhosts_.find(vhostname);

		if (vhost == vhosts_.end())
			throw host_not_found(vhostname);

		auto ctx = *vhost->second;
		auto data = ctx.find(plug);
		if (data != ctx.end())
			return *static_cast<T *>(data->second);

		ctx.set<T>(plug, new T);
		return ctx.get<T>(plug);
	}

	template<typename T>
	T *free_context(plugin *plug)
	{
		/// \todo free all contexts owned by given plugin
		return context_.free<T>(plug);
	}
	// }}}

	/**
	 * retrieves reference to server currently loaded configuration.
	 */
	x0::settings& config();

	/**
	 * writes a log entry into the server's error log.
	 */
	void log(severity s, const char *msg, ...);

	/**
	 * sets up a TCP/IP listener on given bind_address and port.
	 *
	 * If there is already a listener on this bind_address:port pair
	 * then no error will be raised.
	 */
	void setup_listener(int port, const std::string& bind_address = "0::0");

	/**
	 * loads a plugin into the server.
	 *
	 * \see plugin, unload_plugin(), loaded_plugins()
	 */
	void load_plugin(const std::string& name);

	/** safely unloads a plugin. */
	void unload_plugin(const std::string& name);

	/** retrieves a list of currently loaded plugins */
	std::vector<std::string> loaded_plugins() const;

	void handle_request(request& in, response& out);

	boost::asio::io_service& io_service();

	/** retrieves the current server time. */
	const datetime& now() const;

private:
	long long getrlimit(int resource);
	long long setrlimit(int resource, long long max);

	void drop_privileges(const std::string& user, const std::string& group);

	listener_ptr listener_by_port(int port);

private:
	x0::context context_;											//!< server context
	std::map<std::string, std::shared_ptr<x0::context>> vhosts_;	//!< vhost contexts
	std::list<listener_ptr> listeners_;
	boost::asio::io_service io_service_;
	bool paused_;
	x0::settings settings_;
	std::string configfile_;
	logger_ptr logger_;
	plugin_map_t plugins_;
	datetime now_;

public:
	value_property<int> max_connections;
	value_property<int> max_keep_alive_requests;
	value_property<int> max_keep_alive_idle;
	value_property<int> max_read_idle;
	value_property<int> max_write_idle;
	value_property<std::string> tag;
	fileinfo_service fileinfo;

	property<unsigned long long> max_fds;
};

// {{{ inlines
inline boost::asio::io_service& server::io_service()
{
	return io_service_;
}

inline const x0::datetime& server::now() const
{
	return now_;
}
// }}}

} // namespace x0

#endif
// vim:syntax=cpp
<|endoftext|>


<commit_before>/**
 * @file
 */
#include "libbirch/Label.hpp"

libbirch::Label::Label() : Any(0) {
  //
}

libbirch::Label::Label(const Label& o) :
    Any(o) {
  auto& o1 = const_cast<Label&>(o);
  o1.lock.write();
  o1.memo.rehash();
  o1.lock.downgrade();
  memo.copy(o1.memo);
  o1.lock.unread();
}

libbirch::Any* libbirch::Label::mapGet(Any* o) {
  Any* prev = nullptr;
  Any* next = o;
  bool frozen = o->isFrozen();
  while (frozen && next) {
    prev = next;
    next = memo.get(prev);
    if (next) {
      frozen = next->isFrozen();
    }
  }
  if (!next) {
	  next = prev;
	}
  if (frozen) {
    assert(!next->isDestroyed());
    Any* cloned;
    if (false && next->isUnique()) {
      /* final-reference optimization: the pointer being updated is the final
       * remaining pointer to the object, rather than copying the object and
       * then destroying it, recycle the object to be the copy */
      cloned = next->recycle(this);
    } else {
      /* copy the object */
      cloned = next->copy(this);

      /* single-reference optimization: at the time of freezing, if there was
       * only one reference to the object, it need not be memoized, as there
       * are no other pointers to update to the copy */
      if (true || !next->isFrozenUnique()) {
        memo.put(next, cloned);
        thaw();
      }
    }
    next = cloned;
  }
  return next;
}

libbirch::Any* libbirch::Label::mapPull(Any* o) {
  Any* prev = nullptr;
  Any* next = o;
  bool frozen = o->isFrozen();
  while (frozen && next) {
    prev = next;
    next = memo.get(prev);
    if (next) {
      frozen = next->isFrozen();
    }
  }
  if (!next) {
	  next = prev;
	}
  return next;
}
<commit_msg>Restored final-reference and single-reference optimizations (previously removed for debugging).<commit_after>/**
 * @file
 */
#include "libbirch/Label.hpp"

libbirch::Label::Label() : Any(0) {
  //
}

libbirch::Label::Label(const Label& o) :
    Any(o) {
  auto& o1 = const_cast<Label&>(o);
  o1.lock.write();
  o1.memo.rehash();
  o1.lock.downgrade();
  memo.copy(o1.memo);
  o1.lock.unread();
}

libbirch::Any* libbirch::Label::mapGet(Any* o) {
  Any* prev = nullptr;
  Any* next = o;
  bool frozen = o->isFrozen();
  while (frozen && next) {
    prev = next;
    next = memo.get(prev);
    if (next) {
      frozen = next->isFrozen();
    }
  }
  if (!next) {
	  next = prev;
	}
  if (frozen) {
    assert(!next->isDestroyed());
    Any* cloned;
    if (next->isUnique()) {
      /* final-reference optimization: the pointer being updated is the final
       * remaining pointer to the object, rather than copying the object and
       * then destroying it, recycle the object to be the copy */
      cloned = next->recycle(this);
    } else {
      /* copy the object */
      cloned = next->copy(this);

      /* single-reference optimization: at the time of freezing, if there was
       * only one reference to the object, it need not be memoized, as there
       * are no other pointers to update to the copy */
      if (!next->isFrozenUnique()) {
        memo.put(next, cloned);
        thaw();
      }
    }
    next = cloned;
  }
  return next;
}

libbirch::Any* libbirch::Label::mapPull(Any* o) {
  Any* prev = nullptr;
  Any* next = o;
  bool frozen = o->isFrozen();
  while (frozen && next) {
    prev = next;
    next = memo.get(prev);
    if (next) {
      frozen = next->isFrozen();
    }
  }
  if (!next) {
	  next = prev;
	}
  return next;
}
<|endoftext|>


<commit_before>#include "ymlparser.h"
#include <QDebug>

YMLParser::YMLParser()
{
}

void YMLParser::writeItem(cv::FileStorage &fs, ObjectRect* obj)
{
    // Write class name
    switch(obj->getType())
    {
    case ObjectType::Face:
        fs << "className" << "Face";
        break;
    case ObjectType::NumberPlate:
        fs << "className" << "NumberPlate";
        break;
    case ObjectType::ToBlur:
        fs << "className" << "ToBlur";
        break;
    case ObjectType::None:
        fs << "className" << "None";
        break;
    }

    // Write class name
    switch(obj->getSubType())
    {
    case ObjectSubType::None:
        fs << "subClassName" << "None";
        break;
    case ObjectSubType::Front:
        fs << "subClassName" << "Front";
        break;
    case ObjectSubType::Profile:
        fs << "subClassName" << "Profile";
        break;
    }

    // Write square area coodinates
    fs << "area" << "{";
        fs << "p1" << cv::Point2d(obj->proj_point_1().x(), obj->proj_point_1().y());
        fs << "p2" << cv::Point2d(obj->proj_point_2().x(), obj->proj_point_2().y());
        fs << "p3" << cv::Point2d(obj->proj_point_3().x(), obj->proj_point_3().y());
        fs << "p4" << cv::Point2d(obj->proj_point_4().x(), obj->proj_point_4().y());
    fs << "}";

    // Write params
    fs << "params" << "{";
        fs << "azimuth" << obj->proj_azimuth();
        fs << "elevation" << obj->proj_elevation();
        fs << "aperture" << obj->proj_aperture();
        fs << "width" << obj->proj_width();
        fs << "height" << obj->proj_height();
    fs << "}";

    // Write status tags
    fs << "autoStatus" << obj->getAutomaticStatus().toStdString();
    fs << "manualStatus" << obj->getManualStatus().toStdString();
}

ObjectRect* YMLParser::readItem(cv::FileNodeIterator iterator, int ymltype)
{
    // Initialize detected object
    ObjectRect* object = new ObjectRect;

    // Parse falsePositive tag
    std::string falsePositive;
    (*iterator)["falsePositive"] >> falsePositive;
    QString lowerFalsePositive = QString( falsePositive.c_str() ).toLower();

    // Parse class name
    std::string className;
    (*iterator)["className"] >> className;

    // Parse sub class name
    std::string subClassName;
    (*iterator)["subClassName"] >> subClassName;

    QString lowerClassName = QString( className.c_str() ).toLower();
    QString lowerSubClassName = QString( subClassName.c_str() ).toLower();

    if(lowerClassName == "face")
    {
        object->setType( ObjectType::Face );
    } else if (lowerClassName == "front" || lowerClassName == "front:profile"){
        object->setType( ObjectType::Face );
        object->setSubType( ObjectSubType::Front );
    } else if (lowerClassName == "profile"){
        object->setType( ObjectType::Face );
        object->setSubType( ObjectSubType::Profile );
    } else if(lowerClassName == "numberplate") {
        object->setType( ObjectType::NumberPlate );
    } else if(lowerClassName == "toblur") {
        object->setType( ObjectType::ToBlur );
    } else if(lowerClassName == "none") {
        object->setType( ObjectType::None );
    }

    if(lowerSubClassName == "none")
    {
        object->setSubType( ObjectSubType::None );
    } else if(lowerSubClassName == "front") {
        object->setSubType( ObjectSubType::Front );
    } else if(lowerSubClassName == "profile") {
        object->setSubType( ObjectSubType::Profile );
    }

    // Parse area points
    cv::FileNode areaNode = (*iterator)["area"];
    cv::Point2d pt_1;
    cv::Point2d pt_2;
    cv::Point2d pt_3;
    cv::Point2d pt_4;

    switch(ymltype)
    {
    case YMLType::Detector:
        areaNode["p1"] >> pt_1;
        areaNode["p2"] >> pt_3;
        break;
    case YMLType::Validator:
        areaNode["p1"] >> pt_1;
        areaNode["p2"] >> pt_2;
        areaNode["p3"] >> pt_3;
        areaNode["p4"] >> pt_4;
        break;
    }

    object->setPoints(QPointF(pt_1.x, pt_1.y),
                      QPointF(pt_2.x, pt_2.y),
                      QPointF(pt_3.x, pt_3.y),
                      QPointF(pt_4.x, pt_4.y));

    // Parse gnomonic params
    cv::FileNode paramsNode = (*iterator)["params"];
    float azimuth = 0.0;
    float elevation = 0.0;
    float aperture = 0.0;
    float width = 0.0;
    float height = 0.0;

    paramsNode["azimuth"] >> azimuth;
    paramsNode["elevation"] >> elevation;
    paramsNode["aperture"] >> aperture;
    paramsNode["width"] >> width;
    paramsNode["height"] >> height;

    object->setProjectionParametters(azimuth,
                                    elevation,
                                    aperture,
                                    width,
                                    height);

    object->setProjectionParametters(azimuth, elevation, aperture, width, height);
    object->setProjectionPoints();

    // Parse auto status
    std::string autoStatus;
    (*iterator)["autoStatus"] >> autoStatus;

    QString lowerAutoStatus = QString( autoStatus.c_str() ).toLower();
    lowerAutoStatus = lowerAutoStatus.length() > 0 ? lowerAutoStatus : "none";

    if(lowerAutoStatus != "none")
    {
        if(lowerAutoStatus == "valid")
        {
            object->setObjectRectType( ObjectRectType::Valid );
            object->setAutomaticStatus( "Valid" );
        } else {
            object->setObjectRectType( ObjectRectType::Invalid );

            switch(ymltype)
            {
            case YMLType::Detector:
                if( lowerAutoStatus == "filtered-ratio" )
                {
                   object->setAutomaticStatus( "Ratio" );
                } else if( lowerAutoStatus == "filtered-size" ){
                   object->setAutomaticStatus( "Size" );
                } else if( lowerAutoStatus == "filtered-ratio-size" ){
                    object->setAutomaticStatus( "Ratio-Size" );
                }
                break;
            case YMLType::Validator:
                if( lowerAutoStatus == "ratio" )
                {
                   object->setAutomaticStatus( "Ratio" );
                } else if( lowerAutoStatus == "size" ){
                   object->setAutomaticStatus( "Size" );
                } else if( lowerAutoStatus == "ratio-size" ){
                    object->setAutomaticStatus( "Ratio-Size" );
                } else if( lowerAutoStatus == "missingoption" ){
                    object->setAutomaticStatus( "MissingOption" );
                }
                break;
            }
        }
    } else {
        object->setObjectRectType( ObjectRectType::Manual );
    }

    object->setAutomaticStatus( (object->getAutomaticStatus().length() > 0 ? object->getAutomaticStatus() : "None") );

    // Parse manual status
    std::string manualStatus;
    (*iterator)["manualStatus"] >> manualStatus;
    object->setManualStatus( QString(manualStatus.c_str()) );
    object->setManualStatus( (object->getManualStatus().length() > 0 ? object->getManualStatus() : "None") );

    if(lowerFalsePositive == "no")
    {
        if(lowerAutoStatus == "none")
        {
            object->setManualStatus("Valid");
        }
    } else if( lowerFalsePositive == "yes" )
    {
        object->setManualStatus("Invalid");
    }

    if(object->getType() == ObjectType::ToBlur)
    {
        object->setObjectRectState( ObjectRectState::ToBlur );
    } else {

        if(object->getManualStatus() != "None")
        {
            if(object->getManualStatus() == "Valid")
            {
                object->setObjectRectState( ObjectRectState::Valid );
            } else {
                object->setObjectRectState( ObjectRectState::Invalid );
            }
        } else {
            object->setObjectRectState( ObjectRectState::None );
        }

    }

    cv::FileNode childNode = (*iterator)["childrens"];
    for (cv::FileNodeIterator child = childNode.begin(); child != childNode.end(); ++child) {
        object->childrens.append( this->readItem( child ) );
    }

    object->setResizeEnabled( false );

    // Return object
    return object;
}

void YMLParser::writeYML(QList<ObjectRect*> objects, QString path)
{
    // Open storage for writing
    cv::FileStorage fs(path.toStdString(), cv::FileStorage::WRITE);

    // Write source file path
    fs << "source_image" << objects.first()->getSourceImagePath().toStdString();

    // Write objects
    fs << "objects" << "[";

    // Iterate over objects
    foreach (ObjectRect* obj, objects) {

        // Open array element
        fs << "{";

        // Object writer method
        this->writeItem(fs, obj);

        // Write childrens if present
        if(obj->childrens.length() > 0)
        {
            fs << "childrens" << "[";
            foreach (ObjectRect* child, obj->childrens) {
                fs << "{";
                this->writeItem(fs, child);
                fs << "}";
            }
            fs << "]";
        }

        // Close array element
        fs << "}";
    }

    // Close array
    fs << "]";
}

QList<ObjectRect*> YMLParser::loadYML(QString path, int ymltype)
{
    // Init output list
    QList<ObjectRect*> out_list;

    // Read YML file
    cv::FileStorage fs(path.toStdString(), cv::FileStorage::READ);

    // Retrieve objects node
    cv::FileNode objectsNode = fs["objects"];

    // Retrieve invalid objects node
    cv::FileNode invalidObjectsNode = fs["invalidObjects"];

    // Iterate over objects
    for (cv::FileNodeIterator it = objectsNode.begin(); it != objectsNode.end(); ++it) {

        // Initialize detected object
        ObjectRect* object = this->readItem(it, ymltype);

        std::string source_image;
        fs["source_image"] >> source_image;

        object->setSourceImagePath( QString(source_image.c_str()) );

        // Append to list
        out_list.append(object);
    }

    // Iterate over objects
    for (cv::FileNodeIterator it = invalidObjectsNode.begin(); it != invalidObjectsNode.end(); ++it) {

        // Initialize detected object
        ObjectRect* object = this->readItem(it, ymltype);

        object->setObjectRectType( ObjectRectType::Invalid );
        object->setAutomaticStatus( (object->getAutomaticStatus().length() <= 0 || object->getAutomaticStatus() == "None") ? "MissingOption" : object->getAutomaticStatus() );

        std::string source_image;
        fs["source_image"] >> source_image;

        object->setSourceImagePath( QString(source_image.c_str()) );

        // Append to list
        out_list.append(object);
    }

    // Return results
    return out_list;
}

<commit_msg>Added blurObject tag save/load<commit_after>#include "ymlparser.h"
#include <QDebug>

YMLParser::YMLParser()
{
}

void YMLParser::writeItem(cv::FileStorage &fs, ObjectRect* obj)
{
    // Write class name
    switch(obj->getType())
    {
    case ObjectType::Face:
        fs << "className" << "Face";
        break;
    case ObjectType::NumberPlate:
        fs << "className" << "NumberPlate";
        break;
    case ObjectType::ToBlur:
        fs << "className" << "ToBlur";
        break;
    case ObjectType::None:
        fs << "className" << "None";
        break;
    }

    // Write class name
    switch(obj->getSubType())
    {
    case ObjectSubType::None:
        fs << "subClassName" << "None";
        break;
    case ObjectSubType::Front:
        fs << "subClassName" << "Front";
        break;
    case ObjectSubType::Profile:
        fs << "subClassName" << "Profile";
        break;
    }

    // Write square area coodinates
    fs << "area" << "{";
        fs << "p1" << cv::Point2d(obj->proj_point_1().x(), obj->proj_point_1().y());
        fs << "p2" << cv::Point2d(obj->proj_point_2().x(), obj->proj_point_2().y());
        fs << "p3" << cv::Point2d(obj->proj_point_3().x(), obj->proj_point_3().y());
        fs << "p4" << cv::Point2d(obj->proj_point_4().x(), obj->proj_point_4().y());
    fs << "}";

    // Write params
    fs << "params" << "{";
        fs << "azimuth" << obj->proj_azimuth();
        fs << "elevation" << obj->proj_elevation();
        fs << "aperture" << obj->proj_aperture();
        fs << "width" << obj->proj_width();
        fs << "height" << obj->proj_height();
    fs << "}";

    // Write status tags
    fs << "autoStatus" << obj->getAutomaticStatus().toStdString();
    fs << "manualStatus" << obj->getManualStatus().toStdString();
    fs << "blurObject" << (obj->isBlurred() ? "Yes" : "No");
}

ObjectRect* YMLParser::readItem(cv::FileNodeIterator iterator, int ymltype)
{
    // Initialize detected object
    ObjectRect* object = new ObjectRect;

    // Parse falsePositive tag
    std::string falsePositive;
    (*iterator)["falsePositive"] >> falsePositive;
    QString lowerFalsePositive = QString( falsePositive.c_str() ).toLower();

    // Parse class name
    std::string className;
    (*iterator)["className"] >> className;

    // Parse sub class name
    std::string subClassName;
    (*iterator)["subClassName"] >> subClassName;

    QString lowerClassName = QString( className.c_str() ).toLower();
    QString lowerSubClassName = QString( subClassName.c_str() ).toLower();

    if(lowerClassName == "face")
    {
        object->setType( ObjectType::Face );
    } else if (lowerClassName == "front" || lowerClassName == "front:profile"){
        object->setType( ObjectType::Face );
        object->setSubType( ObjectSubType::Front );
    } else if (lowerClassName == "profile"){
        object->setType( ObjectType::Face );
        object->setSubType( ObjectSubType::Profile );
    } else if(lowerClassName == "numberplate") {
        object->setType( ObjectType::NumberPlate );
    } else if(lowerClassName == "toblur") {
        object->setType( ObjectType::ToBlur );
    } else if(lowerClassName == "none") {
        object->setType( ObjectType::None );
    }

    if(lowerSubClassName == "none")
    {
        object->setSubType( ObjectSubType::None );
    } else if(lowerSubClassName == "front") {
        object->setSubType( ObjectSubType::Front );
    } else if(lowerSubClassName == "profile") {
        object->setSubType( ObjectSubType::Profile );
    }

    // Parse area points
    cv::FileNode areaNode = (*iterator)["area"];
    cv::Point2d pt_1;
    cv::Point2d pt_2;
    cv::Point2d pt_3;
    cv::Point2d pt_4;

    switch(ymltype)
    {
    case YMLType::Detector:
        areaNode["p1"] >> pt_1;
        areaNode["p2"] >> pt_3;
        break;
    case YMLType::Validator:
        areaNode["p1"] >> pt_1;
        areaNode["p2"] >> pt_2;
        areaNode["p3"] >> pt_3;
        areaNode["p4"] >> pt_4;
        break;
    }

    object->setPoints(QPointF(pt_1.x, pt_1.y),
                      QPointF(pt_2.x, pt_2.y),
                      QPointF(pt_3.x, pt_3.y),
                      QPointF(pt_4.x, pt_4.y));

    // Parse gnomonic params
    cv::FileNode paramsNode = (*iterator)["params"];
    float azimuth = 0.0;
    float elevation = 0.0;
    float aperture = 0.0;
    float width = 0.0;
    float height = 0.0;

    paramsNode["azimuth"] >> azimuth;
    paramsNode["elevation"] >> elevation;
    paramsNode["aperture"] >> aperture;
    paramsNode["width"] >> width;
    paramsNode["height"] >> height;

    object->setProjectionParametters(azimuth,
                                    elevation,
                                    aperture,
                                    width,
                                    height);

    object->setProjectionParametters(azimuth, elevation, aperture, width, height);
    object->setProjectionPoints();

    // Parse auto status
    std::string autoStatus;
    (*iterator)["autoStatus"] >> autoStatus;

    QString lowerAutoStatus = QString( autoStatus.c_str() ).toLower();
    lowerAutoStatus = lowerAutoStatus.length() > 0 ? lowerAutoStatus : "none";

    if(lowerAutoStatus != "none")
    {
        if(lowerAutoStatus == "valid")
        {
            object->setObjectRectType( ObjectRectType::Valid );
            object->setAutomaticStatus( "Valid" );
        } else {
            object->setObjectRectType( ObjectRectType::Invalid );

            switch(ymltype)
            {
            case YMLType::Detector:
                if( lowerAutoStatus == "filtered-ratio" )
                {
                   object->setAutomaticStatus( "Ratio" );
                } else if( lowerAutoStatus == "filtered-size" ){
                   object->setAutomaticStatus( "Size" );
                } else if( lowerAutoStatus == "filtered-ratio-size" ){
                    object->setAutomaticStatus( "Ratio-Size" );
                }
                break;
            case YMLType::Validator:
                if( lowerAutoStatus == "ratio" )
                {
                   object->setAutomaticStatus( "Ratio" );
                } else if( lowerAutoStatus == "size" ){
                   object->setAutomaticStatus( "Size" );
                } else if( lowerAutoStatus == "ratio-size" ){
                    object->setAutomaticStatus( "Ratio-Size" );
                } else if( lowerAutoStatus == "missingoption" ){
                    object->setAutomaticStatus( "MissingOption" );
                }
                break;
            }
        }
    } else {
        object->setObjectRectType( ObjectRectType::Manual );
    }

    object->setAutomaticStatus( (object->getAutomaticStatus().length() > 0 ? object->getAutomaticStatus() : "None") );

    // Parse manual status
    std::string manualStatus;
    (*iterator)["manualStatus"] >> manualStatus;
    object->setManualStatus( QString(manualStatus.c_str()) );
    object->setManualStatus( (object->getManualStatus().length() > 0 ? object->getManualStatus() : "None") );

    if(lowerFalsePositive == "no")
    {
        if(lowerAutoStatus == "none")
        {
            object->setManualStatus("Valid");
        }
    } else if( lowerFalsePositive == "yes" )
    {
        object->setManualStatus("Invalid");
    }

    if(object->getType() == ObjectType::ToBlur)
    {
        object->setObjectRectState( ObjectRectState::ToBlur );
    } else {

        if(object->getManualStatus() != "None")
        {
            if(object->getManualStatus() == "Valid")
            {
                object->setObjectRectState( ObjectRectState::Valid );
            } else {
                object->setObjectRectState( ObjectRectState::Invalid );
            }
        } else {
            object->setObjectRectState( ObjectRectState::None );
        }

    }

    std::string blurObject;
    (*iterator)["blurObject"] >> blurObject;

    QString blurObject_lower = QString( blurObject.c_str() ).toLower();

    object->setBlurred( blurObject_lower == "yes" ? true : false );

    cv::FileNode childNode = (*iterator)["childrens"];
    for (cv::FileNodeIterator child = childNode.begin(); child != childNode.end(); ++child) {
        object->childrens.append( this->readItem( child ) );
    }

    object->setResizeEnabled( false );

    // Return object
    return object;
}

void YMLParser::writeYML(QList<ObjectRect*> objects, QString path)
{
    // Open storage for writing
    cv::FileStorage fs(path.toStdString(), cv::FileStorage::WRITE);

    // Write source file path
    fs << "source_image" << objects.first()->getSourceImagePath().toStdString();

    // Write objects
    fs << "objects" << "[";

    // Iterate over objects
    foreach (ObjectRect* obj, objects) {

        // Open array element
        fs << "{";

        // Object writer method
        this->writeItem(fs, obj);

        // Write childrens if present
        if(obj->childrens.length() > 0)
        {
            fs << "childrens" << "[";
            foreach (ObjectRect* child, obj->childrens) {
                fs << "{";
                this->writeItem(fs, child);
                fs << "}";
            }
            fs << "]";
        }

        // Close array element
        fs << "}";
    }

    // Close array
    fs << "]";
}

QList<ObjectRect*> YMLParser::loadYML(QString path, int ymltype)
{
    // Init output list
    QList<ObjectRect*> out_list;

    // Read YML file
    cv::FileStorage fs(path.toStdString(), cv::FileStorage::READ);

    // Retrieve objects node
    cv::FileNode objectsNode = fs["objects"];

    // Retrieve invalid objects node
    cv::FileNode invalidObjectsNode = fs["invalidObjects"];

    // Iterate over objects
    for (cv::FileNodeIterator it = objectsNode.begin(); it != objectsNode.end(); ++it) {

        // Initialize detected object
        ObjectRect* object = this->readItem(it, ymltype);

        std::string source_image;
        fs["source_image"] >> source_image;

        object->setSourceImagePath( QString(source_image.c_str()) );

        // Append to list
        out_list.append(object);
    }

    // Iterate over objects
    for (cv::FileNodeIterator it = invalidObjectsNode.begin(); it != invalidObjectsNode.end(); ++it) {

        // Initialize detected object
        ObjectRect* object = this->readItem(it, ymltype);

        object->setObjectRectType( ObjectRectType::Invalid );
        object->setAutomaticStatus( (object->getAutomaticStatus().length() <= 0 || object->getAutomaticStatus() == "None") ? "MissingOption" : object->getAutomaticStatus() );

        std::string source_image;
        fs["source_image"] >> source_image;

        object->setSourceImagePath( QString(source_image.c_str()) );

        // Append to list
        out_list.append(object);
    }

    // Return results
    return out_list;
}

<|endoftext|>


<commit_before>#include <rai/cli/daemon.hpp>

#include <rai/working.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <fstream>
#include <thread>

rai_daemon::daemon_config::daemon_config () :
rpc_enable (false)
{
}

void rai_daemon::daemon_config::serialize (std::ostream & output_a)
{
    boost::property_tree::ptree tree;
	tree.put ("rpc_enable", rpc_enable);
	boost::property_tree::ptree rpc_l;
	rpc.serialize_json (rpc_l);
	tree.add_child ("rpc", rpc_l);
	boost::property_tree::ptree node_l;
	node.serialize_json (node_l);
	tree.add_child ("node", node_l);
    boost::property_tree::write_json (output_a, tree);
}

rai_daemon::daemon_config::daemon_config (bool & error_a, std::istream & input_a)
{
    error_a = false;
    boost::property_tree::ptree tree;
	try
	{
		rpc_enable = tree.get <bool> ("rpc_enable");
		boost::property_tree::read_json (input_a, tree);
		auto node_l (tree.get_child ("node"));
		error_a = error_a || node.deserialize_json (node_l);
		auto rpc_l (tree.get_child ("rpc"));
		error_a = error_a || node.deserialize_json (rpc_l);
	}
	catch (std::runtime_error const &)
	{
		error_a = true;
	}
}

void rai_daemon::daemon::run ()
{
    auto working (rai::working_path ());
	boost::filesystem::create_directories (working);
    auto config_error (false);
    rai_daemon::daemon_config config;
    auto config_path ((working / "config.json").string ());
    std::ifstream config_file;
    config_file.open (config_path);
    if (!config_file.fail ())
    {
        config = rai_daemon::daemon_config (config_error, config_file);
    }
    else
    {
        std::ofstream config_file;
        config_file.open (config_path);
        if (!config_file.fail ())
        {
            config.serialize (config_file);
        }
    }
    if (!config_error)
    {
        auto service (boost::make_shared <boost::asio::io_service> ());
        auto pool (boost::make_shared <boost::network::utils::thread_pool> ());
        rai::processor_service processor;
        rai::node_init init;
        auto node (std::make_shared <rai::node> (init, service, working, processor, config.node));
        if (!init.error ())
        {
            node->start ();
            rai::rpc rpc (service, pool, *node, config.rpc);
            if (config.rpc_enable)
            {
                rpc.start ();
            }
            std::thread network_thread ([&service] ()
                {
                    try
                    {
                        service->run ();
                    }
                    catch (...)
                    {
                        assert (false);
                    }
                });
            std::thread processor_thread ([&processor] ()
                {
                    try
                    {
                        processor.run ();
                    }
                    catch (...)
                    {
                        assert (false);
                    }
                });
            network_thread.join ();
            processor_thread.join ();
        }
        else
        {
            std::cerr << "Error initializing node\n";
        }
    }
    else
    {
        std::cerr << "Error loading configuration\n";
    }
}
<commit_msg>Deserializing config correctly.<commit_after>#include <rai/cli/daemon.hpp>

#include <rai/working.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <iostream>
#include <fstream>
#include <thread>

rai_daemon::daemon_config::daemon_config () :
rpc_enable (false)
{
}

void rai_daemon::daemon_config::serialize (std::ostream & output_a)
{
    boost::property_tree::ptree tree;
	tree.put ("rpc_enable", rpc_enable);
	boost::property_tree::ptree rpc_l;
	rpc.serialize_json (rpc_l);
	tree.add_child ("rpc", rpc_l);
	boost::property_tree::ptree node_l;
	node.serialize_json (node_l);
	tree.add_child ("node", node_l);
    boost::property_tree::write_json (output_a, tree);
}

rai_daemon::daemon_config::daemon_config (bool & error_a, std::istream & input_a)
{
    error_a = false;
    boost::property_tree::ptree tree;
	try
	{
        boost::property_tree::read_json (input_a, tree);
		rpc_enable = tree.get <bool> ("rpc_enable");
		auto node_l (tree.get_child ("node"));
		error_a = error_a || node.deserialize_json (node_l);
		auto rpc_l (tree.get_child ("rpc"));
		error_a = error_a || rpc.deserialize_json (rpc_l);
	}
	catch (std::runtime_error const &)
	{
		error_a = true;
	}
}

void rai_daemon::daemon::run ()
{
    auto working (rai::working_path ());
	boost::filesystem::create_directories (working);
    auto config_error (false);
    rai_daemon::daemon_config config;
    auto config_path ((working / "config.json").string ());
    std::ifstream config_file;
    config_file.open (config_path);
    if (!config_file.fail ())
    {
        config = rai_daemon::daemon_config (config_error, config_file);
    }
    else
    {
        std::ofstream config_file;
        config_file.open (config_path);
        if (!config_file.fail ())
        {
            config.serialize (config_file);
        }
    }
    if (!config_error)
    {
        auto service (boost::make_shared <boost::asio::io_service> ());
        auto pool (boost::make_shared <boost::network::utils::thread_pool> ());
        rai::processor_service processor;
        rai::node_init init;
        auto node (std::make_shared <rai::node> (init, service, working, processor, config.node));
        if (!init.error ())
        {
            node->start ();
            rai::rpc rpc (service, pool, *node, config.rpc);
            if (config.rpc_enable)
            {
                rpc.start ();
            }
            std::thread network_thread ([&service] ()
                {
                    try
                    {
                        service->run ();
                    }
                    catch (...)
                    {
                        assert (false);
                    }
                });
            std::thread processor_thread ([&processor] ()
                {
                    try
                    {
                        processor.run ();
                    }
                    catch (...)
                    {
                        assert (false);
                    }
                });
            network_thread.join ();
            processor_thread.join ();
        }
        else
        {
            std::cerr << "Error initializing node\n";
        }
    }
    else
    {
        std::cerr << "Error loading configuration\n";
    }
}
<|endoftext|>


<commit_before>// Random access pseudorandom permutations

#include <other/core/random/permute.h>
#include <other/core/random/counter.h>
#include <other/core/math/integer_log.h>
#include <other/core/python/module.h>
namespace other {

// For details, see
//   John Black and Phillip Rogaway, Ciphers with Arbitrary Finite Domains.
//   Mihir Bellare, Thomas Ristenpart, Phillip Rogaway, and Till Stegers, Format-Preserving Encryption.
//   http://blog.notdot.net/2007/9/Damn-Cool-Algorithms-Part-2-Secure-permutations-with-block-ciphers
// Specifically, we use the FE2 construction with a = 2^k, b = 2^k or 2^(k+1), three rounds, and threefry
// as the round function.  Then we use cycle walking to turn this into a permutation on [0,n-1].

// An earlier version used TEA, but the quality of this was questionable and it didn't work for small n.

static inline uint64_t fe2_encrypt(const int bits, const uint128_t key, const uint64_t x) {
  assert(bits==64 || x<(uint64_t(1)<<bits));
  // Prepare for FE2
  const int a = bits>>1, b = bits-a; // logs of a,b in the paper
  const uint32_t ma = (uint64_t(1)<<a)-1, // bit masks
                 mb = (uint64_t(1)<<b)-1;
  uint32_t L = x>>b, R = x&mb;
  // Three rounds of FE2
  L = ma&(L+threefry(key,uint64_t(1)<<32|R)); // round 1: s = a
  R = mb&(R+threefry(key,uint64_t(2)<<32|L)); // round 2: s = b
  L = ma&(L+threefry(key,uint64_t(3)<<32|R)); // round 3: s = a
  return uint64_t(L)<<b|R;
}

// The inverse of fe2_encrypt
static inline uint64_t fe2_decrypt(const int bits, const uint128_t key, const uint64_t x) {
  assert(bits==64 || x<(uint64_t(1)<<bits));
  // Prepare for FE2
  const int a = bits>>1, b = bits-a; // logs of a,b in the paper
  const uint32_t ma = (uint64_t(1)<<a)-1, // bit masks
                 mb = (uint64_t(1)<<b)-1;
  uint32_t L = x>>b, R = x&mb;
  // Three rounds of FE2
  L = ma&(L-threefry(key,uint64_t(3)<<32|R)); // round 3: s = a
  R = mb&(R-threefry(key,uint64_t(2)<<32|L)); // round 2: s = b
  L = ma&(L-threefry(key,uint64_t(1)<<32|R)); // round 1: s = a
  return uint64_t(L)<<b|R;
}

// Find a power of two strictly larger than n.  By insisting on strictly larger, we avoid the weakness
// that Feistel permutations are always even (apparently).  This would be detectable for small n.
static inline int next_log(const uint64_t n) {
  return integer_log(n)+1;
}

// Since we use the next power of two for the FE2 block cipher, the cycle walking construction
// needs an average of at most 2 iterations.  This amounts to 6 calls to threefry, or a couple
// hundred cycles.

uint64_t random_permute(const uint64_t n, const uint128_t key, uint64_t x) {
  assert(x<n);
  const int bits = next_log(n);
  do { // Repeatedly encrypt until we're back in the right range
    x = fe2_encrypt(bits,key,x);
  } while (x>=n);
  return x;
}

uint64_t random_unpermute(const uint64_t n, const uint128_t key, uint64_t x) {
  assert(x<n);
  const int bits = next_log(n);
  do { // Repeatedly decrypt until we're back in the right range
    x = fe2_decrypt(bits,key,x);
  } while (x>=n);
  return x;
}

}
using namespace other;

void wrap_permute() {
  OTHER_FUNCTION(random_permute)
  OTHER_FUNCTION(random_unpermute)
}
<commit_msg>added casts to permutations to make windows happy<commit_after>// Random access pseudorandom permutations

#include <other/core/random/permute.h>
#include <other/core/random/counter.h>
#include <other/core/math/integer_log.h>
#include <other/core/python/module.h>
namespace other {

// For details, see
//   John Black and Phillip Rogaway, Ciphers with Arbitrary Finite Domains.
//   Mihir Bellare, Thomas Ristenpart, Phillip Rogaway, and Till Stegers, Format-Preserving Encryption.
//   http://blog.notdot.net/2007/9/Damn-Cool-Algorithms-Part-2-Secure-permutations-with-block-ciphers
// Specifically, we use the FE2 construction with a = 2^k, b = 2^k or 2^(k+1), three rounds, and threefry
// as the round function.  Then we use cycle walking to turn this into a permutation on [0,n-1].

// An earlier version used TEA, but the quality of this was questionable and it didn't work for small n.

static inline uint64_t fe2_encrypt(const int bits, const uint128_t key, const uint64_t x) {
  assert(bits==64 || x<(uint64_t(1)<<bits));
  // Prepare for FE2
  const int a = bits>>1, b = bits-a; // logs of a,b in the paper
  const uint32_t ma = (uint64_t(1)<<a)-1, // bit masks
                 mb = (uint64_t(1)<<b)-1;
  uint32_t L = (uint32_t)(x>>b), R = x&mb;
  // Three rounds of FE2
  L = ma&(L+cast_uint128<uint32_t>(threefry(key,uint64_t(1)<<32|R))); // round 1: s = a
  R = mb&(R+cast_uint128<uint32_t>(threefry(key,uint64_t(2)<<32|L))); // round 2: s = b
  L = ma&(L+cast_uint128<uint32_t>(threefry(key,uint64_t(3)<<32|R))); // round 3: s = a
  return uint64_t(L)<<b|R;
}

// The inverse of fe2_encrypt
static inline uint64_t fe2_decrypt(const int bits, const uint128_t key, const uint64_t x) {
  assert(bits==64 || x<(uint64_t(1)<<bits));
  // Prepare for FE2
  const int a = bits>>1, b = bits-a; // logs of a,b in the paper
  const uint32_t ma = (uint64_t(1)<<a)-1, // bit masks
                 mb = (uint64_t(1)<<b)-1;
  uint32_t L = (uint32_t)(x>>b), R = x&mb;
  // Three rounds of FE2
  L = ma&(L-cast_uint128<uint32_t>(threefry(key,uint64_t(3)<<32|R))); // round 3: s = a
  R = mb&(R-cast_uint128<uint32_t>(threefry(key,uint64_t(2)<<32|L))); // round 2: s = b
  L = ma&(L-cast_uint128<uint32_t>(threefry(key,uint64_t(1)<<32|R))); // round 1: s = a
  return uint64_t(L)<<b|R;
}

// Find a power of two strictly larger than n.  By insisting on strictly larger, we avoid the weakness
// that Feistel permutations are always even (apparently).  This would be detectable for small n.
static inline int next_log(const uint64_t n) {
  return integer_log(n)+1;
}

// Since we use the next power of two for the FE2 block cipher, the cycle walking construction
// needs an average of at most 2 iterations.  This amounts to 6 calls to threefry, or a couple
// hundred cycles.

uint64_t random_permute(const uint64_t n, const uint128_t key, uint64_t x) {
  assert(x<n);
  const int bits = next_log(n);
  do { // Repeatedly encrypt until we're back in the right range
    x = fe2_encrypt(bits,key,x);
  } while (x>=n);
  return x;
}

uint64_t random_unpermute(const uint64_t n, const uint128_t key, uint64_t x) {
  assert(x<n);
  const int bits = next_log(n);
  do { // Repeatedly decrypt until we're back in the right range
    x = fe2_decrypt(bits,key,x);
  } while (x>=n);
  return x;
}

}
using namespace other;

void wrap_permute() {
  OTHER_FUNCTION(random_permute)
  OTHER_FUNCTION(random_unpermute)
}
<|endoftext|>


<commit_before>#include "Protocol.h"

using namespace IM;

Protocol::Protocol( uint32 capabilities )
:	m_capabilities( capabilities )
{
}

Protocol::~Protocol() {
}

bool
Protocol::HasCapability( capability_bitmask cap )
{
	return (m_capabilities & cap) != 0;
}

uint32
Protocol::Capabilities(void) {
	return m_capabilities;
};<commit_msg>Fixed a warning when building libim<commit_after>#include "Protocol.h"

using namespace IM;

Protocol::Protocol( uint32 capabilities )
:	m_capabilities( capabilities )
{
}

Protocol::~Protocol() {
}

bool
Protocol::HasCapability( capability_bitmask cap )
{
	return (m_capabilities & cap) != 0;
}

uint32
Protocol::Capabilities(void) {
	return m_capabilities;
};
<|endoftext|>


<commit_before>#include "vga/rast/text_10x16.h"

#include "vga/timing.h"
#include "vga/font_10x16.h"
#include "vga/unpack_text_10p_attributed.h"

namespace vga {
namespace rast {

static constexpr unsigned glyph_cols = 10, glyph_rows = 16;
static constexpr unsigned chars_in_font = 256;

Text_10x16::Text_10x16(unsigned width, unsigned height, unsigned top_line)
  : _cols((width + (glyph_cols - 1)) / glyph_cols),
    _rows((height + (glyph_rows - 1)) / glyph_rows),
    _fb(nullptr),
    _font(nullptr),
    _top_line(top_line) {}

void Text_10x16::activate(Timing const &timing) {
  _font = new unsigned char[chars_in_font * glyph_rows];
  _fb = new unsigned[_cols * _rows];

  for (unsigned i = 0; i < chars_in_font * glyph_rows; ++i) {
    _font[i] = font_10x16[i];
  }
}

__attribute__((section(".ramcode")))
Rasterizer::LineShape Text_10x16::rasterize(unsigned line_number,
                                            Pixel *raster_target) {
  line_number -= _top_line;
  if (line_number >= _rows * glyph_rows) return { 0, 0 };

  unsigned text_row = line_number / glyph_rows;
  unsigned row_in_glyph = line_number % glyph_rows;

  unsigned const *src = _fb + _cols * text_row;
  unsigned char const *font = _font + row_in_glyph * chars_in_font;

  unpack_text_10p_attributed_impl(src, font, raster_target, _cols);

  return { 0, _cols * glyph_cols };
}

void Text_10x16::deactivate() {
  _font = nullptr;
  _fb = nullptr;
  _cols = 0;
}

void Text_10x16::clear_framebuffer(Pixel bg) {
  unsigned word = bg << 8 | ' ';
  for (unsigned i = 0; i < _cols * _rows; ++i) {
    _fb[i] = word;
  }
}

void Text_10x16::put_char(unsigned col, unsigned row,
                          Pixel fore, Pixel back,
                          char c) {
  _fb[row * _cols + col] = (fore << 16) | (back << 8) | c;
}

}  // namespace rast
}  // namespace vga
<commit_msg>vga/rast/text_10x16: blank after text.<commit_after>#include "vga/rast/text_10x16.h"

#include "vga/timing.h"
#include "vga/font_10x16.h"
#include "vga/unpack_text_10p_attributed.h"

namespace vga {
namespace rast {

static constexpr unsigned glyph_cols = 10, glyph_rows = 16;
static constexpr unsigned chars_in_font = 256;

Text_10x16::Text_10x16(unsigned width, unsigned height, unsigned top_line)
  : _cols((width + (glyph_cols - 1)) / glyph_cols),
    _rows((height + (glyph_rows - 1)) / glyph_rows),
    _fb(nullptr),
    _font(nullptr),
    _top_line(top_line) {}

void Text_10x16::activate(Timing const &timing) {
  _font = new unsigned char[chars_in_font * glyph_rows];
  _fb = new unsigned[_cols * _rows];

  for (unsigned i = 0; i < chars_in_font * glyph_rows; ++i) {
    _font[i] = font_10x16[i];
  }
}

__attribute__((section(".ramcode")))
Rasterizer::LineShape Text_10x16::rasterize(unsigned line_number,
                                            Pixel *raster_target) {
  line_number -= _top_line;

  unsigned text_row = line_number / glyph_rows;
  unsigned row_in_glyph = line_number % glyph_rows;

  if (text_row >= _rows) return { 0, 0 };

  unsigned const *src = _fb + _cols * text_row;
  unsigned char const *font = _font + row_in_glyph * chars_in_font;

  unpack_text_10p_attributed_impl(src, font, raster_target, _cols);

  return { 0, _cols * glyph_cols };
}

void Text_10x16::deactivate() {
  _font = nullptr;
  _fb = nullptr;
  _cols = 0;
}

void Text_10x16::clear_framebuffer(Pixel bg) {
  unsigned word = bg << 8 | ' ';
  for (unsigned i = 0; i < _cols * _rows; ++i) {
    _fb[i] = word;
  }
}

void Text_10x16::put_char(unsigned col, unsigned row,
                          Pixel fore, Pixel back,
                          char c) {
  _fb[row * _cols + col] = (fore << 16) | (back << 8) | c;
}

}  // namespace rast
}  // namespace vga
<|endoftext|>