/*
 *  entropy calculator
 *
 *  Copyright (c) 2008, Veacheslav Patkov.
 *  aLL rigths reserved.
 *
 *  Licensed under GNU GPL v2
 *
 */

#include <windows.h>
#include <stdio.h>
#include <math.h>

#include "../../../pdk/include/plugin.h"
#include "rsrc.h"

#define ENTROPY_VERSION "0.01"

#define BUFSIZE 512

HINSTANCE hinst;
HWND hDLG;
plug_interface *pif;
char buf[BUFSIZE];

unsigned int get_entropy(char *fname, double *pentropy)
{
    HANDLE f, fm;
    char *fmp, *p;
    unsigned int i, cnt = 0, fsize;
    double entropy = 0, ln2 = log(2);
    static unsigned int freq[257];
    static double prob[257], entr[257];

    if ((f = CreateFile(fname,GENERIC_READ,FILE_SHARE_READ,0,OPEN_ALWAYS,
                        FILE_ATTRIBUTE_NORMAL,0)) == INVALID_HANDLE_VALUE) {
        sprintf(buf,"Cannot open file `%s'",fname);
        MessageBox(hDLG,buf,"Error !",MB_ICONERROR);
        return 0;
    }
    if (!(fsize = (unsigned int)GetFileSize(f,0)) || fsize == -1) {
        sprintf(buf,"Empty file `%s'",fname);
        MessageBox(hDLG,buf,"Error !",MB_ICONERROR);
        return 0;
    }
    if (!(fm = CreateFileMapping(f,0,PAGE_READONLY,0,0,0)) ||
        !(fmp = (char *)MapViewOfFile(fm,FILE_MAP_READ,0,0,0))) {
        sprintf(buf,"Cannot map file `%s'",fname);
        MessageBox(hDLG,buf,"Error !",MB_ICONERROR);
        return 0;
    }

    for (i = 0; i <= 256; i++)
        freq[i] = 0;
    for (i = 0, p = fmp; i < fsize; i++, p++) {
        freq[(unsigned char)*p]++;
        cnt++;
    }

    UnmapViewOfFile(fmp);
    CloseHandle(fm);
    CloseHandle(f);

    for (i = 0; i <= 256; i++)
        prob[i] = freq[i]/(double)cnt;
    for (i = 0; i <= 256; i++) {
        if (!freq[i])
            continue;
        entr[i] = -prob[i]*log(prob[i])/ln2;
        entropy += entr[i];
    }

    *pentropy = entropy;
    return cnt;
}

BOOL dialog_main(HWND hdlg, UINT umsg, WPARAM wparam, LPARAM lparam)
{
    HWND hIDC_BAR;
    unsigned int len;
    double entropy;

    switch (umsg)
    {
        case WM_INITDIALOG:
            hDLG = hdlg;
            SendMessage(hdlg,WM_SETTEXT,0,(LPARAM)" [ Entropy Calculator ]");

            if (!(len = get_entropy(pif->fname,&entropy)))
                goto end_dialog;
            sprintf(buf,"Length: %u bytes (%u bits)",len,len*8);
            SetDlgItemText(hdlg,IDC_LENGTH,buf);
            sprintf(buf,"Entropy: %.4f (%spacked)",entropy,entropy > 6.5 ? "" : "not ");
            SetDlgItemText(hdlg,IDC_ENTROPY,buf);
            hIDC_BAR = GetDlgItem(hdlg,IDC_BAR);
            SendMessage(hIDC_BAR,WM_USER+5,1,(LPARAM)floor(entropy*100.0/8.0));
            EnableWindow(hIDC_BAR,0);

            break;

        case WM_COMMAND:
            switch (LOWORD(wparam)) {
                case IDC_ABOUT:
                    MessageBox(hdlg,
                               "Entropy Calculator version " ENTROPY_VERSION "\n"
                               "Copyright \xa9 2008 Veacheslav Patkov\n"
                               "All rights reserved.",
                               " [ Entropy Calculator ] - about...",
                               MB_ICONINFORMATION);
                    break;
                case IDC_CLOSE:
                    goto end_dialog;
            }
            break;

        case WM_CLOSE:
          end_dialog:
            EndDialog(hdlg,0);
            break;
    }
    return 0;
}

char *pname(void)
{
    return "Entropy Calculator";
}

void pmain(plug_interface *pi)
{
    if (!*pi->fname) {
        MessageBox(0,"File name is not selected !","Error !",MB_ICONERROR);
        return;
    }
    pif = pi;
    DialogBoxParam(hinst,MAKEINTRESOURCE(IDD_DIALOG),pi->hwnd,(DLGPROC)&dialog_main,0);
    return;
}

int __stdcall dllentry(HINSTANCE hinstance, DWORD reason, LPVOID reserved)
{
    hinst = hinstance;
    return 1;
}
