<commit_before>#include "stdafx.h"
#include "AltTabber.h"

extern ProgramState_t g_programState;
extern void log(LPTSTR fmt, ...);
extern MonitorGeom_t GetMonitorGeometry();

static inline BOOL IsAltTabWindow(HWND hwnd)
{
    if(!IsWindowVisible(hwnd))
        return FALSE;

    TCHAR str[MAX_PATH + 1];
    GetWindowText(hwnd, str, MAX_PATH);

    log(_T("window %ls has style %lX and exstyle %lX\n"),
        str,
        GetWindowLong(hwnd, GWL_STYLE),
        GetWindowLong(hwnd, GWL_EXSTYLE));

    // this prevents stuff like the copy file dialog from showing up
    // but it also prevents stuff like tunngle's border windows from
    // showing up; I've opted to hide all of them.
    HWND hwndTry, hwndWalk = NULL;
    hwndTry = GetAncestor(hwnd, GA_ROOTOWNER);
    while(hwndTry != hwndWalk)
    {
        hwndWalk = hwndTry;
        hwndTry = GetLastActivePopup(hwndWalk);
        if(IsWindowVisible(hwndTry))
            break;
    }
    if(hwndWalk != hwnd)
        return FALSE;

    // this prevents borderless windows from showing up (like steam or remote desktop)
#if 0
    TITLEBARINFO ti;

    // the following removes some task tray programs and "Program Manager"
    ti.cbSize = sizeof(ti);
    GetTitleBarInfo(hwnd, &ti);
    if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
        return FALSE;
#endif

    // Tool windows should not be displayed either, these do not appear in the
    // task bar.
    if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
        return FALSE;

    if(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
        return FALSE;
#if 0
    LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
    if((style & (WS_VISIBLE | WS_EX_TOOLWINDOW | WS_POPUP | WS_CAPTION
        | WS_DLGFRAME | WS_OVERLAPPED | WS_TILED | WS_SYSMENU | WS_THICKFRAME
        )) == 0)
    {
        return FALSE;
    }
#endif

    return TRUE;
}

static BOOL GetImagePathName(HWND hwnd, std::wstring& imagePathName)
{
    BOOL hr = 0;
    TCHAR str2[MAX_PATH + 1];
    DWORD procId;
    if(GetWindowThreadProcessId(hwnd, &procId) > 0) {
        auto hnd = OpenProcess(
                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                FALSE,
                procId);
        if(hnd != NULL) {
            UINT len;
            if((len = GetModuleFileNameEx(hnd, NULL, str2, MAX_PATH)) > 0) {
                imagePathName.assign(&str2[0], &str2[len]);
                hr = 1;
            }
            CloseHandle(hnd);
        }
    }

    return hr;
}

static BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam)
{
    if(hwnd == g_programState.hWnd) return TRUE;
    if(!IsAltTabWindow(hwnd)) return TRUE;

    std::wstring filter = *((std::wstring const*)lParam);

    TCHAR str[257];
    GetWindowText(hwnd, str, 256);
    std::wstring title(str);

    std::wstring imagePathName;
    if(GetImagePathName(hwnd, imagePathName)) {
        std::wstringstream wss;
        wss << imagePathName << std::wstring(L" // ") << title;
        title = wss.str();
    }

    log(_T("the label is: %ls\n"), title.c_str());

    std::transform(title.begin(), title.end(), title.begin(), ::tolower);
    std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower);
    if(!filter.empty() && title.find(filter) == std::wstring::npos) {
        return TRUE;
    }

    HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
    HTHUMBNAIL hThumb = NULL;
    auto hr = DwmRegisterThumbnail(g_programState.hWnd, hwnd, &hThumb);
    log(_T("register thumbnail for %p on monitor %p: %d\n"),
            (void*)hwnd,
            (void*)hMonitor,
            hr);
    if(hr == S_OK) {
        AppThumb_t at = {
            APP_THUMB_AERO,
            hwnd,
        };
        at.thumb = hThumb;
        g_programState.thumbnails[hMonitor].push_back(at);
    } else {
        AppThumb_t at = {
            APP_THUMB_COMPAT,
            hwnd,
        };
        HICON hIcon = (HICON)GetClassLong(hwnd, GCL_HICON);
        at.icon = hIcon;
        g_programState.thumbnails[hMonitor].push_back(at);
    }

    return TRUE;
}

void PurgeThumbnails()
{
    for(auto i = g_programState.thumbnails.begin();
            i != g_programState.thumbnails.end();
            ++i)
    {
        auto thumbs = i->second;
        decltype(thumbs) rest(thumbs.size());
        std::remove_copy_if(
                thumbs.begin(), thumbs.end(),
                std::inserter(rest, rest.end()),
                [](AppThumb_t const& thumb) -> bool {
                    return thumb.type != APP_THUMB_AERO;
                });
        std::for_each(rest.begin(), rest.end(),
                [](AppThumb_t const& thumb) {
                    DwmUnregisterThumbnail(thumb.thumb);
                });
    }
    g_programState.thumbnails.clear();
}

void CreateThumbnails(std::wstring const& filter)
{
    PurgeThumbnails();
    auto hr = EnumWindows(enumWindows, (LPARAM)&filter);
    log(_T("enum desktop windows: %d\n"), hr);
}

template<typename F>
void PerformSlotting(F& functor)
{
    auto mis = GetMonitorGeometry();
    for(size_t i = 0; i < mis.monitors.size(); ++i) {
        auto& mi = mis.monitors[i];
        auto& thumbs = g_programState.thumbnails[mi.hMonitor];
        auto nWindows = thumbs.size();

        unsigned int nTiles = 1;
        while(nTiles < nWindows) nTiles <<= 1;
        if(nTiles != nWindows) nTiles = max(1, nTiles >> 1);

        long lala = (long)(sqrt((double)nTiles) + 0.5);

        long l1 = lala;
        long l2 = lala;
        while(((unsigned)l1) * ((unsigned)l2) < nWindows) l1++;
        lala = l1 * l2;

        long ws = (mi.extent.right - mi.extent.left) / l1;
        long hs = (mi.extent.bottom - mi.extent.top) / l2;

        for(size_t j = 0; j < thumbs.size(); ++j) {
            functor(mi, j, l1, l2, hs, ws);
        }
    }
}

void SetThumbnails()
{
    g_programState.activeSlot = -1;
    g_programState.slots.clear();
    //ShowWindow(g_programState.hWnd, SW_HIDE);
    size_t nthSlot = 0;

    MonitorGeom_t mis = GetMonitorGeometry();

    PerformSlotting([&](MonitorInfo_t& mi, size_t j, long l1, long l2, long hs, long ws) {
            AppThumb_t& thumb = g_programState.thumbnails[mi.hMonitor][j];

            long x = (j % l1) * ws + 3;
            long y = (j / l1) * hs + hs / 3;
            long x1 = x + ws - 3;
            long y1 = y + hs - hs / 3;
            RECT r;
            r.left = mi.extent.left - mis.r.left + x;
            r.right = mi.extent.left - mis.r.left + x1;
            r.top = mi.extent.top - mis.r.top + y;
            r.bottom = mi.extent.top - mis.r.top + y1;

            if(thumb.type == APP_THUMB_AERO) {
                DWM_THUMBNAIL_PROPERTIES thProps;
                thProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_VISIBLE;
                thProps.rcDestination = r;
                thProps.fVisible = TRUE;
                DwmUpdateThumbnailProperties(thumb.thumb, &thProps);
            }

            if(thumb.hwnd == g_programState.prevActiveWindow) {
                g_programState.activeSlot = nthSlot;
            }

            SlotThing_t st;
            st.hwnd = thumb.hwnd;
            st.r.left = mi.extent.left - mis.r.left + (j % l1) * ws;
            st.r.top = mi.extent.top - mis.r.top + (j / l1) * hs;
            st.r.right = st.r.left + ws;
            st.r.bottom = st.r.top + hs;
            st.moveUpDownAmount = l1;
            g_programState.slots.push_back(st);

            ++nthSlot;
    });

    if(g_programState.activeSlot < 0 && g_programState.slots.size() > 0) {
        g_programState.activeSlot = 0;
    }
}

void OnPaint(HDC hdc)
{
    HGDIOBJ original = NULL;
    original = SelectObject(hdc, GetStockObject(DC_PEN));
    HPEN pen = CreatePen(PS_SOLID, 5, RGB(0, 255, 0));
    auto originalBrush = SelectObject(hdc, GetStockObject(DC_BRUSH));
    SelectObject(hdc, GetStockObject(DC_BRUSH));

    LONG fSize = 12l;
    fSize = MulDiv(fSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
    if(fSize != 12l) log(_T("font size scaled to %ld\n"), fSize);
    HFONT font = CreateFont(
            fSize, 0, 0, 0, 0, 0, 0, 0,
            DEFAULT_CHARSET,
            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
            CLEARTYPE_QUALITY,
            DEFAULT_PITCH | FF_DONTCARE,
            _T("Courier New"));
    HFONT originalFont = (HFONT)SelectObject(hdc, font);

    auto mis = GetMonitorGeometry();
    SetDCBrushColor(hdc, RGB(0, 0, 0));
    log(_T("rectangle is %ld %ld %ld %ld\n"), mis.r.left, mis.r.top, mis.r.right, mis.r.bottom);
    //auto hrRectangle = Rectangle(hdc, 0, 0, mis.r.right - mis.r.left, mis.r.bottom - mis.r.top);
    //log(_T("rectangle returned %d: errno %d\n"), hrRectangle, GetLastError());
    RECT winRect;
    GetWindowRect(g_programState.hWnd, &winRect);
    log(_T("window rect %ld %ld %ld %ld\n"), winRect.left, winRect.top, winRect.right, winRect.bottom);
    auto hrRectangle = Rectangle(hdc, 0, 0, winRect.right - winRect.left, winRect.bottom - winRect.top);
    log(_T("rectangle returned %d: errno %d\n"), hrRectangle, GetLastError());

    SetDCBrushColor(hdc, RGB(255, 0, 0));

    //for(size_t i = 0; i < g_programState.slots.size(); ++i) {
    //    RECT r = (g_programState.slots[i].r);
    //    Rectangle(hdc, r.left, r.top, r.right, r.bottom);
    //}
    if(g_programState.activeSlot >= 0) {
        RECT r = (g_programState.slots[g_programState.activeSlot]).r;
        Rectangle(hdc, r.left, r.top, r.right, r.bottom);
    }

    SelectObject(hdc, GetStockObject(WHITE_BRUSH));
    SelectObject(hdc, GetStockObject(BLACK_PEN));
    int prevBkMode = SetBkMode(hdc, TRANSPARENT);

    PerformSlotting([&](MonitorInfo_t& mi, size_t j, long l1, long l2, long hs, long ws) {
            AppThumb_t& thumb = g_programState.thumbnails[mi.hMonitor][j];
            HWND hwnd = thumb.hwnd;

            long x = (j % l1) * ws + 3;
            long y = (j / l1) * hs + 3;
            long x1 = x + ws - 3;
            long y1 = y + hs - 2 * hs / 3 - 2;
            RECT r;
            r.left = mi.extent.left - mis.r.left + x;
            r.right = mi.extent.left - mis.r.left + x1;
            r.top = mi.extent.top - mis.r.top + y;
            r.bottom = mi.extent.top - mis.r.top + y1;

            TCHAR str[257];
            GetWindowText(hwnd, str, 256);
            std::wstring title(str);

            Rectangle(hdc, r.left, r.top, r.right, r.bottom);
            r.left += 3;
            r.right -= 3;
            r.top += 3;
            r.bottom -= 3;
            DrawText(hdc, str, -1, &r, DT_BOTTOM | DT_LEFT | DT_WORDBREAK);

            if(thumb.type == APP_THUMB_COMPAT) {
                DrawIcon(hdc, r.left + 3, r.bottom + 3, thumb.icon);
            }
    });

    DeleteObject(font);
    SetBkMode(hdc, prevBkMode);
    SelectObject(hdc, originalFont);
    SelectObject(hdc, originalBrush);
    SelectObject(hdc, original);
}<commit_msg>use EnumDesktopWindows instead of EnumWindows<commit_after>#include "stdafx.h"
#include "AltTabber.h"

extern ProgramState_t g_programState;
extern void log(LPTSTR fmt, ...);
extern MonitorGeom_t GetMonitorGeometry();

static inline BOOL IsAltTabWindow(HWND hwnd)
{
    if(!IsWindowVisible(hwnd))
        return FALSE;

    TCHAR str[MAX_PATH + 1];
    GetWindowText(hwnd, str, MAX_PATH);

    log(_T("window %ls has style %lX and exstyle %lX\n"),
        str,
        GetWindowLong(hwnd, GWL_STYLE),
        GetWindowLong(hwnd, GWL_EXSTYLE));

    // this prevents stuff like the copy file dialog from showing up
    // but it also prevents stuff like tunngle's border windows from
    // showing up; I've opted to hide all of them.
    HWND hwndTry, hwndWalk = NULL;
    hwndTry = GetAncestor(hwnd, GA_ROOTOWNER);
    while(hwndTry != hwndWalk)
    {
        hwndWalk = hwndTry;
        hwndTry = GetLastActivePopup(hwndWalk);
        if(IsWindowVisible(hwndTry))
            break;
    }
    if(hwndWalk != hwnd)
        return FALSE;

    // this prevents borderless windows from showing up (like steam or remote desktop)
#if 0
    TITLEBARINFO ti;

    // the following removes some task tray programs and "Program Manager"
    ti.cbSize = sizeof(ti);
    GetTitleBarInfo(hwnd, &ti);
    if(ti.rgstate[0] & STATE_SYSTEM_INVISIBLE)
        return FALSE;
#endif

    // Tool windows should not be displayed either, these do not appear in the
    // task bar.
    if(GetWindowLong(hwnd, GWL_EXSTYLE) & WS_EX_TOOLWINDOW)
        return FALSE;

    if(GetWindowLong(hwnd, GWL_STYLE) & WS_CHILD)
        return FALSE;
#if 0
    LONG style = GetWindowLong(hwnd, GWL_EXSTYLE);
    if((style & (WS_VISIBLE | WS_EX_TOOLWINDOW | WS_POPUP | WS_CAPTION
        | WS_DLGFRAME | WS_OVERLAPPED | WS_TILED | WS_SYSMENU | WS_THICKFRAME
        )) == 0)
    {
        return FALSE;
    }
#endif

    return TRUE;
}

static BOOL GetImagePathName(HWND hwnd, std::wstring& imagePathName)
{
    BOOL hr = 0;
    TCHAR str2[MAX_PATH + 1];
    DWORD procId;
    if(GetWindowThreadProcessId(hwnd, &procId) > 0) {
        auto hnd = OpenProcess(
                PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                FALSE,
                procId);
        if(hnd != NULL) {
            UINT len;
            if((len = GetModuleFileNameEx(hnd, NULL, str2, MAX_PATH)) > 0) {
                imagePathName.assign(&str2[0], &str2[len]);
                hr = 1;
            }
            CloseHandle(hnd);
        }
    }

    return hr;
}

static BOOL CALLBACK enumWindows(HWND hwnd, LPARAM lParam)
{
    if(hwnd == g_programState.hWnd) return TRUE;
    if(!IsAltTabWindow(hwnd)) return TRUE;

    std::wstring filter = *((std::wstring const*)lParam);

    TCHAR str[257];
    GetWindowText(hwnd, str, 256);
    std::wstring title(str);

    std::wstring imagePathName;
    if(GetImagePathName(hwnd, imagePathName)) {
        std::wstringstream wss;
        wss << imagePathName << std::wstring(L" // ") << title;
        title = wss.str();
    }

    log(_T("the label is: %ls\n"), title.c_str());

    std::transform(title.begin(), title.end(), title.begin(), ::tolower);
    std::transform(filter.begin(), filter.end(), filter.begin(), ::tolower);
    if(!filter.empty() && title.find(filter) == std::wstring::npos) {
        return TRUE;
    }

#if 0
    // I keep finding myself rewriting this code twice a day, so keep it
    // floating around
    HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL);
    if(!hMonitor) return TRUE;
#else
    HMONITOR hMonitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
#endif
    HTHUMBNAIL hThumb = NULL;
    auto hr = DwmRegisterThumbnail(g_programState.hWnd, hwnd, &hThumb);
    log(_T("register thumbnail for %p on monitor %p: %d\n"),
            (void*)hwnd,
            (void*)hMonitor,
            hr);
    if(hr == S_OK) {
        AppThumb_t at = {
            APP_THUMB_AERO,
            hwnd,
        };
        at.thumb = hThumb;
        g_programState.thumbnails[hMonitor].push_back(at);
    } else {
        AppThumb_t at = {
            APP_THUMB_COMPAT,
            hwnd,
        };
        HICON hIcon = (HICON)GetClassLong(hwnd, GCL_HICON);
        at.icon = hIcon;
        g_programState.thumbnails[hMonitor].push_back(at);
    }

    return TRUE;
}

void PurgeThumbnails()
{
    for(auto i = g_programState.thumbnails.begin();
            i != g_programState.thumbnails.end();
            ++i)
    {
        auto thumbs = i->second;
        decltype(thumbs) rest(thumbs.size());
        std::remove_copy_if(
                thumbs.begin(), thumbs.end(),
                std::inserter(rest, rest.end()),
                [](AppThumb_t const& thumb) -> bool {
                    return thumb.type != APP_THUMB_AERO;
                });
        std::for_each(rest.begin(), rest.end(),
                [](AppThumb_t const& thumb) {
                    DwmUnregisterThumbnail(thumb.thumb);
                });
    }
    g_programState.thumbnails.clear();
}

void CreateThumbnails(std::wstring const& filter)
{
    PurgeThumbnails();
    auto hDesktop = OpenInputDesktop(0, FALSE, GENERIC_READ);
    if(!hDesktop) {
        log(_T("open desktop failed; errno = %d\n"), GetLastError());
        return;
    }
    auto hr = EnumDesktopWindows(hDesktop, enumWindows, (LPARAM)&filter);
    CloseDesktop(hDesktop);
    log(_T("enum desktop windows: %d\n"), hr);
}

template<typename F>
void PerformSlotting(F& functor)
{
    auto mis = GetMonitorGeometry();
    for(size_t i = 0; i < mis.monitors.size(); ++i) {
        auto& mi = mis.monitors[i];
        auto& thumbs = g_programState.thumbnails[mi.hMonitor];
        auto nWindows = thumbs.size();

        unsigned int nTiles = 1;
        while(nTiles < nWindows) nTiles <<= 1;
        if(nTiles != nWindows) nTiles = max(1, nTiles >> 1);

        long lala = (long)(sqrt((double)nTiles) + 0.5);

        long l1 = lala;
        long l2 = lala;
        while(((unsigned)l1) * ((unsigned)l2) < nWindows) l1++;
        lala = l1 * l2;

        long ws = (mi.extent.right - mi.extent.left) / l1;
        long hs = (mi.extent.bottom - mi.extent.top) / l2;

        for(size_t j = 0; j < thumbs.size(); ++j) {
            functor(mi, j, l1, l2, hs, ws);
        }
    }
}

void SetThumbnails()
{
    g_programState.activeSlot = -1;
    g_programState.slots.clear();
    //ShowWindow(g_programState.hWnd, SW_HIDE);
    size_t nthSlot = 0;

    MonitorGeom_t mis = GetMonitorGeometry();

    PerformSlotting([&](MonitorInfo_t& mi, size_t j, long l1, long l2, long hs, long ws) {
            AppThumb_t& thumb = g_programState.thumbnails[mi.hMonitor][j];

            long x = (j % l1) * ws + 3;
            long y = (j / l1) * hs + hs / 3;
            long x1 = x + ws - 3;
            long y1 = y + hs - hs / 3;
            RECT r;
            r.left = mi.extent.left - mis.r.left + x;
            r.right = mi.extent.left - mis.r.left + x1;
            r.top = mi.extent.top - mis.r.top + y;
            r.bottom = mi.extent.top - mis.r.top + y1;

            if(thumb.type == APP_THUMB_AERO) {
                DWM_THUMBNAIL_PROPERTIES thProps;
                thProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_VISIBLE;
                thProps.rcDestination = r;
                thProps.fVisible = TRUE;
                DwmUpdateThumbnailProperties(thumb.thumb, &thProps);
            }

            if(thumb.hwnd == g_programState.prevActiveWindow) {
                g_programState.activeSlot = nthSlot;
            }

            SlotThing_t st;
            st.hwnd = thumb.hwnd;
            st.r.left = mi.extent.left - mis.r.left + (j % l1) * ws;
            st.r.top = mi.extent.top - mis.r.top + (j / l1) * hs;
            st.r.right = st.r.left + ws;
            st.r.bottom = st.r.top + hs;
            st.moveUpDownAmount = l1;
            g_programState.slots.push_back(st);

            ++nthSlot;
    });

    if(g_programState.activeSlot < 0 && g_programState.slots.size() > 0) {
        g_programState.activeSlot = 0;
    }
}

void OnPaint(HDC hdc)
{
    HGDIOBJ original = NULL;
    original = SelectObject(hdc, GetStockObject(DC_PEN));
    HPEN pen = CreatePen(PS_SOLID, 5, RGB(0, 255, 0));
    auto originalBrush = SelectObject(hdc, GetStockObject(DC_BRUSH));
    SelectObject(hdc, GetStockObject(DC_BRUSH));

    LONG fSize = 12l;
    fSize = MulDiv(fSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
    if(fSize != 12l) log(_T("font size scaled to %ld\n"), fSize);
    HFONT font = CreateFont(
            fSize, 0, 0, 0, 0, 0, 0, 0,
            DEFAULT_CHARSET,
            OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
            CLEARTYPE_QUALITY,
            DEFAULT_PITCH | FF_DONTCARE,
            _T("Courier New"));
    HFONT originalFont = (HFONT)SelectObject(hdc, font);

    auto mis = GetMonitorGeometry();
    SetDCBrushColor(hdc, RGB(0, 0, 0));
    log(_T("rectangle is %ld %ld %ld %ld\n"), mis.r.left, mis.r.top, mis.r.right, mis.r.bottom);
    //auto hrRectangle = Rectangle(hdc, 0, 0, mis.r.right - mis.r.left, mis.r.bottom - mis.r.top);
    //log(_T("rectangle returned %d: errno %d\n"), hrRectangle, GetLastError());
    RECT winRect;
    GetWindowRect(g_programState.hWnd, &winRect);
    log(_T("window rect %ld %ld %ld %ld\n"), winRect.left, winRect.top, winRect.right, winRect.bottom);
    auto hrRectangle = Rectangle(hdc, 0, 0, winRect.right - winRect.left, winRect.bottom - winRect.top);
    log(_T("rectangle returned %d: errno %d\n"), hrRectangle, GetLastError());

    SetDCBrushColor(hdc, RGB(255, 0, 0));

    //for(size_t i = 0; i < g_programState.slots.size(); ++i) {
    //    RECT r = (g_programState.slots[i].r);
    //    Rectangle(hdc, r.left, r.top, r.right, r.bottom);
    //}
    if(g_programState.activeSlot >= 0) {
        RECT r = (g_programState.slots[g_programState.activeSlot]).r;
        Rectangle(hdc, r.left, r.top, r.right, r.bottom);
    }

    SelectObject(hdc, GetStockObject(WHITE_BRUSH));
    SelectObject(hdc, GetStockObject(BLACK_PEN));
    int prevBkMode = SetBkMode(hdc, TRANSPARENT);

    PerformSlotting([&](MonitorInfo_t& mi, size_t j, long l1, long l2, long hs, long ws) {
            AppThumb_t& thumb = g_programState.thumbnails[mi.hMonitor][j];
            HWND hwnd = thumb.hwnd;

            long x = (j % l1) * ws + 3;
            long y = (j / l1) * hs + 3;
            long x1 = x + ws - 3;
            long y1 = y + hs - 2 * hs / 3 - 2;
            RECT r;
            r.left = mi.extent.left - mis.r.left + x;
            r.right = mi.extent.left - mis.r.left + x1;
            r.top = mi.extent.top - mis.r.top + y;
            r.bottom = mi.extent.top - mis.r.top + y1;

            TCHAR str[257];
            GetWindowText(hwnd, str, 256);
            std::wstring title(str);

            Rectangle(hdc, r.left, r.top, r.right, r.bottom);
            r.left += 3;
            r.right -= 3;
            r.top += 3;
            r.bottom -= 3;
            DrawText(hdc, str, -1, &r, DT_BOTTOM | DT_LEFT | DT_WORDBREAK);

            if(thumb.type == APP_THUMB_COMPAT) {
                DrawIcon(hdc, r.left + 3, r.bottom + 3, thumb.icon);
            }
    });

    DeleteObject(font);
    SetBkMode(hdc, prevBkMode);
    SelectObject(hdc, originalFont);
    SelectObject(hdc, originalBrush);
    SelectObject(hdc, original);
}<|endoftext|>


<commit_before>// AnalogScanner.cpp - Implementation file for the AnalogScanner
//   library for Arduino.
//
// Copyright 2014 Mark Rose, markrose@acm.org
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This code is designed to support these Arduino boards and
// Atmel processors:
//
// Processor           Boards
// ---------           ------
// ATmega328           Uno, Mini, Nano
//
// ATmega32u4          Leonardo, Micro, Esplora
//
// ATmega2560          Mega 2560
//
// As of this writing, it has only been tested by the author on the
// Uno (ATmega328), however.
//
// The information sources for the code in this library were both
// the Arduino IDE library source files, particularly wiring_analog.c
// and pins_arduino.h, and the Atmel reference manuals.

#include <Arduino.h>
#include <AnalogScanner.h>

// Define cbi() and sbi() for clearing and setting bits in the
// ADC registers.
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// A pointer to the currently active scanner. The ADC interrupt
// handler calls the currently active scanner to process a new
// analog value when available.
AnalogScanner *AnalogScanner::pCurrentScanner = NULL;

// Gets the index (0-15) corresponding to a pin number. If
// the pin number is already an index in the range 0-15, it is
// returned unchanged. Otherwise it is converted to a pin index.
//
// The mapping is A0->0, A1->1, ..., A15->15.
int AnalogScanner::getPinIndex(int pin) {
  switch (pin) {
  case A0: //FALLTHROUGH
  case 0: return 0;

  case A1: //FALLTHROUGH
  case 1: return 1;

  case A2: //FALLTHROUGH
  case 2: return 2;

  case A3: //FALLTHROUGH
  case 3: return 3;

  case A4: //FALLTHROUGH
  case 4: return 4;

  case A5: //FALLTHROUGH
  case 5: return 5;

  case A6: //FALLTHROUGH
  case 6: return 6;

  case A7: //FALLTHROUGH
  case 7: return 7;

#ifdef A8
  case A8: //FALLTHROUGH
  case 8: return 8;
#endif

#ifdef A9
  case A9: //FALLTHROUGH
  case 9: return 9;
#endif

#ifdef A10
  case A10: //FALLTHROUGH
  case 10: return 10;
#endif

#ifdef A11
  case A11: //FALLTHROUGH
  case 11: return 11;
#endif

#ifdef A12
  case A12: //FALLTHROUGH
  case 12: return 12;
#endif

#ifdef A13
  case A13: //FALLTHROUGH
  case 13: return 13;
#endif

#ifdef A14
  case A14: //FALLTHROUGH
  case 14: return 14;
#endif

#ifdef A15
  case A15: //FALLTHROUGH
  case 15: return 15;
#endif

  default:
    return 0;
  }
}

// Gets the pin number for a pin or channel.
// Code from wiring_analog.c, lines 44-57.
uint8_t AnalogScanner::normalizePin(uint8_t pin) {
#if defined(analogPinToChannel)
#if defined(__AVR_ATmega32U4__)
  if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#endif
  pin = analogPinToChannel(pin);
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#elif defined(__AVR_ATmega32U4__)
  if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
  if (pin >= 24) pin -= 24; // allow for channel or pin numbers
#elif defined(ADAFRUIT_FEATHER_M0)
	pin = g_APinDescription[pin].ulADCChannelNumber;
#else
  if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

  return pin;
}

// Creates a new instance of the analog input scanner. Initializes
// all scanned values to zero and all callbacks to null. Clears the
// scan order and sets the analog reference voltage to the default.
AnalogScanner::AnalogScanner() {
  for (int i=0; i < ANALOG_INPUTS; ++i) {
    values[i] = 0;
    pCallback[i] = NULL;
  }

  scanOrderSize = 0;
  currentIndex = -1;
  analogRef = DEFAULT;
}

// Sets a callback function for a particular analog pin. The
// function is called by the interrupt handling code as soon
// as a new analog value is available.
void AnalogScanner::setCallback(int pin, void (*p)(int index, int pin, int value)) {
  pCallback[getPinIndex(pin)] = p;
}

// Sets the scan order for the analog pins. The same pin may
// be specified multiple times if a pin should be sampled more
// often.
void AnalogScanner::setScanOrder(int n, const int order[]) {
  scanOrderSize = min(SCAN_ORDER_MAX, n);
  for (int i=0; i < scanOrderSize; ++i) {
    requestedPins[i] = order[i];
    normalizedPins[i] = normalizePin(order[i]);
  }
}

// Gets the most recently read value for an analog pin.
int AnalogScanner::getValue(int pin) {
  noInterrupts();
  int value = values[getPinIndex(pin)];
  interrupts();

  return value;
}

// Sets the analog reference voltage. See the built-in Arduino
// function analogReference() for details.
void AnalogScanner::setAnalogReference(int reference) {
  analogRef = reference & 3;
}

// Begins scanning the analog input pins.
void AnalogScanner::beginScanning() {
  pCurrentScanner = this;

  #if defined(__SAMD21G18A__)
  ADC->CTRLA.bit.ENABLE = 1;
  delay(1);
  ADC->INTENSET.bit.RESRDY = 1;
  NVIC_EnableIRQ(ADC_IRQn); 	// enable ADC interrupts
  NVIC_SetPriority(ADC_IRQn, 2); //set priority of the interrupt
  #else
  sbi(ADCSRA, ADEN); // Enable the ADC.
  delay(1);
  cbi(ADMUX, ADLAR); // Make sure the ADC value is right-justified.
  sbi(ADCSRA, ADIE); // Enable ADC complete interrupts.
  #endif
  startNextScan();
}

// Ends scanning the analog input pins. Disables the ADC to
// save power.
void AnalogScanner::endScanning() {
  #if defined(__SAMD21G18A__)
  ADC->CTRLA.bit.ENABLE = 0;
  ADC->INTENSET.bit.RESRDY = 0;
  #else
  cbi(ADCSRA, ADEN); // Disable the ADC.
  cbi(ADCSRA, ADIE); // Disable ADC complete interrupts.
  #endif
}

// Starts the next ADC read.
void AnalogScanner::startNextScan() {
  if (scanOrderSize > 0) {
    if (++currentIndex >= scanOrderSize) {
      currentIndex = 0;
    }
    currentPin = requestedPins[currentIndex];
    int pin = normalizedPins[currentIndex];
	#if defined(__SAMD21G18A__)
		ADC->INPUTCTRL.bit.MUXPOS = pin;
		ADC->SWTRIG.bit.START = 1;
	#else
#ifdef MUX5
    // Set whether we're reading from inputs 0-7 or 8-15.
    ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
    ADMUX = (analogRef << 6) | (pin & 7);
    sbi(ADCSRA, ADSC); // Start the ADC conversion.
	#endif
  }
}

// Processes a new value from the ADC.
void AnalogScanner::processScan() {
  // We must read ADCL first, which locks ADCH until it is read.
  #if defined(__SAMD21G18A__)
  int index = getPinIndex(currentPin);
  int pin = currentPin;
  values[index] = ADC->RESULT.reg;
  #else
  int low = ADCL;
  int high = ADCH;
  int index = getPinIndex(currentPin);
  int pin = currentPin;
  values[index] = (high << 8) | low;
  #endif
  // Invoke the next scan before the callback, to make the
  // read rate more uniform.
  startNextScan();

  if (pCallback[index] != NULL) {
    pCallback[index](currentIndex, pin, values[index]);
  }
}

// Handles the ADC completion interrupt by requesting that the
// current scanner read teh newly available analog input value.
void AnalogScanner::scanComplete() {
  pCurrentScanner->processScan();
}

// Defines an ADC interrupt processing routine that asks the
// currently active scanner to process a newly scanned value.
#if defined (__SAMD21G18A__)
void ADC_Handler() {
  AnalogScanner::scanComplete();
}
#else
ISR(ADC_vect) {
  AnalogScanner::scanComplete();
}
#endif<commit_msg>Bugfix to return correct array index when using callbacks<commit_after>// AnalogScanner.cpp - Implementation file for the AnalogScanner
//   library for Arduino.
//
// Copyright 2014 Mark Rose, markrose@acm.org
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This code is designed to support these Arduino boards and
// Atmel processors:
//
// Processor           Boards
// ---------           ------
// ATmega328           Uno, Mini, Nano
//
// ATmega32u4          Leonardo, Micro, Esplora
//
// ATmega2560          Mega 2560
//
// As of this writing, it has only been tested by the author on the
// Uno (ATmega328), however.
//
// The information sources for the code in this library were both
// the Arduino IDE library source files, particularly wiring_analog.c
// and pins_arduino.h, and the Atmel reference manuals.

#include <Arduino.h>
#include <AnalogScanner.h>

// Define cbi() and sbi() for clearing and setting bits in the
// ADC registers.
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// A pointer to the currently active scanner. The ADC interrupt
// handler calls the currently active scanner to process a new
// analog value when available.
AnalogScanner *AnalogScanner::pCurrentScanner = NULL;

// Gets the index (0-15) corresponding to a pin number. If
// the pin number is already an index in the range 0-15, it is
// returned unchanged. Otherwise it is converted to a pin index.
//
// The mapping is A0->0, A1->1, ..., A15->15.
int AnalogScanner::getPinIndex(int pin) {
  switch (pin) {
  case A0: //FALLTHROUGH
  case 0: return 0;

  case A1: //FALLTHROUGH
  case 1: return 1;

  case A2: //FALLTHROUGH
  case 2: return 2;

  case A3: //FALLTHROUGH
  case 3: return 3;

  case A4: //FALLTHROUGH
  case 4: return 4;

  case A5: //FALLTHROUGH
  case 5: return 5;

  case A6: //FALLTHROUGH
  case 6: return 6;

  case A7: //FALLTHROUGH
  case 7: return 7;

#ifdef A8
  case A8: //FALLTHROUGH
  case 8: return 8;
#endif

#ifdef A9
  case A9: //FALLTHROUGH
  case 9: return 9;
#endif

#ifdef A10
  case A10: //FALLTHROUGH
  case 10: return 10;
#endif

#ifdef A11
  case A11: //FALLTHROUGH
  case 11: return 11;
#endif

#ifdef A12
  case A12: //FALLTHROUGH
  case 12: return 12;
#endif

#ifdef A13
  case A13: //FALLTHROUGH
  case 13: return 13;
#endif

#ifdef A14
  case A14: //FALLTHROUGH
  case 14: return 14;
#endif

#ifdef A15
  case A15: //FALLTHROUGH
  case 15: return 15;
#endif

  default:
    return 0;
  }
}

// Gets the pin number for a pin or channel.
// Code from wiring_analog.c, lines 44-57.
uint8_t AnalogScanner::normalizePin(uint8_t pin) {
#if defined(analogPinToChannel)
#if defined(__AVR_ATmega32U4__)
  if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#endif
  pin = analogPinToChannel(pin);
#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
  if (pin >= 54) pin -= 54; // allow for channel or pin numbers
#elif defined(__AVR_ATmega32U4__)
  if (pin >= 18) pin -= 18; // allow for channel or pin numbers
#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
  if (pin >= 24) pin -= 24; // allow for channel or pin numbers
#elif defined(ADAFRUIT_FEATHER_M0)
	pin = g_APinDescription[pin].ulADCChannelNumber;
#else
  if (pin >= 14) pin -= 14; // allow for channel or pin numbers
#endif

  return pin;
}

// Creates a new instance of the analog input scanner. Initializes
// all scanned values to zero and all callbacks to null. Clears the
// scan order and sets the analog reference voltage to the default.
AnalogScanner::AnalogScanner() {
  for (int i=0; i < ANALOG_INPUTS; ++i) {
    values[i] = 0;
    pCallback[i] = NULL;
  }

  scanOrderSize = 0;
  currentIndex = -1;
  analogRef = DEFAULT;
}

// Sets a callback function for a particular analog pin. The
// function is called by the interrupt handling code as soon
// as a new analog value is available.
void AnalogScanner::setCallback(int pin, void (*p)(int index, int pin, int value)) {
  pCallback[getPinIndex(pin)] = p;
}

// Sets the scan order for the analog pins. The same pin may
// be specified multiple times if a pin should be sampled more
// often.
void AnalogScanner::setScanOrder(int n, const int order[]) {
  scanOrderSize = min(SCAN_ORDER_MAX, n);
  for (int i=0; i < scanOrderSize; ++i) {
    requestedPins[i] = order[i];
    normalizedPins[i] = normalizePin(order[i]);
  }
}

// Gets the most recently read value for an analog pin.
int AnalogScanner::getValue(int pin) {
  noInterrupts();
  int value = values[getPinIndex(pin)];
  interrupts();

  return value;
}

// Sets the analog reference voltage. See the built-in Arduino
// function analogReference() for details.
void AnalogScanner::setAnalogReference(int reference) {
  analogRef = reference & 3;
}

// Begins scanning the analog input pins.
void AnalogScanner::beginScanning() {
  pCurrentScanner = this;

  #if defined(__SAMD21G18A__)
  ADC->CTRLA.bit.ENABLE = 1;
  delay(1);
  ADC->INTENSET.bit.RESRDY = 1;
  NVIC_EnableIRQ(ADC_IRQn); 	// enable ADC interrupts
  NVIC_SetPriority(ADC_IRQn, 2); //set priority of the interrupt
  #else
  sbi(ADCSRA, ADEN); // Enable the ADC.
  delay(1);
  cbi(ADMUX, ADLAR); // Make sure the ADC value is right-justified.
  sbi(ADCSRA, ADIE); // Enable ADC complete interrupts.
  #endif
  startNextScan();
}

// Ends scanning the analog input pins. Disables the ADC to
// save power.
void AnalogScanner::endScanning() {
  #if defined(__SAMD21G18A__)
  ADC->CTRLA.bit.ENABLE = 0;
  ADC->INTENSET.bit.RESRDY = 0;
  #else
  cbi(ADCSRA, ADEN); // Disable the ADC.
  cbi(ADCSRA, ADIE); // Disable ADC complete interrupts.
  #endif
}

// Starts the next ADC read.
void AnalogScanner::startNextScan() {
  if (scanOrderSize > 0) {
    if (++currentIndex >= scanOrderSize) {
      currentIndex = 0;
    }
    currentPin = requestedPins[currentIndex];
    int pin = normalizedPins[currentIndex];
	#if defined(__SAMD21G18A__)
		ADC->INPUTCTRL.bit.MUXPOS = pin;
		ADC->SWTRIG.bit.START = 1;
	#else
#ifdef MUX5
    // Set whether we're reading from inputs 0-7 or 8-15.
    ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5);
#endif
    ADMUX = (analogRef << 6) | (pin & 7);
    sbi(ADCSRA, ADSC); // Start the ADC conversion.
	#endif
  }
}

// Processes a new value from the ADC.
void AnalogScanner::processScan() {
  // We must read ADCL first, which locks ADCH until it is read.
  #if defined(__SAMD21G18A__)
  int index = getPinIndex(currentPin);
  int pin = currentPin;
  values[index] = ADC->RESULT.reg;
  #else
  int low = ADCL;
  int high = ADCH;
  int index = getPinIndex(currentPin);
  int pin = currentPin;
  values[index] = (high << 8) | low;
  #endif
  int currentIndexLocal = currentIndex;  //make a local copy of the currentIndex
  // Invoke the next scan before the callback, to make the
  // read rate more uniform.
startNextScan(); //currentIndex will be updated/wrapped to 0 here

  if (pCallback[index] != NULL) {
    pCallback[index](currentIndexLocal, pin, values[index]); //use the not updated copy of the currentIndex here
  }
}

// Handles the ADC completion interrupt by requesting that the
// current scanner read teh newly available analog input value.
void AnalogScanner::scanComplete() {
  pCurrentScanner->processScan();
}

// Defines an ADC interrupt processing routine that asks the
// currently active scanner to process a newly scanned value.
#if defined (__SAMD21G18A__)
void ADC_Handler() {
  AnalogScanner::scanComplete();
}
#else
ISR(ADC_vect) {
  AnalogScanner::scanComplete();
}
#endif<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
#include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"

using ::testing::Return;
using ::testing::_;
using ::testing::SetArgPointee;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::MockFunction;

namespace webrtc {

namespace {
static const size_t kMaxEncodedBytes = 1000;
static const size_t kMaxNumSamples = 48 * 10 * 2;  // 10 ms @ 48 kHz stereo.
}

class AudioEncoderCopyRedTest : public ::testing::Test {
 protected:
  AudioEncoderCopyRedTest()
      : timestamp_(4711),
        sample_rate_hz_(16000),
        num_audio_samples_10ms(sample_rate_hz_ / 100),
        red_payload_type_(200) {
    AudioEncoderCopyRed::Config config;
    config.payload_type = red_payload_type_;
    config.speech_encoder = &mock_encoder_;
    red_.reset(new AudioEncoderCopyRed(config));
    memset(encoded_, 0, sizeof(encoded_));
    memset(audio_, 0, sizeof(audio_));
    EXPECT_CALL(mock_encoder_, num_channels()).WillRepeatedly(Return(1));
    EXPECT_CALL(mock_encoder_, sample_rate_hz())
        .WillRepeatedly(Return(sample_rate_hz_));
  }

  virtual void TearDown() OVERRIDE {
    red_.reset();
    // Don't expect the red_ object to delete the AudioEncoder object. But it
    // will be deleted with the test fixture. This is why we explicitly delete
    // the red_ object above, and set expectations on mock_encoder_ afterwards.
    EXPECT_CALL(mock_encoder_, Die()).Times(1);
  }

  void Encode() {
    ASSERT_TRUE(red_.get() != NULL);
    encoded_info_ = AudioEncoder::EncodedInfo();
    ASSERT_TRUE(red_->Encode(timestamp_, audio_, num_audio_samples_10ms,
                             kMaxEncodedBytes, encoded_, &encoded_info_));
    timestamp_ += num_audio_samples_10ms;
  }

  MockAudioEncoder mock_encoder_;
  scoped_ptr<AudioEncoderCopyRed> red_;
  uint32_t timestamp_;
  int16_t audio_[kMaxNumSamples];
  const int sample_rate_hz_;
  size_t num_audio_samples_10ms;
  uint8_t encoded_[kMaxEncodedBytes];
  AudioEncoder::EncodedInfo encoded_info_;
  const int red_payload_type_;
};

class MockEncodeHelper {
 public:
  MockEncodeHelper() : write_payload_(false), payload_(NULL) {
    memset(&info_, 0, sizeof(info_));
  }

  bool Encode(uint32_t timestamp,
              const int16_t* audio,
              size_t max_encoded_bytes,
              uint8_t* encoded,
              AudioEncoder::EncodedInfo* info) {
    if (write_payload_) {
      CHECK(encoded);
      CHECK_LE(info_.encoded_bytes, max_encoded_bytes);
      memcpy(encoded, payload_, info_.encoded_bytes);
    }
    CHECK(info);
    *info = info_;
    return true;
  }

  AudioEncoder::EncodedInfo info_;
  bool write_payload_;
  uint8_t* payload_;
};

TEST_F(AudioEncoderCopyRedTest, CreateAndDestroy) {
}

TEST_F(AudioEncoderCopyRedTest, CheckSampleRatePropagation) {
  EXPECT_CALL(mock_encoder_, sample_rate_hz()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->sample_rate_hz());
}

TEST_F(AudioEncoderCopyRedTest, CheckNumChannelsPropagation) {
  EXPECT_CALL(mock_encoder_, num_channels()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->num_channels());
}

TEST_F(AudioEncoderCopyRedTest, CheckFrameSizePropagation) {
  EXPECT_CALL(mock_encoder_, Num10MsFramesInNextPacket()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->Num10MsFramesInNextPacket());
}

TEST_F(AudioEncoderCopyRedTest, CheckMaxFrameSizePropagation) {
  EXPECT_CALL(mock_encoder_, Max10MsFramesInAPacket()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->Max10MsFramesInAPacket());
}

// Checks that the an Encode() call is immediately propagated to the speech
// encoder.
TEST_F(AudioEncoderCopyRedTest, CheckImmediateEncode) {
  // Interleaving the EXPECT_CALL sequence with expectations on the MockFunction
  // check ensures that exactly one call to EncodeInternal happens in each
  // Encode call.
  InSequence s;
  MockFunction<void(int check_point_id)> check;
  for (int i = 1; i <= 6; ++i) {
    EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
        .WillOnce(Return(true));
    EXPECT_CALL(check, Call(i));
    Encode();
    check.Call(i);
  }
}

// Checks that no output is produced if the underlying codec doesn't emit any
// new data, even if the RED codec is loaded with a secondary encoding.
TEST_F(AudioEncoderCopyRedTest, CheckNoOuput) {
  // Start with one Encode() call that will produce output.
  static const size_t kEncodedSize = 17;
  AudioEncoder::EncodedInfo info;
  info.encoded_bytes = kEncodedSize;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  Encode();
  // First call is a special case, since it does not include a secondary
  // payload.
  EXPECT_EQ(1u, encoded_info_.redundant.size());
  EXPECT_EQ(kEncodedSize, encoded_info_.encoded_bytes);

  // Next call to the speech encoder will not produce any output.
  info.encoded_bytes = 0;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  Encode();
  EXPECT_EQ(0u, encoded_info_.encoded_bytes);

  // Final call to the speech encoder will produce output.
  info.encoded_bytes = kEncodedSize;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  Encode();
  EXPECT_EQ(2 * kEncodedSize, encoded_info_.encoded_bytes);
  ASSERT_EQ(2u, encoded_info_.redundant.size());
}

// Checks that the correct payload sizes are populated into the redundancy
// information.
TEST_F(AudioEncoderCopyRedTest, CheckPayloadSizes) {
  // Let the mock encoder return payload sizes 1, 2, 3, ..., 10 for the sequence
  // of calls.
  static const int kNumPackets = 10;
  InSequence s;
  for (int encode_size = 1; encode_size <= kNumPackets; ++encode_size) {
    AudioEncoder::EncodedInfo info;
    info.encoded_bytes = encode_size;
    EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
        .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  }

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  EXPECT_EQ(1u, encoded_info_.redundant.size());
  EXPECT_EQ(1u, encoded_info_.encoded_bytes);

  for (size_t i = 2; i <= kNumPackets; ++i) {
    Encode();
    ASSERT_EQ(2u, encoded_info_.redundant.size());
    EXPECT_EQ(i, encoded_info_.redundant[0].encoded_bytes);
    EXPECT_EQ(i - 1, encoded_info_.redundant[1].encoded_bytes);
    EXPECT_EQ(i + i - 1, encoded_info_.encoded_bytes);
  }
}

// Checks that the correct timestamps are returned.
TEST_F(AudioEncoderCopyRedTest, CheckTimestamps) {
  MockEncodeHelper helper;

  helper.info_.encoded_bytes = 17;
  helper.info_.encoded_timestamp = timestamp_;
  uint32_t primary_timestamp = timestamp_;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  EXPECT_EQ(primary_timestamp, encoded_info_.encoded_timestamp);

  uint32_t secondary_timestamp = primary_timestamp;
  primary_timestamp = timestamp_;
  helper.info_.encoded_timestamp = timestamp_;
  Encode();
  ASSERT_EQ(2u, encoded_info_.redundant.size());
  EXPECT_EQ(primary_timestamp, encoded_info_.redundant[0].encoded_timestamp);
  EXPECT_EQ(secondary_timestamp, encoded_info_.redundant[1].encoded_timestamp);
  EXPECT_EQ(primary_timestamp, encoded_info_.encoded_timestamp);
}

// Checks that the primary and secondary payloads are written correctly.
TEST_F(AudioEncoderCopyRedTest, CheckPayloads) {
  // Let the mock encoder write payloads with increasing values. The first
  // payload will have values 0, 1, 2, ..., kPayloadLenBytes - 1.
  MockEncodeHelper helper;
  static const size_t kPayloadLenBytes = 5;
  helper.info_.encoded_bytes = kPayloadLenBytes;
  helper.write_payload_ = true;
  uint8_t payload[kPayloadLenBytes];
  for (uint8_t i = 0; i < kPayloadLenBytes; ++i) {
    payload[i] = i;
  }
  helper.payload_ = payload;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  EXPECT_EQ(kPayloadLenBytes, encoded_info_.encoded_bytes);
  for (size_t i = 0; i < kPayloadLenBytes; ++i) {
    EXPECT_EQ(i, encoded_[i]);
  }

  for (int j = 0; j < 5; ++j) {
    // Increment all values of the payload by 10.
    for (size_t i = 0; i < kPayloadLenBytes; ++i)
      helper.payload_[i] += 10;

    Encode();
    ASSERT_EQ(2u, encoded_info_.redundant.size());
    EXPECT_EQ(kPayloadLenBytes, encoded_info_.redundant[0].encoded_bytes);
    EXPECT_EQ(kPayloadLenBytes, encoded_info_.redundant[1].encoded_bytes);
    for (size_t i = 0; i < kPayloadLenBytes; ++i) {
      // Check primary payload.
      EXPECT_EQ((j + 1) * 10 + i, encoded_[i]);
      // Check secondary payload.
      EXPECT_EQ(j * 10 + i, encoded_[i + kPayloadLenBytes]);
    }
  }
}

// Checks correct propagation of payload type.
// Checks that the correct timestamps are returned.
TEST_F(AudioEncoderCopyRedTest, CheckPayloadType) {
  MockEncodeHelper helper;

  helper.info_.encoded_bytes = 17;
  const int primary_payload_type = red_payload_type_ + 1;
  helper.info_.payload_type = primary_payload_type;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  ASSERT_EQ(1u, encoded_info_.redundant.size());
  EXPECT_EQ(primary_payload_type, encoded_info_.redundant[0].payload_type);
  EXPECT_EQ(red_payload_type_, encoded_info_.payload_type);

  const int secondary_payload_type = red_payload_type_ + 2;
  helper.info_.payload_type = secondary_payload_type;
  Encode();
  ASSERT_EQ(2u, encoded_info_.redundant.size());
  EXPECT_EQ(secondary_payload_type, encoded_info_.redundant[0].payload_type);
  EXPECT_EQ(primary_payload_type, encoded_info_.redundant[1].payload_type);
  EXPECT_EQ(red_payload_type_, encoded_info_.payload_type);
}

#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)

// This test fixture tests various error conditions that makes the
// AudioEncoderCng die via CHECKs.
class AudioEncoderCopyRedDeathTest : public AudioEncoderCopyRedTest {
 protected:
  AudioEncoderCopyRedDeathTest() : AudioEncoderCopyRedTest() {}
};

TEST_F(AudioEncoderCopyRedDeathTest, WrongFrameSize) {
  num_audio_samples_10ms *= 2;  // 20 ms frame.
  EXPECT_DEATH(Encode(), "");
  num_audio_samples_10ms = 0;  // Zero samples.
  EXPECT_DEATH(Encode(), "");
}

// Test fails memcheck.
// https://code.google.com/p/webrtc/issues/detail?id=4108
TEST_F(AudioEncoderCopyRedDeathTest, DISABLED_NullSpeechEncoder) {
  AudioEncoderCopyRed* red;
  AudioEncoderCopyRed::Config config;
  config.speech_encoder = NULL;
  EXPECT_DEATH(red = new AudioEncoderCopyRed(config),
               "Speech encoder not provided.");
}

#endif  // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)

}  // namespace webrtc
<commit_msg>Fixing the memory leak in AudioEncoderCopyRedDeathTest.NullSpeechEncoder<commit_after>/*
 *  Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
#include "webrtc/modules/audio_coding/codecs/mock/mock_audio_encoder.h"
#include "webrtc/system_wrappers/interface/scoped_ptr.h"

using ::testing::Return;
using ::testing::_;
using ::testing::SetArgPointee;
using ::testing::InSequence;
using ::testing::Invoke;
using ::testing::MockFunction;

namespace webrtc {

namespace {
static const size_t kMaxEncodedBytes = 1000;
static const size_t kMaxNumSamples = 48 * 10 * 2;  // 10 ms @ 48 kHz stereo.
}

class AudioEncoderCopyRedTest : public ::testing::Test {
 protected:
  AudioEncoderCopyRedTest()
      : timestamp_(4711),
        sample_rate_hz_(16000),
        num_audio_samples_10ms(sample_rate_hz_ / 100),
        red_payload_type_(200) {
    AudioEncoderCopyRed::Config config;
    config.payload_type = red_payload_type_;
    config.speech_encoder = &mock_encoder_;
    red_.reset(new AudioEncoderCopyRed(config));
    memset(encoded_, 0, sizeof(encoded_));
    memset(audio_, 0, sizeof(audio_));
    EXPECT_CALL(mock_encoder_, num_channels()).WillRepeatedly(Return(1));
    EXPECT_CALL(mock_encoder_, sample_rate_hz())
        .WillRepeatedly(Return(sample_rate_hz_));
  }

  virtual void TearDown() OVERRIDE {
    red_.reset();
    // Don't expect the red_ object to delete the AudioEncoder object. But it
    // will be deleted with the test fixture. This is why we explicitly delete
    // the red_ object above, and set expectations on mock_encoder_ afterwards.
    EXPECT_CALL(mock_encoder_, Die()).Times(1);
  }

  void Encode() {
    ASSERT_TRUE(red_.get() != NULL);
    encoded_info_ = AudioEncoder::EncodedInfo();
    ASSERT_TRUE(red_->Encode(timestamp_, audio_, num_audio_samples_10ms,
                             kMaxEncodedBytes, encoded_, &encoded_info_));
    timestamp_ += num_audio_samples_10ms;
  }

  MockAudioEncoder mock_encoder_;
  scoped_ptr<AudioEncoderCopyRed> red_;
  uint32_t timestamp_;
  int16_t audio_[kMaxNumSamples];
  const int sample_rate_hz_;
  size_t num_audio_samples_10ms;
  uint8_t encoded_[kMaxEncodedBytes];
  AudioEncoder::EncodedInfo encoded_info_;
  const int red_payload_type_;
};

class MockEncodeHelper {
 public:
  MockEncodeHelper() : write_payload_(false), payload_(NULL) {
    memset(&info_, 0, sizeof(info_));
  }

  bool Encode(uint32_t timestamp,
              const int16_t* audio,
              size_t max_encoded_bytes,
              uint8_t* encoded,
              AudioEncoder::EncodedInfo* info) {
    if (write_payload_) {
      CHECK(encoded);
      CHECK_LE(info_.encoded_bytes, max_encoded_bytes);
      memcpy(encoded, payload_, info_.encoded_bytes);
    }
    CHECK(info);
    *info = info_;
    return true;
  }

  AudioEncoder::EncodedInfo info_;
  bool write_payload_;
  uint8_t* payload_;
};

TEST_F(AudioEncoderCopyRedTest, CreateAndDestroy) {
}

TEST_F(AudioEncoderCopyRedTest, CheckSampleRatePropagation) {
  EXPECT_CALL(mock_encoder_, sample_rate_hz()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->sample_rate_hz());
}

TEST_F(AudioEncoderCopyRedTest, CheckNumChannelsPropagation) {
  EXPECT_CALL(mock_encoder_, num_channels()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->num_channels());
}

TEST_F(AudioEncoderCopyRedTest, CheckFrameSizePropagation) {
  EXPECT_CALL(mock_encoder_, Num10MsFramesInNextPacket()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->Num10MsFramesInNextPacket());
}

TEST_F(AudioEncoderCopyRedTest, CheckMaxFrameSizePropagation) {
  EXPECT_CALL(mock_encoder_, Max10MsFramesInAPacket()).WillOnce(Return(17));
  EXPECT_EQ(17, red_->Max10MsFramesInAPacket());
}

// Checks that the an Encode() call is immediately propagated to the speech
// encoder.
TEST_F(AudioEncoderCopyRedTest, CheckImmediateEncode) {
  // Interleaving the EXPECT_CALL sequence with expectations on the MockFunction
  // check ensures that exactly one call to EncodeInternal happens in each
  // Encode call.
  InSequence s;
  MockFunction<void(int check_point_id)> check;
  for (int i = 1; i <= 6; ++i) {
    EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
        .WillOnce(Return(true));
    EXPECT_CALL(check, Call(i));
    Encode();
    check.Call(i);
  }
}

// Checks that no output is produced if the underlying codec doesn't emit any
// new data, even if the RED codec is loaded with a secondary encoding.
TEST_F(AudioEncoderCopyRedTest, CheckNoOuput) {
  // Start with one Encode() call that will produce output.
  static const size_t kEncodedSize = 17;
  AudioEncoder::EncodedInfo info;
  info.encoded_bytes = kEncodedSize;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  Encode();
  // First call is a special case, since it does not include a secondary
  // payload.
  EXPECT_EQ(1u, encoded_info_.redundant.size());
  EXPECT_EQ(kEncodedSize, encoded_info_.encoded_bytes);

  // Next call to the speech encoder will not produce any output.
  info.encoded_bytes = 0;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  Encode();
  EXPECT_EQ(0u, encoded_info_.encoded_bytes);

  // Final call to the speech encoder will produce output.
  info.encoded_bytes = kEncodedSize;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  Encode();
  EXPECT_EQ(2 * kEncodedSize, encoded_info_.encoded_bytes);
  ASSERT_EQ(2u, encoded_info_.redundant.size());
}

// Checks that the correct payload sizes are populated into the redundancy
// information.
TEST_F(AudioEncoderCopyRedTest, CheckPayloadSizes) {
  // Let the mock encoder return payload sizes 1, 2, 3, ..., 10 for the sequence
  // of calls.
  static const int kNumPackets = 10;
  InSequence s;
  for (int encode_size = 1; encode_size <= kNumPackets; ++encode_size) {
    AudioEncoder::EncodedInfo info;
    info.encoded_bytes = encode_size;
    EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
        .WillOnce(DoAll(SetArgPointee<4>(info), Return(true)));
  }

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  EXPECT_EQ(1u, encoded_info_.redundant.size());
  EXPECT_EQ(1u, encoded_info_.encoded_bytes);

  for (size_t i = 2; i <= kNumPackets; ++i) {
    Encode();
    ASSERT_EQ(2u, encoded_info_.redundant.size());
    EXPECT_EQ(i, encoded_info_.redundant[0].encoded_bytes);
    EXPECT_EQ(i - 1, encoded_info_.redundant[1].encoded_bytes);
    EXPECT_EQ(i + i - 1, encoded_info_.encoded_bytes);
  }
}

// Checks that the correct timestamps are returned.
TEST_F(AudioEncoderCopyRedTest, CheckTimestamps) {
  MockEncodeHelper helper;

  helper.info_.encoded_bytes = 17;
  helper.info_.encoded_timestamp = timestamp_;
  uint32_t primary_timestamp = timestamp_;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  EXPECT_EQ(primary_timestamp, encoded_info_.encoded_timestamp);

  uint32_t secondary_timestamp = primary_timestamp;
  primary_timestamp = timestamp_;
  helper.info_.encoded_timestamp = timestamp_;
  Encode();
  ASSERT_EQ(2u, encoded_info_.redundant.size());
  EXPECT_EQ(primary_timestamp, encoded_info_.redundant[0].encoded_timestamp);
  EXPECT_EQ(secondary_timestamp, encoded_info_.redundant[1].encoded_timestamp);
  EXPECT_EQ(primary_timestamp, encoded_info_.encoded_timestamp);
}

// Checks that the primary and secondary payloads are written correctly.
TEST_F(AudioEncoderCopyRedTest, CheckPayloads) {
  // Let the mock encoder write payloads with increasing values. The first
  // payload will have values 0, 1, 2, ..., kPayloadLenBytes - 1.
  MockEncodeHelper helper;
  static const size_t kPayloadLenBytes = 5;
  helper.info_.encoded_bytes = kPayloadLenBytes;
  helper.write_payload_ = true;
  uint8_t payload[kPayloadLenBytes];
  for (uint8_t i = 0; i < kPayloadLenBytes; ++i) {
    payload[i] = i;
  }
  helper.payload_ = payload;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  EXPECT_EQ(kPayloadLenBytes, encoded_info_.encoded_bytes);
  for (size_t i = 0; i < kPayloadLenBytes; ++i) {
    EXPECT_EQ(i, encoded_[i]);
  }

  for (int j = 0; j < 5; ++j) {
    // Increment all values of the payload by 10.
    for (size_t i = 0; i < kPayloadLenBytes; ++i)
      helper.payload_[i] += 10;

    Encode();
    ASSERT_EQ(2u, encoded_info_.redundant.size());
    EXPECT_EQ(kPayloadLenBytes, encoded_info_.redundant[0].encoded_bytes);
    EXPECT_EQ(kPayloadLenBytes, encoded_info_.redundant[1].encoded_bytes);
    for (size_t i = 0; i < kPayloadLenBytes; ++i) {
      // Check primary payload.
      EXPECT_EQ((j + 1) * 10 + i, encoded_[i]);
      // Check secondary payload.
      EXPECT_EQ(j * 10 + i, encoded_[i + kPayloadLenBytes]);
    }
  }
}

// Checks correct propagation of payload type.
// Checks that the correct timestamps are returned.
TEST_F(AudioEncoderCopyRedTest, CheckPayloadType) {
  MockEncodeHelper helper;

  helper.info_.encoded_bytes = 17;
  const int primary_payload_type = red_payload_type_ + 1;
  helper.info_.payload_type = primary_payload_type;
  EXPECT_CALL(mock_encoder_, EncodeInternal(_, _, _, _, _))
      .WillRepeatedly(Invoke(&helper, &MockEncodeHelper::Encode));

  // First call is a special case, since it does not include a secondary
  // payload.
  Encode();
  ASSERT_EQ(1u, encoded_info_.redundant.size());
  EXPECT_EQ(primary_payload_type, encoded_info_.redundant[0].payload_type);
  EXPECT_EQ(red_payload_type_, encoded_info_.payload_type);

  const int secondary_payload_type = red_payload_type_ + 2;
  helper.info_.payload_type = secondary_payload_type;
  Encode();
  ASSERT_EQ(2u, encoded_info_.redundant.size());
  EXPECT_EQ(secondary_payload_type, encoded_info_.redundant[0].payload_type);
  EXPECT_EQ(primary_payload_type, encoded_info_.redundant[1].payload_type);
  EXPECT_EQ(red_payload_type_, encoded_info_.payload_type);
}

#if GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)

// This test fixture tests various error conditions that makes the
// AudioEncoderCng die via CHECKs.
class AudioEncoderCopyRedDeathTest : public AudioEncoderCopyRedTest {
 protected:
  AudioEncoderCopyRedDeathTest() : AudioEncoderCopyRedTest() {}
};

TEST_F(AudioEncoderCopyRedDeathTest, WrongFrameSize) {
  num_audio_samples_10ms *= 2;  // 20 ms frame.
  EXPECT_DEATH(Encode(), "");
  num_audio_samples_10ms = 0;  // Zero samples.
  EXPECT_DEATH(Encode(), "");
}

TEST_F(AudioEncoderCopyRedDeathTest, NullSpeechEncoder) {
  AudioEncoderCopyRed* red = NULL;
  AudioEncoderCopyRed::Config config;
  config.speech_encoder = NULL;
  EXPECT_DEATH(red = new AudioEncoderCopyRed(config),
               "Speech encoder not provided.");
  // The delete operation is needed to avoid leak reports from memcheck.
  delete red;
}

#endif  // GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID)

}  // namespace webrtc
<|endoftext|>


<commit_before>#define ZIP_DISABLE_DEPRECATED
#include "Archive.h"
#include "zip.h"
#include <stdexcept>
#include <string.h> // memcpy

#define m_zip ((zip*)m_handle)

Archive::Archive(string path, bool createNew)
{
  if(createNew)
    remove(path.c_str());

  int error = 0;
  m_handle = zip_open(path.c_str(), createNew ? ZIP_CREATE : 0, &error);

  if(!m_handle)
    throw runtime_error("Can't open archive '" + path + "'");
}

Archive::~Archive()
{
  zip_close(m_zip);
}

string Archive::getFile(string path)
{
  auto file = zip_fopen(m_zip, path.c_str(), 0);

  if(!file)
    throw runtime_error("Can't find '" + path + "' inside archive");

  char buffer[1024];
  string contents;
  int bytes = 0;

  while((bytes = zip_fread(file, buffer, sizeof buffer)) > 0)
    contents += string(buffer, bytes);

  zip_fclose(file);
  return contents;
}

void Archive::setFile(string path, const string& data)
{
  printf("Adding: '%s'\n", path.c_str());

  auto ptr = static_cast<char*>(std::malloc(data.size()));

  if(!ptr)
    throw std::runtime_error("malloc failed");

  memcpy(ptr, data.data(), data.size());

  auto source = zip_source_buffer(m_zip, ptr, data.size(), 1);

  if(!source)
    throw runtime_error(string("Can't create zip source: ") + zip_strerror(m_zip));

  auto const idx = zip_file_add(m_zip, path.c_str(), source, 0);

  if(idx < 0)
    throw runtime_error("Can't create '" + path + "' inside archive: " + zip_strerror(m_zip));
}

vector<string> Archive::getFilenames()
{
  auto const N = zip_get_num_entries(m_zip, 0);

  vector<string> r;

  for(int i = 0; i < N; ++i)
    r.push_back(zip_get_name(m_zip, i, 0));

  return r;
}

<commit_msg>Remove debug trace<commit_after>#define ZIP_DISABLE_DEPRECATED
#include "Archive.h"
#include "zip.h"
#include <stdexcept>
#include <string.h> // memcpy

#define m_zip ((zip*)m_handle)

Archive::Archive(string path, bool createNew)
{
  if(createNew)
    remove(path.c_str());

  int error = 0;
  m_handle = zip_open(path.c_str(), createNew ? ZIP_CREATE : 0, &error);

  if(!m_handle)
    throw runtime_error("Can't open archive '" + path + "'");
}

Archive::~Archive()
{
  zip_close(m_zip);
}

string Archive::getFile(string path)
{
  auto file = zip_fopen(m_zip, path.c_str(), 0);

  if(!file)
    throw runtime_error("Can't find '" + path + "' inside archive");

  char buffer[1024];
  string contents;
  int bytes = 0;

  while((bytes = zip_fread(file, buffer, sizeof buffer)) > 0)
    contents += string(buffer, bytes);

  zip_fclose(file);
  return contents;
}

void Archive::setFile(string path, const string& data)
{
  auto ptr = static_cast<char*>(std::malloc(data.size()));

  if(!ptr)
    throw std::runtime_error("malloc failed");

  memcpy(ptr, data.data(), data.size());

  auto source = zip_source_buffer(m_zip, ptr, data.size(), 1);

  if(!source)
    throw runtime_error(string("Can't create zip source: ") + zip_strerror(m_zip));

  auto const idx = zip_file_add(m_zip, path.c_str(), source, 0);

  if(idx < 0)
    throw runtime_error("Can't create '" + path + "' inside archive: " + zip_strerror(m_zip));
}

vector<string> Archive::getFilenames()
{
  auto const N = zip_get_num_entries(m_zip, 0);

  vector<string> r;

  for(int i = 0; i < N; ++i)
    r.push_back(zip_get_name(m_zip, i, 0));

  return r;
}

<|endoftext|>


<commit_before>#include "all.h"
#include <algorithm>
#include <vector>
#include <iostream>
#include <initializer_list>
#include <string>
#include <random>

using namespace rubbish;

struct test{
    int data;
    test(int n=0):data(n){}
    void increment(){data++;}
};

int val(helper::avl_tree_node<int> *p) {return p==nullptr?-1:p->data;}

int main(){
    forward_list_base<test> l;
    for(int i=0;i<10;i++)
        l.push_back(test(i));
    for(auto &i:l)
        i.increment();
    std::for_each(l.begin(),l.end(),[](test &t){std::cout<<t.data<<" ";});

    list_base<int> list;
    // Random integer generation
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dist(1,100);
    for(auto i=0;i<10;++i)
        list.push_back(dist(gen));
    for(auto &i:list)
        std::cout<<i<<" ";
    std::cout<<std::endl;
    list.sort();
    for(auto &i:list)
        std::cout<<i<<" ";
    std::cout<<std::endl;
    for(auto it=list.rbegin();it!=list.rend();++it)
        std::cout<<*it<<" ";

    graph<int> a({0,1,2,3,4,5,6},{{0,1},{0,2},{1,3},{2,3},{2,4},{3,5},{4,5}},true);
    std::vector<int> sv;
    struct op{
        std::vector<int> *p;
        void operator()(int c){
            if(p==nullptr)
                std::cout<<c;
            else
                p->push_back(c);
        }
        explicit op(std::vector<int> *_p=nullptr):p(_p){}
    };
    for(auto &i:a)
        std::cout<<i<<" ";
    std::cout<<std::endl;
    for(auto i=a.bfs_begin();i!=a.bfs_end();++i)
        std::cout<<*i<<" ";
    std::cout<<std::endl;
    for(auto i=a.topo_begin();i!=a.topo_end();++i)
        std::cout<<*i<<" ";
    std::cout<<"\nEnd";

    vector<int> v{0,1,2,3,45};
    for(auto &i:v)
        std::cout<<i<<" ";

    avl_tree<int> te({1,2,3,3,3,86,651,32,41,651,984,16,19,41,0});
    for(auto it=te.level_begin();it!=te.level_end();++it){
        auto &&ptr=it.get().front();
        std::cout<<"this:"<<val(ptr)<<" left:"<<val(ptr->left)<<" right:"<<val(ptr->right)<<" parent:"<<val(ptr->parent)<<std::endl;
    }
    for(auto &i:te)
        std::cout<<i<<" ";
    std::cout<<std::endl;
    te.erase(3);
    for(auto &i:te)
        std::cout<<i<<" ";
    std::cout<<std::endl;
    auto x=te.insert(195);
    std::cout<<(x!=te.end()?*x:0)<<std::endl;
    for(auto &i:te)
        std::cout<<i<<" ";
    std::cout<<std::endl;

    bsearch_tree<int> treea({1,5,7,9,5,25,0,1,9,4,1});
    for(auto &i:treea)
        std::cout<<i<<" ";
    std::cout<<std::endl;
    for(auto it=treea.level_begin();it!=treea.level_end();++it)
        std::cout<<(*it)<<" ";
    std::cout<<"\nExit successfully.";

    binary_tree_base<int> treeb({1,2,3,4,5,6,7,8,9,10},0);
    for(auto it=treeb.preorder_begin();it!=treeb.preorder_end();++it)
        std::cout<<(*it)<<",";
    std::cout<<std::endl;
    for(auto it=treeb.inorder_begin();it!=treeb.inorder_end();++it)
        std::cout<<(*it)<<",";
    std::cout<<std::endl;
    for(auto it=treeb.postorder_begin();it!=treeb.postorder_end();++it)
        std::cout<<(*it)<<",";
    std::cout<<std::endl;
    for(auto it=treeb.level_begin();it!=treeb.level_end();++it)
        std::cout<<(*it)<<",";
    binary_tree_base<int> treeba({1,2,4,8,9,5,10,3,6,7},{8,4,9,2,10,5,1,6,3,7});
    for(auto it=treeba.level_begin();it!=treeba.level_end();++it)
        std::cout<<(*it)<<",";

    continuous_container<int> cc(10,2);
    for(auto &i:cc)
        std::cout<<i<<" ";

    const std::string str("abc");
    map<std::string,int> m={{"abc",2568},{"ffg",45},{"eat",445}};
    std::cout<<m.find(std::string("abc"))->second<<" ";
    m.find(std::string(str))->second+=554;
    std::cout<<m.find(std::string(str))->second;
    m.erase(std::string("ffg"));
    for(auto &i:m)
        std::cout<<i.first<<" "<<i.second;

    return 0;
}
<commit_msg>Rewrite test code<commit_after>#include "all.h"
#include <algorithm>
#include <vector>
#include <iostream>
#include <initializer_list>
#include <string>
#include <random>

#define MESSAGE(msg) std::cout<<msg<<std::endl

using namespace rubbish;

void continuous_container_test();
void vector_test();
void forward_list_test();
void list_test();
void binary_tree_test();
void bsearch_tree_test();
void avl_tree_test();
void map_test();
void graph_test();

int main(){
    continuous_container_test();
    vector_test();
    forward_list_test();
    list_test();
    binary_tree_test();
    bsearch_tree_test();
    avl_tree_test();
    map_test();
    graph_test();
    MESSAGE("\nAll tests are done.");
    return 0;
}

void forward_list_test(){
    struct test{
        int data;
        test(int n=0):data(n){}
        void increment(){data++;}
    };

    MESSAGE("forward_list tests begin. Involving push_back() and iterators.");
    forward_list<test> l;
    MESSAGE("forward_list default initialized.");
    for(int i=0;i<10;i++)
        l.push_back(test(i));
    MESSAGE("push_back() 0-9 successful.");
    for(auto &i:l)
        i.increment();
    MESSAGE("range based for loop(i.e. iterators) successful. Elements:");
    std::for_each(l.begin(),l.end(),[](test &t){std::cout<<t.data<<" ";});
    MESSAGE("\nforward_list tests end.\n");
}

void list_test(){
    MESSAGE("list tests begin. Involving push_back(),sort() and iterators.");
    list<int> list;
    MESSAGE("list default initialized.");
    // Random integer generation
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_int_distribution<int> dist(1,100);
    for(auto i=0;i<10;++i)
        list.push_back(dist(gen));
    MESSAGE("push_back() 10 ints successful.");
    MESSAGE("range based for loop(i.e. iterators) begins:");
    for(auto &i:list)
        std::cout<<i<<" ";
    MESSAGE("\nsorted elements:");
    list.sort();
    for(auto &i:list)
        std::cout<<i<<" ";
    MESSAGE("\nReverse iterator tests, trying to output elements:");
    for(auto it=list.rbegin();it!=list.rend();++it)
        std::cout<<*it<<" ";
    MESSAGE("\nlist tests end.\n");
}

void graph_test(){
    MESSAGE("graph tests begin. Involving iterators only.");
    graph<int> a({0,1,2,3,4,5,6},{{0,1},{0,2},{1,3},{2,3},{2,4},{3,5},{4,5}},true);
    MESSAGE("graph direct initialized with an adjacency list successful.");
    std::vector<int> sv;
    struct op{
        std::vector<int> *p;
        void operator()(int c){
            if(p==nullptr)
                std::cout<<c;
            else
                p->push_back(c);
        }
        explicit op(std::vector<int> *_p=nullptr):p(_p){}
    };
    MESSAGE("depth first iterators tests, trying to output elements:");
    for(auto &i:a)
        std::cout<<i<<" ";
    MESSAGE("\nbreadth first iterators tests, trying to output elements:");
    for(auto i=a.bfs_begin();i!=a.bfs_end();++i)
        std::cout<<*i<<" ";
    MESSAGE("\ntopological iterators tests, trying to output elements:");
    for(auto i=a.topo_begin();i!=a.topo_end();++i)
        std::cout<<*i<<" ";
    MESSAGE("\ngraph tests end.\n");
}

void continuous_container_test(){
    MESSAGE("continuous_container tests begin. Involving iterators only.");
    continuous_container<int> cc(10,2);
    MESSAGE("continuous_container filled with 10 elements whose value is 2. Outputting:");
    for(auto &i:cc)
        std::cout<<i<<" ";
    MESSAGE("\ncontinuous_container tests end.\n");
}

void vector_test(){
    MESSAGE("vector tests begin. Involving iterators only.");
    vector<int> v{0,1,2,3,45};
    MESSAGE("vector direct initialized with an initializer list successful.");
    for(auto &i:v)
        std::cout<<i<<" ";
    MESSAGE("\nvector tests end.\n");
}

void avl_tree_test(){
    auto val=[](helper::avl_tree_node<int> *p) {return p==nullptr?-1:p->data;};
    MESSAGE("avl_tree tests begin. Involving insert(),erase() and iterators.");
    avl_tree<int> te({1,2,3,3,3,86,651,32,41,651,984,16,19,41,0});
    MESSAGE("avl_tree direct initialized with an initializer list successful. Outputting nodes in level order:");
    for(auto it=te.level_begin();it!=te.level_end();++it){
        auto &&ptr=it.get().front();
        std::cout<<"this:"<<val(ptr)<<" left:"<<val(ptr->left)<<" right:"<<val(ptr->right)<<" parent:"<<val(ptr->parent)<<std::endl;
    }
    MESSAGE("Outputting nodes in in-order:");
    for(auto &i:te)
        std::cout<<i<<" ";
    te.erase(3);
    MESSAGE("\nerase(3) executed:");
    for(auto &i:te)
        std::cout<<i<<" ";
    MESSAGE("insert(195) and tests with the returned iterator:");
    auto x=te.insert(195);
    std::cout<<(x!=te.end()?*x:0)<<std::endl;
    MESSAGE("Outputting nodes in in-order again:");
    for(auto &i:te)
        std::cout<<i<<" ";
    MESSAGE("\navl_tree tests end.\n");
}

void bsearch_tree_test(){
    MESSAGE("bsearch_tree tests begin. Involving iterators only.");
    bsearch_tree<int> tree({1,5,7,9,5,25,0,1,9,4,1});
    MESSAGE("bsearch_tree direct initialized with an initializer list successful. Outputting nodes in in-order:");
    for(auto &i:tree)
        std::cout<<i<<" ";
    MESSAGE("\nOutputting nodes in level order:");
    for(auto it=tree.level_begin();it!=tree.level_end();++it)
        std::cout<<(*it)<<" ";
    MESSAGE("\nbsearch_tree tests end.\n");
}

void binary_tree_test(){
    MESSAGE("binary_tree tests begin. Involving iterators only.");
    binary_tree<int> tree({1,2,3,4,5,6,7,8,9,10},0);
    MESSAGE("binary_tree initialized with an level order serialization successful. Outputting in pre-order:");
    for(auto it=tree.preorder_begin();it!=tree.preorder_end();++it)
        std::cout<<(*it)<<" ";
    MESSAGE("\nOutputting nodes in in-order:");
    for(auto it=tree.inorder_begin();it!=tree.inorder_end();++it)
        std::cout<<(*it)<<" ";
    MESSAGE("\nOutputting nodes in post-order:");
    for(auto it=tree.postorder_begin();it!=tree.postorder_end();++it)
        std::cout<<(*it)<<" ";
    MESSAGE("\nOutputting nodes in level order:");
    for(auto it=tree.level_begin();it!=tree.level_end();++it)
        std::cout<<(*it)<<" ";
    binary_tree<int> treea({1,2,4,8,9,5,10,3,6,7},{8,4,9,2,10,5,1,6,3,7});
    MESSAGE("\nAnother binary_tree initialized with pre-order and in-order serialization successful. Outputting in level order:");
    for(auto it=treea.level_begin();it!=treea.level_end();++it)
        std::cout<<(*it)<<" ";
    MESSAGE("\nbinary_tree tests end.\n");
}

void map_test(){
    MESSAGE("map tests begin. Involving find(),erase(),iterators and pair utility.");
    const std::string str("abc");
    map<std::string,int> m={{"abc",2568},{"ffg",45},{"eat",445}};
    MESSAGE("map initialized with an initializer list successful.\nThe list is:{\"abc\",2568},{\"ffg\",45},{\"eat\",445}\nFinding \"abc\" in map:");
    std::cout<<m.find(std::string("abc"))->second<<" "<<std::endl;
    MESSAGE("Add 554 to \"abc\"'s corresponding value successful. Reprinting:");
    m.find(std::string(str))->second+=554;
    std::cout<<m.find(std::string(str))->second<<std::endl;
    m.erase(std::string("ffg"));
    MESSAGE("\"ffg\" deleted. Outputting nodes:");
    for(auto &i:m)
        std::cout<<i.first<<" "<<i.second<<std::endl;
    MESSAGE("map tests end.\n");
}

#undef MESSAGE
<|endoftext|>


<commit_before>#include <iostream>
#include "../inc/Frisk.h"
#include "../inc/ConsoleReporter.h"

int mult(int x, int y) { return x * y; }

DEF_TEST(mult_test)
{
  BEGIN_TEST(self);

  self.setOption(FRISK_OPTION_CONTINUE, true);

  EXPECT_EQUAL(self, mult(0, 0), 0, "0 times anything should be 0");
  EXPECT_EQUAL(self, mult(0, 5), 0, "0 times anything should be 0");
  EXPECT_EQUAL(self, mult(5, 0), 0, "0 times anything should be 0");
  EXPECT_EQUAL(self, mult(1, 5), 5, "1 times anything is itself");
  EXPECT_EQUAL(self, mult(5, 1), 5, "1 times anything is itself");
  EXPECT_EQUAL(self, mult(5, 5), 25, "5 times itself is its square");
  EXPECT_EQUAL(self, mult(1, -5), -5, "1 times a negative number is that negative number");
  EXPECT_EQUAL(self, mult(-5, 1), -5, "1 times a negative number is that negative number");
  EXPECT_GREATER(self, mult(-5, -5), 0, "Two negatives mutlipled should be positive.");
  EXPECT_LESS(self, mult(-5, 5), 0, "One negative times one positive should be negative.");
}

int main()
{
	Frisk::TestCollection tests;
  tests.addTest(mult_test, "mult_test");

	Frisk::ConsoleReporter reporter;
  reporter.setOption("description", true);
	std::list<Frisk::Test> results = tests.runTests(false, &reporter);

	return 1;
}
<commit_msg>Updated demo main to return failure/pass depending on if any tests failed<commit_after>#include <iostream>
#include "../inc/Frisk.h"
#include "../inc/ConsoleReporter.h"

int mult(int x, int y) { return x * y; }

DEF_TEST(mult_test)
{
  BEGIN_TEST(self);

  self.setOption(FRISK_OPTION_CONTINUE, true);

  EXPECT_EQUAL(self, mult(0, 0), 0, "0 times anything should be 0");
  EXPECT_EQUAL(self, mult(0, 5), 0, "0 times anything should be 0");
  EXPECT_EQUAL(self, mult(5, 0), 0, "0 times anything should be 0");
  EXPECT_EQUAL(self, mult(1, 5), 5, "1 times anything is itself");
  EXPECT_EQUAL(self, mult(5, 1), 5, "1 times anything is itself");
  EXPECT_EQUAL(self, mult(5, 5), 25, "5 times itself is its square");
  EXPECT_EQUAL(self, mult(1, -5), -5, "1 times a negative number is that negative number");
  EXPECT_EQUAL(self, mult(-5, 1), -5, "1 times a negative number is that negative number");
  EXPECT_GREATER(self, mult(-5, -5), 0, "Two negatives mutlipled should be positive.");
  EXPECT_LESS(self, mult(-5, 5), 0, "One negative times one positive should be negative.");
}

int main()
{
	Frisk::TestCollection tests;
  tests.addTest(mult_test, "mult_test");

	Frisk::ConsoleReporter reporter;
  reporter.setOption("description", true);
	std::list<Frisk::Test> results = tests.runTests(false, &reporter);

	for (std::list<Frisk::Test>::iterator it = results.begin(); it != results.end(); it++)
  {
    if ((*it).getFailureCount() != 0)
      return 1;
  }

  return 0;
}
<|endoftext|>