1 /* in_flac - Winamp2 FLAC input plugin
\r
2 * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2009 Josh Coalson
\r
4 * This library is free software; you can redistribute it and/or
\r
5 * modify it under the terms of the GNU Lesser General Public
\r
6 * License as published by the Free Software Foundation; either
\r
7 * version 2.1 of the License, or (at your option) any later version.
\r
9 * This library is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
12 * Lesser General Public License for more details.
\r
14 * You should have received a copy of the GNU Lesser General Public
\r
15 * License along with this library; if not, write to the Free Software
\r
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
\r
20 # include <config.h>
\r
23 #include <windows.h>
\r
25 #include "FLAC/all.h"
\r
26 #include "share/alloc.h"
\r
27 #include "plugin_common/all.h"
\r
28 #include "infobox.h"
\r
29 #include "configure.h"
\r
30 #include "resource.h"
\r
35 char filename[MAX_PATH];
\r
36 FLAC__StreamMetadata *tags;
\r
39 static char buffer[8192];
\r
40 static char *genres = NULL;
\r
41 static DWORD genresSize = 0, genresCount = 0;
\r
42 static BOOL genresChanged = FALSE, isNT;
\r
44 static const char infoTitle[] = "FLAC File Info";
\r
50 /* TODO: write genres in utf-8 ? */
\r
52 static __inline int GetGenresFileName(char *buffer, int size)
\r
56 if (!GetModuleFileName(NULL, buffer, size))
\r
58 c = strrchr(buffer, '\\');
\r
60 strcpy(c+1, "genres.txt");
\r
65 static void LoadGenres()
\r
71 FLAC__ASSERT(0 != genres);
\r
73 if (!GetGenresFileName(buffer, sizeof(buffer))) return;
\r
75 hFile = CreateFile(buffer, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
\r
76 if (hFile == INVALID_HANDLE_VALUE) return;
\r
77 genresSize = GetFileSize(hFile, 0);
\r
78 if (genresSize && (genres = (char*)safe_malloc_add_2op_(genresSize, /*+*/2)))
\r
80 if (!ReadFile(hFile, genres, genresSize, &spam, NULL) || spam!=genresSize)
\r
87 genres[genresSize] = 0;
\r
88 genres[genresSize+1] = 0;
\r
89 /* replace newlines */
\r
90 genresChanged = FALSE;
\r
93 for (c=genres; *c; c++)
\r
106 CloseHandle(hFile);
\r
109 static void SaveGenres(HWND hlist)
\r
115 if (!GetGenresFileName(buffer, sizeof(buffer))) return;
\r
117 hFile = CreateFile(buffer, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
\r
118 if (hFile == INVALID_HANDLE_VALUE) return;
\r
120 count = SendMessage(hlist, CB_GETCOUNT, 0, 0);
\r
121 for (i=0; i<count; i++)
\r
123 SendMessage(hlist, CB_GETLBTEXT, i, (LPARAM)buffer);
\r
124 len = strlen(buffer);
\r
130 WriteFile(hFile, buffer, len, &spam, NULL);
\r
133 CloseHandle(hFile);
\r
136 static void AddGenre(HWND hwnd, const char *genre)
\r
138 HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
\r
140 if (SendMessage(hgen, CB_FINDSTRINGEXACT, -1, (LPARAM)genre) == CB_ERR)
\r
142 genresChanged = TRUE;
\r
143 SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)genre);
\r
147 static void InitGenres(HWND hwnd)
\r
149 HWND hgen = GetDlgItem(hwnd, IDC_GENRE);
\r
152 /* set text length limit to 64 chars */
\r
153 SendMessage(hgen, CB_LIMITTEXT, 64, 0);
\r
154 /* try to load genres */
\r
157 /* add the to list */
\r
160 SendMessage(hgen, CB_INITSTORAGE, genresCount, genresSize);
\r
162 for (c = genres; *c; c += strlen(c)+1)
\r
163 SendMessage(hgen, CB_ADDSTRING, 0, (LPARAM)c);
\r
167 static void DeinitGenres(HWND hwnd, BOOL final)
\r
169 if (genresChanged && hwnd)
\r
171 SaveGenres(GetDlgItem(hwnd, IDC_GENRE));
\r
172 genresChanged = FALSE;
\r
182 static wchar_t *AnsiToWide(const char *src)
\r
187 FLAC__ASSERT(0 != src);
\r
189 len = strlen(src) + 1;
\r
191 dest = (wchar_t*)safe_malloc_mul_2op_(len, /*times*/sizeof(wchar_t));
\r
192 if (dest) mbstowcs(dest, src, len);
\r
200 #define SetText(x,y) ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \
\r
201 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL); \
\r
202 if(ucs2) free(ucs2); \
\r
203 SetDlgItemText(hwnd, x, buffer)
\r
205 #define GetText(x,y) GetDlgItemText(hwnd, x, buffer, sizeof(buffer)); \
\r
206 if (*buffer) { ucs2 = AnsiToWide(buffer); FLAC_plugin__tags_set_tag_ucs2(data->tags, y, ucs2, /*replace_all=*/false); free(ucs2); } \
\r
207 else FLAC_plugin__tags_delete_tag(data->tags, y)
\r
209 #define SetTextW(x,y) ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, y); \
\r
210 SetDlgItemTextW(hwnd, x, ucs2); \
\r
213 #define GetTextW(x,y) GetDlgItemTextW(hwnd, x, (WCHAR*)buffer, sizeof(buffer)/2); \
\r
214 if (*(WCHAR*)buffer) FLAC_plugin__tags_set_tag_ucs2(data->tags, y, (WCHAR*)buffer, /*replace_all=*/false); \
\r
215 else FLAC_plugin__tags_delete_tag(data->tags, y)
\r
218 static BOOL InitInfoboxInfo(HWND hwnd, const char *file)
\r
220 LOCALDATA *data = LocalAlloc(LPTR, sizeof(LOCALDATA));
\r
222 FLAC__StreamMetadata streaminfo;
\r
223 DWORD length, bps, ratio, rg;
\r
226 SetWindowLong(hwnd, GWL_USERDATA, (LONG)data);
\r
228 strncpy(data->filename, file, sizeof(data->filename));
\r
229 SetDlgItemText(hwnd, IDC_NAME, file);
\r
230 /* stream data and vorbis comment */
\r
231 filesize = FileSize(file);
\r
232 if (!filesize) return FALSE;
\r
233 if (!FLAC__metadata_get_streaminfo(file, &streaminfo))
\r
235 ReadTags(file, &data->tags, false);
\r
237 length = (DWORD)(streaminfo.data.stream_info.total_samples / streaminfo.data.stream_info.sample_rate);
\r
238 bps = (DWORD)(filesize / (125*streaminfo.data.stream_info.total_samples/streaminfo.data.stream_info.sample_rate));
\r
239 ratio = bps*1000000 / (streaminfo.data.stream_info.sample_rate*streaminfo.data.stream_info.channels*streaminfo.data.stream_info.bits_per_sample);
\r
240 rg = FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_TRACK_GAIN") ? 1 : 0;
\r
241 rg |= FLAC_plugin__tags_get_tag_utf8(data->tags, "REPLAYGAIN_ALBUM_GAIN") ? 2 : 0;
\r
243 sprintf(buffer, "Sample rate: %d Hz\nChannels: %d\nBits per sample: %d\nMin block size: %d\nMax block size: %d\n"
\r
244 "File size: %I64d bytes\nTotal samples: %I64d\nLength: %d:%02d\nAvg. bitrate: %d\nCompression ratio: %d.%d%%\n"
\r
245 "ReplayGain: %s\n",
\r
246 streaminfo.data.stream_info.sample_rate, streaminfo.data.stream_info.channels, streaminfo.data.stream_info.bits_per_sample,
\r
247 streaminfo.data.stream_info.min_blocksize, streaminfo.data.stream_info.max_blocksize, filesize, streaminfo.data.stream_info.total_samples,
\r
248 length/60, length%60, bps, ratio/10, ratio%10,
\r
249 rg==3 ? "track gain\nReplayGain: album gain" : rg==2 ? "album gain" : rg==1 ? "track gain" : "not present");
\r
251 SetDlgItemText(hwnd, IDC_INFO, buffer);
\r
255 SetTextW(IDC_TITLE, "TITLE");
\r
256 SetTextW(IDC_ARTIST, "ARTIST");
\r
257 SetTextW(IDC_ALBUM, "ALBUM");
\r
258 SetTextW(IDC_COMMENT, "COMMENT");
\r
259 SetTextW(IDC_YEAR, "DATE");
\r
260 SetTextW(IDC_TRACK, "TRACKNUMBER");
\r
261 SetTextW(IDC_GENRE, "GENRE");
\r
265 SetText(IDC_TITLE, "TITLE");
\r
266 SetText(IDC_ARTIST, "ARTIST");
\r
267 SetText(IDC_ALBUM, "ALBUM");
\r
268 SetText(IDC_COMMENT, "COMMENT");
\r
269 SetText(IDC_YEAR, "DATE");
\r
270 SetText(IDC_TRACK, "TRACKNUMBER");
\r
271 SetText(IDC_GENRE, "GENRE");
\r
277 static void __inline SetTag(HWND hwnd, const char *filename, FLAC__StreamMetadata *tags)
\r
279 strcpy(buffer, infoTitle);
\r
281 if (FLAC_plugin__tags_set(filename, tags))
\r
282 strcat(buffer, " [Updated]");
\r
283 else strcat(buffer, " [Failed]");
\r
285 SetWindowText(hwnd, buffer);
\r
288 static void UpdateTag(HWND hwnd)
\r
290 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
\r
296 GetTextW(IDC_TITLE, "TITLE");
\r
297 GetTextW(IDC_ARTIST, "ARTIST");
\r
298 GetTextW(IDC_ALBUM, "ALBUM");
\r
299 GetTextW(IDC_COMMENT, "COMMENT");
\r
300 GetTextW(IDC_YEAR, "DATE");
\r
301 GetTextW(IDC_TRACK, "TRACKNUMBER");
\r
302 GetTextW(IDC_GENRE, "GENRE");
\r
304 ucs2 = FLAC_plugin__tags_get_tag_ucs2(data->tags, "GENRE");
\r
305 WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK, ucs2, -1, buffer, sizeof(buffer), NULL, NULL);
\r
310 GetText(IDC_TITLE, "TITLE");
\r
311 GetText(IDC_ARTIST, "ARTIST");
\r
312 GetText(IDC_ALBUM, "ALBUM");
\r
313 GetText(IDC_COMMENT, "COMMENT");
\r
314 GetText(IDC_YEAR, "DATE");
\r
315 GetText(IDC_TRACK, "TRACKNUMBER");
\r
316 GetText(IDC_GENRE, "GENRE");
\r
319 /* update genres list (buffer should contain genre) */
\r
320 if (buffer[0]) AddGenre(hwnd, buffer);
\r
323 SetTag(hwnd, data->filename, data->tags);
\r
326 static void RemoveTag(HWND hwnd)
\r
328 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
\r
329 FLAC_plugin__tags_delete_all(data->tags);
\r
331 SetDlgItemText(hwnd, IDC_TITLE, "");
\r
332 SetDlgItemText(hwnd, IDC_ARTIST, "");
\r
333 SetDlgItemText(hwnd, IDC_ALBUM, "");
\r
334 SetDlgItemText(hwnd, IDC_COMMENT, "");
\r
335 SetDlgItemText(hwnd, IDC_YEAR, "");
\r
336 SetDlgItemText(hwnd, IDC_TRACK, "");
\r
337 SetDlgItemText(hwnd, IDC_GENRE, "");
\r
339 SetTag(hwnd, data->filename, data->tags);
\r
343 static INT_PTR CALLBACK InfoProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
\r
348 case WM_INITDIALOG:
\r
349 SetWindowText(hwnd, infoTitle);
\r
352 if (!InitInfoboxInfo(hwnd, (const char*)lParam))
\r
353 PostMessage(hwnd, WM_CLOSE, 0, 0);
\r
358 LOCALDATA *data = (LOCALDATA*)GetWindowLong(hwnd, GWL_USERDATA);
\r
359 FLAC_plugin__tags_destroy(&data->tags);
\r
361 DeinitGenres(hwnd, FALSE);
\r
366 switch (LOWORD(wParam))
\r
371 EndDialog(hwnd, LOWORD(wParam));
\r
392 ULONGLONG FileSize(const char *fileName)
\r
395 HANDLE hFile = CreateFile(fileName, 0, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
\r
397 if (hFile == INVALID_HANDLE_VALUE) return 0;
\r
398 res.LowPart = GetFileSize(hFile, &res.HighPart);
\r
399 CloseHandle(hFile);
\r
400 return res.QuadPart;
\r
403 static __inline char *GetFileName(const char *fullname)
\r
405 const char *c = fullname + strlen(fullname) - 1;
\r
407 while (c > fullname)
\r
409 if (*c=='\\' || *c=='/')
\r
420 void ReadTags(const char *fileName, FLAC__StreamMetadata **tags, BOOL forDisplay)
\r
422 if(FLAC_plugin__tags_get(fileName, tags)) {
\r
424 /* add file name */
\r
429 ucs2 = AnsiToWide(fileName);
\r
430 FLAC_plugin__tags_set_tag_ucs2(*tags, "filepath", ucs2, /*replace_all=*/true);
\r
433 strcpy(buffer, GetFileName(fileName));
\r
434 if (c = strrchr(buffer, '.')) *c = 0;
\r
435 ucs2 = AnsiToWide(buffer);
\r
436 FLAC_plugin__tags_set_tag_ucs2(*tags, "filename", ucs2, /*replace_all=*/true);
\r
448 isNT = !(GetVersion() & 0x80000000);
\r
451 void DeinitInfobox()
\r
453 DeinitGenres(NULL, true);
\r
456 void DoInfoBox(HINSTANCE inst, HWND hwnd, const char *filename)
\r
458 DialogBoxParam(inst, MAKEINTRESOURCE(IDD_INFOBOX), hwnd, InfoProc, (LONG)filename);
\r