major plugin revamp based on x-fixer's code
[flac.git] / src / plugin_winamp2 / infobox.c
index 43a1fe5..d94054d 100644 (file)
+/* in_flac - Winamp2 FLAC input plugin\r
+ * Copyright (C) 2002,2003,2004  Josh Coalson\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License\r
+ * as published by the Free Software Foundation; either version 2\r
+ * of the License, or (at your option) any later version.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\r
+ */\r
+\r
 #include <windows.h>\r
 #include <stdio.h>\r
 #include "FLAC/all.h"\r
 #include "plugin_common/all.h"\r
 #include "infobox.h"\r
+#include "config.h"\r
 #include "resource.h"\r
 \r
 \r
 typedef struct\r
 {\r
-    char filename[MAX_PATH];\r
+       char filename[MAX_PATH];\r
+       FLAC_Plugin__CanonicalTag tag;\r
 } LOCALDATA;\r
 \r
-static char buffer[256];\r
+static char buffer[1024];\r
 static char *genres = NULL;\r
-static int  genresSize = 0, genresCount = 0, genresChanged = 0;\r
+static DWORD genresSize = 0, genresCount = 0;\r
+static BOOL genresChanged = FALSE, isNT;\r
 \r
 static const char infoTitle[] = "FLAC File Info";\r
 \r
-//fixme int64\r
-static __inline DWORD FileSize(const char *file)\r
-{\r
-    HANDLE hFile = CreateFile(file, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
-    DWORD res;\r
+/*\r
+ *  Genres\r
+ */\r
 \r
-    if (hFile == INVALID_HANDLE_VALUE) return 0;\r
-    res = GetFileSize(hFile, 0);\r
-    CloseHandle(hFile);\r
-    return res;\r
-}\r
+/* TODO: write genres in utf-8 ? */\r
 \r
 static __inline int GetGenresFileName(char *buffer, int size)\r
 {\r
-    char *c;\r
+       char *c;\r
 \r
-    if (!GetModuleFileName(NULL, buffer, size))\r
-        return 0;\r
-    c = strrchr(buffer, '\\');\r
-    if (!c) return 0;\r
-    strcpy(c+1, "genres.txt");\r
+       if (!GetModuleFileName(NULL, buffer, size))\r
+               return 0;\r
+       c = strrchr(buffer, '\\');\r
+       if (!c) return 0;\r
+       strcpy(c+1, "genres.txt");\r
 \r
-    return 1;\r
+       return 1;\r
 }\r
 \r
 static void LoadGenres()\r
 {\r
-    HANDLE hFile;\r
-    DWORD  spam;\r
-    char  *c;\r
-\r
-    if (!GetGenresFileName(buffer, sizeof(buffer))) return;\r
-    // load file\r
-    hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
-    if (hFile == INVALID_HANDLE_VALUE) return;\r
-    genresSize = GetFileSize(hFile, 0);\r
-    if (!genresSize) return;\r
-    genres = (char*)malloc(genresSize+2);\r
-    if (!genres) return;\r
-    if (!ReadFile(hFile, genres, genresSize, &spam, NULL))\r
-    {\r
-        free(genres);\r
-        genres = NULL;\r
-        return;\r
-    }\r
-    genres[genresSize] = 0;\r
-    genres[genresSize+1] = 0;\r
-    // replace newlines\r
-    genresChanged = 0;\r
-    genresCount = 1;\r
-\r
-    for (c=genres; *c; c++)\r
-    {\r
-        if (*c == 10)\r
-        {\r
-            *c = 0;\r
-            if (*(c+1))\r
-                genresCount++;\r
-            else genresSize--;\r
-        }\r
-    }\r
-\r
-    CloseHandle(hFile);\r
+       HANDLE hFile;\r
+       DWORD  spam;\r
+       char  *c;\r
+\r
+       FLAC__ASSERT(0 != genres);\r
+\r
+       if (!GetGenresFileName(buffer, sizeof(buffer))) return;\r
+       /* load file */\r
+       hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+       if (hFile == INVALID_HANDLE_VALUE) return;\r
+       genresSize = GetFileSize(hFile, 0);\r
+       if (genresSize && (genres = (char*)malloc(genresSize+2)))\r
+       {\r
+               if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)\r
+               {\r
+                       free(genres);\r
+                       genres = NULL;\r
+               }\r
+               else\r
+               {\r
+                       genres[genresSize] = 0;\r
+                       genres[genresSize+1] = 0;\r
+                       /* replace newlines */\r
+                       genresChanged = FALSE;\r
+                       genresCount = 1;\r
+\r
+                       for (c=genres; *c; c++)\r
+                       {\r
+                               if (*c == 10)\r
+                               {\r
+                                       *c = 0;\r
+                                       if (*(c+1))\r
+                                               genresCount++;\r
+                                       else genresSize--;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+\r
+       CloseHandle(hFile);\r
 }\r
 \r
 static void SaveGenres(HWND hlist)\r
 {\r
-    HANDLE hFile;\r
-    DWORD  spam;\r
-    int i, count, len;\r
-\r
-    if (!GetGenresFileName(buffer, sizeof(buffer))) return;\r
-    // write file\r
-    hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
-    if (hFile == INVALID_HANDLE_VALUE) return;\r
-\r
-    count = SendMessage(hlist, CB_GETCOUNT, 0, 0);\r
-    for (i=0; i<count; i++)\r
-    {\r
-        SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);\r
-        len = strlen(buffer);\r
-        if (i != count-1)\r
-        {\r
-            buffer[len] = 10;\r
-            len++;\r
-        }\r
-        WriteFile(hFile, buffer, len, &spam, NULL);\r
-    }\r
-\r
-    CloseHandle(hFile);\r
+       HANDLE hFile;\r
+       DWORD  spam;\r
+       int i, count, len;\r
+\r
+       if (!GetGenresFileName(buffer, sizeof(buffer))) return;\r
+       /* write file */\r
+       hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);\r
+       if (hFile == INVALID_HANDLE_VALUE) return;\r
+\r
+       count = SendMessage(hlist, CB_GETCOUNT, 0, 0);\r
+       for (i=0; i<count; i++)\r
+       {\r
+               SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);\r
+               len = strlen(buffer);\r
+               if (i != count-1)\r
+               {\r
+                       buffer[len] = 10;\r
+                       len++;\r
+               }\r
+               WriteFile(hFile, buffer, len, &spam, NULL);\r
+       }\r
+\r
+       CloseHandle(hFile);\r
 }\r
 \r
+static void AddGenre(HWND hwnd, const char *genre)\r
+{\r
+       HWND hgen = GetDlgItem(hwnd, IDC_GENRE);\r
+\r
+       if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)\r
+       {\r
+               genresChanged = TRUE;\r
+               SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);\r
+       }\r
+}\r
+\r
+static void InitGenres(HWND hwnd)\r
+{\r
+       HWND hgen = GetDlgItem(hwnd, IDC_GENRE);\r
+       char *c;\r
+\r
+       /* set text length limit to 64 chars */\r
+       SendMessage(hgen, CB_LIMITTEXT, 64, 0);\r
+       /* try to load genres */\r
+       if (!genres)\r
+               LoadGenres(hgen);\r
+       /* add the to list */\r
+       if (genres)\r
+       {\r
+               SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);\r
+\r
+               for (c = genres; *c; c += strlen(c)+1)\r
+                       SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);\r
+       }\r
+}\r
+\r
+static void DeinitGenres(HWND hwnd, BOOL final)\r
+{\r
+       if (genresChanged && hwnd)\r
+       {\r
+               SaveGenres(GetDlgItem(hwnd, IDC_GENRE));\r
+               genresChanged = FALSE;\r
+               final = TRUE;\r
+       }\r
+       if (final)\r
+       {\r
+               free(genres);\r
+               genres = 0;\r
+       }\r
+}\r
+\r
+/*\r
+ *  Infobox helpers\r
+ */\r
+\r
+#define SetText(x,y)            WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, FLAC_plugin__canonical_get(&data->tag, y), -1, buffer, sizeof(buffer), NULL, NULL); \\r
+                                SetDlgItemText(hwnd, x, buffer)\r
+\r
+#define GetText(x,y)            GetDlgItemText(hwnd, x, buffer, sizeof(buffer));                        \\r
+                                if (*buffer) FLAC_plugin__canonical_set_ansi(&data->tag, y, buffer);    \\r
+                                else FLAC_plugin__canonical_remove_all(&data->tag, y)\r
+\r
+#define SetTextW(x,y)           SetDlgItemTextW(hwnd, x, FLAC_plugin__canonical_get(&data->tag, y))\r
+\r
+#define GetTextW(x,y)           GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2);                     \\r
+                                if (*(WCHAR*)buffer) FLAC_plugin__canonical_set(&data->tag, y, (WCHAR*)buffer); \\r
+                                else FLAC_plugin__canonical_remove_all(&data->tag, y)\r
 \r
-#define SetText(x,y)            SetDlgItemText(hwnd, x, y)\r
-#define GetText(x,y)            (GetDlgItemText(hwnd, x, buffer, sizeof(buffer)), y = buffer[0] ? strdup(buffer) : 0)\r
 \r
-static BOOL InitInfobox(HWND hwnd, const char *file)\r
+static BOOL InitInfoboxInfo(HWND hwnd, const char *file)\r
 {\r
-    LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));\r
+       LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));\r
        FLAC__StreamMetadata streaminfo;\r
-    FLAC_Plugin__CanonicalTag tag;\r
-    DWORD filesize, length, bps, ratio;\r
-\r
-    SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);\r
-    // file name\r
-    strncpy(data->filename, file, sizeof(data->filename));\r
-    SetDlgItemText(hwnd, IDC_NAME, file);\r
-    // stream data\r
-    filesize = FileSize(file);\r
-    if (!filesize) return FALSE;\r
+       DWORD    length, bps, ratio, rg;\r
+       LONGLONG filesize;\r
+\r
+       SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);\r
+       /* file name */\r
+       strncpy(data->filename, file, sizeof(data->filename));\r
+       SetDlgItemText(hwnd, IDC_NAME, file);\r
+       /* stream data and vorbis comment */\r
+       filesize = FileSize(file);\r
+       if (!filesize) return FALSE;\r
        if (!FLAC__metadata_get_streaminfo(file, &streaminfo))\r
-        return FALSE;\r
-\r
-    length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);\r
-    bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));\r
-    ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);\r
-\r
-    sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"\r
-                    "File size: %d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n",\r
-        streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,\r
-        streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,\r
-        length/60, length%60, bps, ratio/10, ratio%10);\r
-    //todo: replaygain\r
-\r
-    SetDlgItemText(hwnd, IDC_INFO, buffer);\r
-    // tag\r
-       FLAC_plugin__canonical_tag_init(&tag);\r
-       FLAC_plugin__canonical_tag_get_combined(file, &tag);\r
-\r
-    SetText(IDC_TITLE,   tag.title);\r
-    SetText(IDC_ARTIST,  tag.performer ? tag.performer : tag.composer);\r
-    SetText(IDC_ALBUM,   tag.album);\r
-    SetText(IDC_COMMENT, tag.comment);\r
-    SetText(IDC_YEAR,    tag.year_recorded ? tag.year_recorded : tag.year_performed);\r
-    SetText(IDC_TRACK,   tag.track_number);\r
-    SetText(IDC_GENRE,   tag.genre);\r
-\r
-       FLAC_plugin__canonical_tag_clear(&tag);\r
-\r
-    return TRUE;\r
+               return FALSE;\r
+       ReadTags(file, &data->tag, false);\r
+\r
+       length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);\r
+       bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));\r
+       ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);\r
+       rg  = FLAC_plugin__canonical_get(&data->tag, L"REPLAYGAIN_TRACK_GAIN") ? 1 : 0;\r
+       rg |= FLAC_plugin__canonical_get(&data->tag, L"REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;\r
+\r
+       sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"\r
+                       "File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"\r
+                       "ReplayGain: %s\n",\r
+           streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,\r
+           streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,\r
+           length/60, length%60, bps, ratio/10, ratio%10,\r
+           rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");\r
+\r
+       SetDlgItemText(hwnd, IDC_INFO, buffer);\r
+       /* tag */\r
+       if (isNT)\r
+       {\r
+               SetTextW(IDC_TITLE,   L"TITLE");\r
+               SetTextW(IDC_ARTIST,  L"ARTIST");\r
+               SetTextW(IDC_ALBUM,   L"ALBUM");\r
+               SetTextW(IDC_COMMENT, L"DESCRIPTION");\r
+               SetTextW(IDC_YEAR,    L"DATE");\r
+               SetTextW(IDC_TRACK,   L"TRACKNUMBER");\r
+               SetTextW(IDC_GENRE,   L"GENRE");\r
+       }\r
+       else\r
+       {\r
+               SetText(IDC_TITLE,   L"TITLE");\r
+               SetText(IDC_ARTIST,  L"ARTIST");\r
+               SetText(IDC_ALBUM,   L"ALBUM");\r
+               SetText(IDC_COMMENT, L"DESCRIPTION");\r
+               SetText(IDC_YEAR,    L"DATE");\r
+               SetText(IDC_TRACK,   L"TRACKNUMBER");\r
+               SetText(IDC_GENRE,   L"GENRE");\r
+       }\r
+\r
+       return TRUE;\r
 }\r
 \r
 static void __inline SetTag(HWND hwnd, const char *filename, FLAC_Plugin__CanonicalTag *tag)\r
 {\r
-    strcpy(buffer, infoTitle);\r
+       strcpy(buffer, infoTitle);\r
 \r
        if (FLAC_plugin__vorbiscomment_set(filename, tag))\r
-        strcat(buffer, " [Updated]");\r
-    else strcat(buffer, " [Failed]");\r
+               strcat(buffer, " [Updated]");\r
+       else strcat(buffer, " [Failed]");\r
 \r
-    SetWindowText(hwnd, buffer);\r
+       SetWindowText(hwnd, buffer);\r
 }\r
 \r
 static void UpdateTag(HWND hwnd)\r
 {\r
-    LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
-    FLAC_Plugin__CanonicalTag tag;\r
-       FLAC_plugin__canonical_tag_init(&tag);\r
-\r
-    // get fields\r
-    GetText(IDC_TITLE,   tag.title);\r
-    GetText(IDC_ARTIST,  tag.composer);\r
-    GetText(IDC_ALBUM,   tag.album);\r
-    GetText(IDC_COMMENT, tag.comment);\r
-    GetText(IDC_YEAR,    tag.year_recorded);\r
-    GetText(IDC_TRACK,   tag.track_number);\r
-    GetText(IDC_GENRE,   tag.genre);\r
-\r
-    // update genres list\r
-    if (tag.genre)\r
-    {\r
-        HWND hgen = GetDlgItem(hwnd, IDC_GENRE);\r
-\r
-        if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)tag.genre) == CB_ERR)\r
-        {\r
-            genresChanged = 1;\r
-            SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)tag.genre);\r
-        }\r
-    }\r
-\r
-    // write tag\r
-    SetTag(hwnd, data->filename, &tag);\r
-       FLAC_plugin__canonical_tag_clear(&tag);\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+\r
+       /* get fields */\r
+       if (isNT)\r
+       {\r
+               GetTextW(IDC_TITLE,   L"TITLE");\r
+               GetTextW(IDC_ARTIST,  L"ARTIST");\r
+               GetTextW(IDC_ALBUM,   L"ALBUM");\r
+               GetTextW(IDC_COMMENT, L"DESCRIPTION");\r
+               GetTextW(IDC_YEAR,    L"DATE");\r
+               GetTextW(IDC_TRACK,   L"TRACKNUMBER");\r
+               GetTextW(IDC_GENRE,   L"GENRE");\r
+\r
+               WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, FLAC_plugin__canonical_get(&data->tag, L"GENRE"), -1, buffer, sizeof(buffer), NULL, NULL);\r
+       }\r
+       else\r
+       {\r
+               GetText(IDC_TITLE,   L"TITLE");\r
+               GetText(IDC_ARTIST,  L"ARTIST");\r
+               GetText(IDC_ALBUM,   L"ALBUM");\r
+               GetText(IDC_COMMENT, L"DESCRIPTION");\r
+               GetText(IDC_YEAR,    L"DATE");\r
+               GetText(IDC_TRACK,   L"TRACKNUMBER");\r
+               GetText(IDC_GENRE,   L"GENRE");\r
+       }\r
+\r
+       /* update genres list (buffer should contain genre) */\r
+       if (buffer[0]) AddGenre(hwnd, buffer);\r
+\r
+       /* write tag */\r
+       SetTag(hwnd, data->filename, &data->tag);\r
 }\r
 \r
 static void RemoveTag(HWND hwnd)\r
 {\r
-    LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
-    FLAC_Plugin__CanonicalTag tag;\r
-       FLAC_plugin__canonical_tag_init(&tag);\r
-\r
-    SetText(IDC_TITLE,   "");\r
-    SetText(IDC_ARTIST,  "");\r
-    SetText(IDC_ALBUM,   "");\r
-    SetText(IDC_COMMENT, "");\r
-    SetText(IDC_YEAR,    "");\r
-    SetText(IDC_TRACK,   "");\r
-    SetText(IDC_GENRE,   "");\r
-\r
-    SetTag(hwnd, data->filename, &tag);\r
+       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+       FLAC_plugin__canonical_tag_clear(&data->tag);\r
+\r
+       SetDlgItemText(hwnd, IDC_TITLE,   "");\r
+       SetDlgItemText(hwnd, IDC_ARTIST,  "");\r
+       SetDlgItemText(hwnd, IDC_ALBUM,   "");\r
+       SetDlgItemText(hwnd, IDC_COMMENT, "");\r
+       SetDlgItemText(hwnd, IDC_YEAR,    "");\r
+       SetDlgItemText(hwnd, IDC_TRACK,   "");\r
+       SetDlgItemText(hwnd, IDC_GENRE,   "");\r
+\r
+       SetTag(hwnd, data->filename, &data->tag);\r
 }\r
 \r
 \r
 static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
 {\r
-    switch (msg)\r
-    {\r
-    // init\r
-    case WM_INITDIALOG:\r
-        SetWindowText(hwnd, infoTitle);\r
-        // init genres list\r
-        {\r
-            HWND hgen = GetDlgItem(hwnd, IDC_GENRE);\r
-            char *c;\r
-\r
-            // set text length limit to 64 chars\r
-            SendMessage(hgen, CB_LIMITTEXT, 64, 0);\r
-            // try to load genres\r
-            if (!genres) LoadGenres(hgen);\r
-            // add the to list\r
-            if (genres)\r
-            {\r
-                SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);\r
-\r
-                for (c = genres; *c; c += strlen(c)+1)\r
-                    SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);\r
-            }\r
-        }\r
-        // init fields\r
-        if (!InitInfobox(hwnd, (const char*)lParam))\r
-            PostMessage(hwnd, WM_CLOSE, 0, 0);\r
-        return TRUE;\r
-    // destroy\r
-    case WM_DESTROY:\r
-        if (genresChanged)\r
-        {\r
-            SaveGenres(GetDlgItem(hwnd, IDC_GENRE));\r
-            free(genres);\r
-            genres = 0;\r
-        }\r
-        LocalFree((LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA));\r
-        break;\r
-    // commands\r
-    case WM_COMMAND:\r
-        switch (LOWORD(wParam))\r
-        {\r
-        // ok/cancel\r
-        case IDOK:\r
-        case IDCANCEL:\r
-            EndDialog(hwnd, LOWORD(wParam));\r
-            return TRUE;\r
-        // save\r
-        case IDC_UPDATE:\r
-            UpdateTag(hwnd);\r
-            break;\r
-        // remove\r
-        case IDC_REMOVE:\r
-            RemoveTag(hwnd);\r
-            break;\r
-        }\r
-        break;\r
-    }\r
-\r
-    return 0;\r
+       switch (msg)\r
+       {\r
+       /* init */\r
+       case WM_INITDIALOG:\r
+               SetWindowText(hwnd, infoTitle);\r
+               InitGenres(hwnd);\r
+               /* init fields */\r
+               if (!InitInfoboxInfo(hwnd, (const char*)lParam))\r
+                       PostMessage(hwnd, WM_CLOSE, 0, 0);\r
+               return TRUE;\r
+       /* destroy */\r
+       case WM_DESTROY:\r
+               {\r
+                       LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);\r
+                       FLAC_plugin__canonical_tag_clear(&data->tag);\r
+                       LocalFree(data);\r
+                       DeinitGenres(hwnd, FALSE);\r
+               }\r
+               break;\r
+       /* commands */\r
+       case WM_COMMAND:\r
+               switch (LOWORD(wParam))\r
+               {\r
+               /* ok/cancel */\r
+               case IDOK:\r
+               case IDCANCEL:\r
+                       EndDialog(hwnd, LOWORD(wParam));\r
+                       return TRUE;\r
+               /* save */\r
+               case IDC_UPDATE:\r
+                       UpdateTag(hwnd);\r
+                       break;\r
+               /* remove */\r
+               case IDC_REMOVE:\r
+                       RemoveTag(hwnd);\r
+                       break;\r
+               }\r
+               break;\r
+       }\r
+\r
+       return 0;\r
 }\r
 \r
+/*\r
+ *  Helpers\r
+ */\r
+\r
+ULONGLONG FileSize(const char *fileName)\r
+{\r
+       LARGE_INTEGER res;\r
+       HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+\r
+       if (hFile == INVALID_HANDLE_VALUE) return 0;\r
+       res.LowPart = GetFileSize(hFile, &res.HighPart);\r
+       CloseHandle(hFile);\r
+       return res.QuadPart;\r
+}\r
+\r
+static __inline char *GetFileName(const char *fullname)\r
+{\r
+       const char *c = fullname + strlen(fullname) - 1;\r
+\r
+       while (c > fullname)\r
+       {\r
+               if (*c=='\\' || *c=='/')\r
+               {\r
+                       c++;\r
+                       break;\r
+               }\r
+               c--;\r
+       }\r
+\r
+       return (char*)c;\r
+}\r
+\r
+void ReadTags(const char *fileName, FLAC_Plugin__CanonicalTag *tag, BOOL forDisplay)\r
+{\r
+       FLAC_plugin__canonical_tag_init(tag);\r
+       FLAC_plugin__vorbiscomment_get(fileName, tag, forDisplay ? flac_cfg.title.sep : NULL);\r
+\r
+       if (flac_cfg.title.read_v1)\r
+               FLAC_plugin__canonical_tag_add_id3v1(fileName, tag);\r
+\r
+       /* add file name */\r
+       if (forDisplay)\r
+       {\r
+               char *c;\r
+               FLAC_plugin__canonical_set_ansi(tag, L"filepath", fileName);\r
+\r
+               strcpy(buffer, GetFileName(fileName));\r
+               if (c = strrchr(buffer, '.')) *c = 0;\r
+               FLAC_plugin__canonical_set_ansi(tag, L"filename", buffer);\r
+       }\r
+}\r
+\r
+/*\r
+ *  Front-end\r
+ */\r
+\r
+void InitInfobox()\r
+{\r
+       isNT = !(GetVersion() & 0x80000000);\r
+}\r
+\r
+void DeinitInfobox()\r
+{\r
+       DeinitGenres(NULL, true);\r
+}\r
 \r
 void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)\r
 {\r
-    DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);\r
+       DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);\r
 }\r