annotate src/flac-1.2.1/src/plugin_winamp2/infobox.c @ 93:5fcdb63f4cc6

Add sord, serd
author Chris Cannam <cannam@all-day-breakfast.com>
date Wed, 20 Mar 2013 15:23:43 +0000
parents 98c1576536ae
children
rev   line source
cannam@86 1 /* in_flac - Winamp2 FLAC input plugin
cannam@86 2 * Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
cannam@86 3 *
cannam@86 4 * This library is free software; you can redistribute it and/or
cannam@86 5 * modify it under the terms of the GNU Lesser General Public
cannam@86 6 * License as published by the Free Software Foundation; either
cannam@86 7 * version 2.1 of the License, or (at your option) any later version.
cannam@86 8 *
cannam@86 9 * This library is distributed in the hope that it will be useful,
cannam@86 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
cannam@86 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
cannam@86 12 * Lesser General Public License for more details.
cannam@86 13 *
cannam@86 14 * You should have received a copy of the GNU Lesser General Public
cannam@86 15 * License along with this library; if not, write to the Free Software
cannam@86 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
cannam@86 17 */
cannam@86 18
cannam@86 19 #if HAVE_CONFIG_H
cannam@86 20 # include <config.h>
cannam@86 21 #endif
cannam@86 22
cannam@86 23 #include <windows.h>
cannam@86 24 #include <stdio.h>
cannam@86 25 #include "FLAC/all.h"
cannam@86 26 #include "share/alloc.h"
cannam@86 27 #include "plugin_common/all.h"
cannam@86 28 #include "infobox.h"
cannam@86 29 #include "configure.h"
cannam@86 30 #include "resource.h"
cannam@86 31
cannam@86 32
cannam@86 33 typedef struct
cannam@86 34 {
cannam@86 35 char filename[MAX_PATH];
cannam@86 36 FLAC__StreamMetadata *tags;
cannam@86 37 } LOCALDATA;
cannam@86 38
cannam@86 39 static char buffer[8192];
cannam@86 40 static char *genres = NULL;
cannam@86 41 static DWORD genresSize = 0, genresCount = 0;
cannam@86 42 static BOOL genresChanged = FALSE, isNT;
cannam@86 43
cannam@86 44 static const char infoTitle[] = "FLAC File Info";
cannam@86 45
cannam@86 46 /*
cannam@86 47 * Genres
cannam@86 48 */
cannam@86 49
cannam@86 50 /* TODO: write genres in utf-8 ? */
cannam@86 51
cannam@86 52 static __inline int GetGenresFileName(char *buffer, int size)
cannam@86 53 {
cannam@86 54 char *c;
cannam@86 55
cannam@86 56 if (!GetModuleFileName(NULL, buffer, size))
cannam@86 57 return 0;
cannam@86 58 c = strrchr(buffer, '\\');
cannam@86 59 if (!c) return 0;
cannam@86 60 strcpy(c+1, "genres.txt");
cannam@86 61
cannam@86 62 return 1;
cannam@86 63 }
cannam@86 64
cannam@86 65 static void LoadGenres()
cannam@86 66 {
cannam@86 67 HANDLE hFile;
cannam@86 68 DWORD spam;
cannam@86 69 char *c;
cannam@86 70
cannam@86 71 FLAC__ASSERT(0 != genres);
cannam@86 72
cannam@86 73 if (!GetGenresFileName(buffer, sizeof(buffer))) return;
cannam@86 74 /* load file */
cannam@86 75 hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
cannam@86 76 if (hFile == INVALID_HANDLE_VALUE) return;
cannam@86 77 genresSize = GetFileSize(hFile, 0);
cannam@86 78 if (genresSize && (genres = (char*)safe_malloc_add_2op_(genresSize, /*+*/2)))
cannam@86 79 {
cannam@86 80 if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)
cannam@86 81 {
cannam@86 82 free(genres);
cannam@86 83 genres = NULL;
cannam@86 84 }
cannam@86 85 else
cannam@86 86 {
cannam@86 87 genres[genresSize] = 0;
cannam@86 88 genres[genresSize+1] = 0;
cannam@86 89 /* replace newlines */
cannam@86 90 genresChanged = FALSE;
cannam@86 91 genresCount = 1;
cannam@86 92
cannam@86 93 for (c=genres; *c; c++)
cannam@86 94 {
cannam@86 95 if (*c == 10)
cannam@86 96 {
cannam@86 97 *c = 0;
cannam@86 98 if (*(c+1))
cannam@86 99 genresCount++;
cannam@86 100 else genresSize--;
cannam@86 101 }
cannam@86 102 }
cannam@86 103 }
cannam@86 104 }
cannam@86 105
cannam@86 106 CloseHandle(hFile);
cannam@86 107 }
cannam@86 108
cannam@86 109 static void SaveGenres(HWND hlist)
cannam@86 110 {
cannam@86 111 HANDLE hFile;
cannam@86 112 DWORD spam;
cannam@86 113 int i, count, len;
cannam@86 114
cannam@86 115 if (!GetGenresFileName(buffer, sizeof(buffer))) return;
cannam@86 116 /* write file */
cannam@86 117 hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
cannam@86 118 if (hFile == INVALID_HANDLE_VALUE) return;
cannam@86 119
cannam@86 120 count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
cannam@86 121 for (i=0; i<count; i++)
cannam@86 122 {
cannam@86 123 SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
cannam@86 124 len = strlen(buffer);
cannam@86 125 if (i != count-1)
cannam@86 126 {
cannam@86 127 buffer[len] = 10;
cannam@86 128 len++;
cannam@86 129 }
cannam@86 130 WriteFile(hFile, buffer, len, &spam, NULL);
cannam@86 131 }
cannam@86 132
cannam@86 133 CloseHandle(hFile);
cannam@86 134 }
cannam@86 135
cannam@86 136 static void AddGenre(HWND hwnd, const char *genre)
cannam@86 137 {
cannam@86 138 HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
cannam@86 139
cannam@86 140 if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)
cannam@86 141 {
cannam@86 142 genresChanged = TRUE;
cannam@86 143 SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);
cannam@86 144 }
cannam@86 145 }
cannam@86 146
cannam@86 147 static void InitGenres(HWND hwnd)
cannam@86 148 {
cannam@86 149 HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
cannam@86 150 char *c;
cannam@86 151
cannam@86 152 /* set text length limit to 64 chars */
cannam@86 153 SendMessage(hgen, CB_LIMITTEXT, 64, 0);
cannam@86 154 /* try to load genres */
cannam@86 155 if (!genres)
cannam@86 156 LoadGenres(hgen);
cannam@86 157 /* add the to list */
cannam@86 158 if (genres)
cannam@86 159 {
cannam@86 160 SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
cannam@86 161
cannam@86 162 for (c = genres; *c; c += strlen(c)+1)
cannam@86 163 SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
cannam@86 164 }
cannam@86 165 }
cannam@86 166
cannam@86 167 static void DeinitGenres(HWND hwnd, BOOL final)
cannam@86 168 {
cannam@86 169 if (genresChanged && hwnd)
cannam@86 170 {
cannam@86 171 SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
cannam@86 172 genresChanged = FALSE;
cannam@86 173 final = TRUE;
cannam@86 174 }
cannam@86 175 if (final)
cannam@86 176 {
cannam@86 177 free(genres);
cannam@86 178 genres = 0;
cannam@86 179 }
cannam@86 180 }
cannam@86 181
cannam@86 182 static wchar_t *AnsiToWide(const char *src)
cannam@86 183 {
cannam@86 184 int len;
cannam@86 185 wchar_t *dest;
cannam@86 186
cannam@86 187 FLAC__ASSERT(0 != src);
cannam@86 188
cannam@86 189 len = strlen(src) + 1;
cannam@86 190 /* copy */
cannam@86 191 dest = (wchar_t*)safe_malloc_mul_2op_(len, /*times*/sizeof(wchar_t));
cannam@86 192 if (dest) mbstowcs(dest, src, len);
cannam@86 193 return dest;
cannam@86 194 }
cannam@86 195
cannam@86 196 /*
cannam@86 197 * Infobox helpers
cannam@86 198 */
cannam@86 199
cannam@86 200 #define SetText(x,y) ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \
cannam@86 201 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL); \
cannam@86 202 if(ucs2) free(ucs2); \
cannam@86 203 SetDlgItemText(hwnd, x, buffer)
cannam@86 204
cannam@86 205 #define GetText(x,y) GetDlgItemText(hwnd, x, buffer, sizeof(buffer)); \
cannam@86 206 if (*buffer) { ucs2 = AnsiToWide(buffer); FLAC_plugin__tags_set_tag_ucs2(data->tags, y, ucs2, /*replace_all=*/false); free(ucs2); } \
cannam@86 207 else FLAC_plugin__tags_delete_tag(data->tags, y)
cannam@86 208
cannam@86 209 #define SetTextW(x,y) ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \
cannam@86 210 SetDlgItemTextW(hwnd, x, ucs2); \
cannam@86 211 free(ucs2)
cannam@86 212
cannam@86 213 #define GetTextW(x,y) GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2); \
cannam@86 214 if (*(WCHAR*)buffer) FLAC_plugin__tags_set_tag_ucs2(data->tags, y, (WCHAR*)buffer, /*replace_all=*/false); \
cannam@86 215 else FLAC_plugin__tags_delete_tag(data->tags, y)
cannam@86 216
cannam@86 217
cannam@86 218 static BOOL InitInfoboxInfo(HWND hwnd, const char *file)
cannam@86 219 {
cannam@86 220 LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
cannam@86 221 wchar_t *ucs2;
cannam@86 222 FLAC__StreamMetadata streaminfo;
cannam@86 223 DWORD length, bps, ratio, rg;
cannam@86 224 LONGLONG filesize;
cannam@86 225
cannam@86 226 SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
cannam@86 227 /* file name */
cannam@86 228 strncpy(data->filename, file, sizeof(data->filename));
cannam@86 229 SetDlgItemText(hwnd, IDC_NAME, file);
cannam@86 230 /* stream data and vorbis comment */
cannam@86 231 filesize = FileSize(file);
cannam@86 232 if (!filesize) return FALSE;
cannam@86 233 if (!FLAC__metadata_get_streaminfo(file, &streaminfo))
cannam@86 234 return FALSE;
cannam@86 235 ReadTags(file, &data->tags, false);
cannam@86 236
cannam@86 237 length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
cannam@86 238 bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
cannam@86 239 ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
cannam@86 240 rg = FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_TRACK_GAIN") ? 1 : 0;
cannam@86 241 rg |= FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;
cannam@86 242
cannam@86 243 sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
cannam@86 244 "File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"
cannam@86 245 "ReplayGain: %s\n",
cannam@86 246 streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
cannam@86 247 streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
cannam@86 248 length/60, length%60, bps, ratio/10, ratio%10,
cannam@86 249 rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");
cannam@86 250
cannam@86 251 SetDlgItemText(hwnd, IDC_INFO, buffer);
cannam@86 252 /* tag */
cannam@86 253 if (isNT)
cannam@86 254 {
cannam@86 255 SetTextW(IDC_TITLE, "TITLE");
cannam@86 256 SetTextW(IDC_ARTIST, "ARTIST");
cannam@86 257 SetTextW(IDC_ALBUM, "ALBUM");
cannam@86 258 SetTextW(IDC_COMMENT, "COMMENT");
cannam@86 259 SetTextW(IDC_YEAR, "DATE");
cannam@86 260 SetTextW(IDC_TRACK, "TRACKNUMBER");
cannam@86 261 SetTextW(IDC_GENRE, "GENRE");
cannam@86 262 }
cannam@86 263 else
cannam@86 264 {
cannam@86 265 SetText(IDC_TITLE, "TITLE");
cannam@86 266 SetText(IDC_ARTIST, "ARTIST");
cannam@86 267 SetText(IDC_ALBUM, "ALBUM");
cannam@86 268 SetText(IDC_COMMENT, "COMMENT");
cannam@86 269 SetText(IDC_YEAR, "DATE");
cannam@86 270 SetText(IDC_TRACK, "TRACKNUMBER");
cannam@86 271 SetText(IDC_GENRE, "GENRE");
cannam@86 272 }
cannam@86 273
cannam@86 274 return TRUE;
cannam@86 275 }
cannam@86 276
cannam@86 277 static void __inline SetTag(HWND hwnd, const char *filename, FLAC__StreamMetadata *tags)
cannam@86 278 {
cannam@86 279 strcpy(buffer, infoTitle);
cannam@86 280
cannam@86 281 if (FLAC_plugin__tags_set(filename, tags))
cannam@86 282 strcat(buffer, " [Updated]");
cannam@86 283 else strcat(buffer, " [Failed]");
cannam@86 284
cannam@86 285 SetWindowText(hwnd, buffer);
cannam@86 286 }
cannam@86 287
cannam@86 288 static void UpdateTag(HWND hwnd)
cannam@86 289 {
cannam@86 290 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
cannam@86 291 wchar_t *ucs2;
cannam@86 292
cannam@86 293 /* get fields */
cannam@86 294 if (isNT)
cannam@86 295 {
cannam@86 296 GetTextW(IDC_TITLE, "TITLE");
cannam@86 297 GetTextW(IDC_ARTIST, "ARTIST");
cannam@86 298 GetTextW(IDC_ALBUM, "ALBUM");
cannam@86 299 GetTextW(IDC_COMMENT, "COMMENT");
cannam@86 300 GetTextW(IDC_YEAR, "DATE");
cannam@86 301 GetTextW(IDC_TRACK, "TRACKNUMBER");
cannam@86 302 GetTextW(IDC_GENRE, "GENRE");
cannam@86 303
cannam@86 304 ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, "GENRE");
cannam@86 305 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL);
cannam@86 306 free(ucs2);
cannam@86 307 }
cannam@86 308 else
cannam@86 309 {
cannam@86 310 GetText(IDC_TITLE, "TITLE");
cannam@86 311 GetText(IDC_ARTIST, "ARTIST");
cannam@86 312 GetText(IDC_ALBUM, "ALBUM");
cannam@86 313 GetText(IDC_COMMENT, "COMMENT");
cannam@86 314 GetText(IDC_YEAR, "DATE");
cannam@86 315 GetText(IDC_TRACK, "TRACKNUMBER");
cannam@86 316 GetText(IDC_GENRE, "GENRE");
cannam@86 317 }
cannam@86 318
cannam@86 319 /* update genres list (buffer should contain genre) */
cannam@86 320 if (buffer[0]) AddGenre(hwnd, buffer);
cannam@86 321
cannam@86 322 /* write tag */
cannam@86 323 SetTag(hwnd, data->filename, data->tags);
cannam@86 324 }
cannam@86 325
cannam@86 326 static void RemoveTag(HWND hwnd)
cannam@86 327 {
cannam@86 328 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
cannam@86 329 FLAC_plugin__tags_delete_all(data->tags);
cannam@86 330
cannam@86 331 SetDlgItemText(hwnd, IDC_TITLE, "");
cannam@86 332 SetDlgItemText(hwnd, IDC_ARTIST, "");
cannam@86 333 SetDlgItemText(hwnd, IDC_ALBUM, "");
cannam@86 334 SetDlgItemText(hwnd, IDC_COMMENT, "");
cannam@86 335 SetDlgItemText(hwnd, IDC_YEAR, "");
cannam@86 336 SetDlgItemText(hwnd, IDC_TRACK, "");
cannam@86 337 SetDlgItemText(hwnd, IDC_GENRE, "");
cannam@86 338
cannam@86 339 SetTag(hwnd, data->filename, data->tags);
cannam@86 340 }
cannam@86 341
cannam@86 342
cannam@86 343 static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
cannam@86 344 {
cannam@86 345 switch (msg)
cannam@86 346 {
cannam@86 347 /* init */
cannam@86 348 case WM_INITDIALOG:
cannam@86 349 SetWindowText(hwnd, infoTitle);
cannam@86 350 InitGenres(hwnd);
cannam@86 351 /* init fields */
cannam@86 352 if (!InitInfoboxInfo(hwnd, (const char*)lParam))
cannam@86 353 PostMessage(hwnd, WM_CLOSE, 0, 0);
cannam@86 354 return TRUE;
cannam@86 355 /* destroy */
cannam@86 356 case WM_DESTROY:
cannam@86 357 {
cannam@86 358 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
cannam@86 359 FLAC_plugin__tags_destroy(&data->tags);
cannam@86 360 LocalFree(data);
cannam@86 361 DeinitGenres(hwnd, FALSE);
cannam@86 362 }
cannam@86 363 break;
cannam@86 364 /* commands */
cannam@86 365 case WM_COMMAND:
cannam@86 366 switch (LOWORD(wParam))
cannam@86 367 {
cannam@86 368 /* ok/cancel */
cannam@86 369 case IDOK:
cannam@86 370 case IDCANCEL:
cannam@86 371 EndDialog(hwnd, LOWORD(wParam));
cannam@86 372 return TRUE;
cannam@86 373 /* save */
cannam@86 374 case IDC_UPDATE:
cannam@86 375 UpdateTag(hwnd);
cannam@86 376 break;
cannam@86 377 /* remove */
cannam@86 378 case IDC_REMOVE:
cannam@86 379 RemoveTag(hwnd);
cannam@86 380 break;
cannam@86 381 }
cannam@86 382 break;
cannam@86 383 }
cannam@86 384
cannam@86 385 return 0;
cannam@86 386 }
cannam@86 387
cannam@86 388 /*
cannam@86 389 * Helpers
cannam@86 390 */
cannam@86 391
cannam@86 392 ULONGLONG FileSize(const char *fileName)
cannam@86 393 {
cannam@86 394 LARGE_INTEGER res;
cannam@86 395 HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
cannam@86 396
cannam@86 397 if (hFile == INVALID_HANDLE_VALUE) return 0;
cannam@86 398 res.LowPart = GetFileSize(hFile, &res.HighPart);
cannam@86 399 CloseHandle(hFile);
cannam@86 400 return res.QuadPart;
cannam@86 401 }
cannam@86 402
cannam@86 403 static __inline char *GetFileName(const char *fullname)
cannam@86 404 {
cannam@86 405 const char *c = fullname + strlen(fullname) - 1;
cannam@86 406
cannam@86 407 while (c > fullname)
cannam@86 408 {
cannam@86 409 if (*c=='\\' || *c=='/')
cannam@86 410 {
cannam@86 411 c++;
cannam@86 412 break;
cannam@86 413 }
cannam@86 414 c--;
cannam@86 415 }
cannam@86 416
cannam@86 417 return (char*)c;
cannam@86 418 }
cannam@86 419
cannam@86 420 void ReadTags(const char *fileName, FLAC__StreamMetadata **tags, BOOL forDisplay)
cannam@86 421 {
cannam@86 422 if(FLAC_plugin__tags_get(fileName, tags)) {
cannam@86 423
cannam@86 424 /* add file name */
cannam@86 425 if (forDisplay)
cannam@86 426 {
cannam@86 427 char *c;
cannam@86 428 wchar_t *ucs2;
cannam@86 429 ucs2 = AnsiToWide(fileName);
cannam@86 430 FLAC_plugin__tags_set_tag_ucs2(*tags, "filepath", ucs2, /*replace_all=*/true);
cannam@86 431 free(ucs2);
cannam@86 432
cannam@86 433 strcpy(buffer, GetFileName(fileName));
cannam@86 434 if (c = strrchr(buffer, '.')) *c = 0;
cannam@86 435 ucs2 = AnsiToWide(buffer);
cannam@86 436 FLAC_plugin__tags_set_tag_ucs2(*tags, "filename", ucs2, /*replace_all=*/true);
cannam@86 437 free(ucs2);
cannam@86 438 }
cannam@86 439 }
cannam@86 440 }
cannam@86 441
cannam@86 442 /*
cannam@86 443 * Front-end
cannam@86 444 */
cannam@86 445
cannam@86 446 void InitInfobox()
cannam@86 447 {
cannam@86 448 isNT = !(GetVersion() & 0x80000000);
cannam@86 449 }
cannam@86 450
cannam@86 451 void DeinitInfobox()
cannam@86 452 {
cannam@86 453 DeinitGenres(NULL, true);
cannam@86 454 }
cannam@86 455
cannam@86 456 void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)
cannam@86 457 {
cannam@86 458 DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);
cannam@86 459 }