Metadata.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  1. /*
  2. ** Copyright (C) 2007-2011 Nullsoft, Inc.
  3. **
  4. ** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
  5. ** liable for any damages arising from the use of this software.
  6. **
  7. ** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
  8. ** alter it and redistribute it freely, subject to the following restrictions:
  9. **
  10. ** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
  11. ** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
  12. **
  13. ** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
  14. **
  15. ** 3. This notice may not be removed or altered from any source distribution.
  16. **
  17. ** Author: Ben Allison [email protected]
  18. ** Created: March 1, 2007
  19. **
  20. */
  21. #include "Metadata.h"
  22. #include <FLAC/all.h>
  23. #include "StreamFileWin32.h" // for FileSize64
  24. #include "api__in_flv.h"
  25. #include <strsafe.h>
  26. struct MetadataReader
  27. {
  28. MetadataReader(HANDLE _handle)
  29. {
  30. handle = _handle;
  31. endOfFile=false;
  32. }
  33. HANDLE handle;
  34. bool endOfFile;
  35. };
  36. static size_t win32_read(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
  37. {
  38. MetadataReader *reader = (MetadataReader *)handle;
  39. DWORD bytesRead=0;
  40. BOOL result = ReadFile(reader->handle, ptr, size*nmemb, &bytesRead, NULL);
  41. if (result == TRUE && bytesRead == 0)
  42. reader->endOfFile=true;
  43. return bytesRead/size;
  44. }
  45. static size_t win32_write(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
  46. {
  47. MetadataReader *reader = (MetadataReader *)handle;
  48. DWORD bytesWritten=0;
  49. WriteFile(reader->handle, ptr, size*nmemb, &bytesWritten, NULL);
  50. return bytesWritten/size;
  51. }
  52. static __int64 Seek64(HANDLE hf, __int64 distance, DWORD MoveMethod)
  53. {
  54. LARGE_INTEGER li;
  55. li.QuadPart = distance;
  56. li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
  57. if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
  58. {
  59. li.QuadPart = -1;
  60. }
  61. return li.QuadPart;
  62. }
  63. static int win32_seek(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
  64. {
  65. MetadataReader *reader = (MetadataReader *)handle;
  66. if (Seek64(reader->handle, offset, whence) == -1)
  67. return -1;
  68. else
  69. return 0;
  70. }
  71. static FLAC__int64 win32_tell(FLAC__IOHandle handle)
  72. {
  73. MetadataReader *reader = (MetadataReader *)handle;
  74. return Seek64(reader->handle, 0, FILE_CURRENT);
  75. }
  76. static int win32_eof(FLAC__IOHandle handle)
  77. {
  78. MetadataReader *reader = (MetadataReader *)handle;
  79. return !!reader->endOfFile;
  80. }
  81. static int win32_close(FLAC__IOHandle handle)
  82. {
  83. MetadataReader *reader = (MetadataReader *)handle;
  84. CloseHandle(reader->handle);
  85. reader->handle = INVALID_HANDLE_VALUE;
  86. return 0;
  87. }
  88. static FLAC__IOCallbacks unicodeIO =
  89. {
  90. win32_read,
  91. win32_write,
  92. win32_seek,
  93. win32_tell,
  94. win32_eof,
  95. win32_close,
  96. };
  97. FLACMetadata::FLACMetadata()
  98. {
  99. chain=FLAC__metadata_chain_new();
  100. itr = FLAC__metadata_iterator_new();
  101. block=0;
  102. streamInfo=0;
  103. filesize=0;
  104. }
  105. FLACMetadata::~FLACMetadata()
  106. {
  107. if (chain)
  108. FLAC__metadata_chain_delete(chain);
  109. if (itr)
  110. FLAC__metadata_iterator_delete(itr);
  111. }
  112. void FLACMetadata::Reset()
  113. {
  114. if (chain)
  115. FLAC__metadata_chain_delete(chain);
  116. if (itr)
  117. FLAC__metadata_iterator_delete(itr);
  118. chain=FLAC__metadata_chain_new();
  119. itr = FLAC__metadata_iterator_new();
  120. block=0;
  121. streamInfo=0;
  122. filesize=0;
  123. }
  124. const FLAC__StreamMetadata_StreamInfo *FLACMetadata::GetStreamInfo()
  125. {
  126. if (streamInfo)
  127. return &streamInfo->data.stream_info;
  128. else
  129. return 0;
  130. }
  131. bool FLACMetadata::Open(const wchar_t *filename, bool optimize)
  132. {
  133. if (!chain || !itr)
  134. return false;
  135. HANDLE hfile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
  136. MetadataReader reader(hfile);
  137. if (reader.handle == INVALID_HANDLE_VALUE)
  138. return false;
  139. filesize = FileSize64(reader.handle);
  140. FLAC__bool success = FLAC__metadata_chain_read_with_callbacks(chain, &reader, unicodeIO);
  141. CloseHandle(hfile);
  142. if (!success)
  143. return false;
  144. if (optimize)
  145. {
  146. FLAC__metadata_chain_sort_padding(chain);
  147. FLAC__metadata_chain_merge_padding(chain);
  148. }
  149. FLAC__metadata_iterator_init(itr, chain);
  150. while (1)
  151. {
  152. FLAC__MetadataType type=FLAC__metadata_iterator_get_block_type(itr);
  153. switch (type)
  154. {
  155. case FLAC__METADATA_TYPE_VORBIS_COMMENT:
  156. block = FLAC__metadata_iterator_get_block(itr);
  157. break;
  158. case FLAC__METADATA_TYPE_STREAMINFO:
  159. streamInfo = FLAC__metadata_iterator_get_block(itr);
  160. break;
  161. }
  162. if (FLAC__metadata_iterator_next(itr) == false)
  163. break;
  164. }
  165. return true;
  166. }
  167. const char *FLACMetadata::GetMetadata(const char *tag)
  168. {
  169. if (!block)
  170. return 0;
  171. int pos = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, tag);
  172. if (pos < 0)
  173. {
  174. // fail
  175. }
  176. else
  177. {
  178. const char *entry = (const char *)block->data.vorbis_comment.comments[pos].entry;
  179. const char *metadata = strchr(entry, '='); // find the first equal
  180. if (metadata)
  181. {
  182. return metadata+1;
  183. }
  184. }
  185. return 0;
  186. }
  187. void FLACMetadata::SetMetadata(const char *tag, const char *value)
  188. {
  189. if (!block)
  190. {
  191. FLAC__metadata_iterator_init(itr, chain);
  192. do
  193. {
  194. if (FLAC__METADATA_TYPE_VORBIS_COMMENT == FLAC__metadata_iterator_get_block_type(itr))
  195. {
  196. block = FLAC__metadata_iterator_get_block(itr);
  197. break;
  198. }
  199. }
  200. while (FLAC__metadata_iterator_next(itr) != 0);
  201. if (!block)
  202. {
  203. block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
  204. FLAC__metadata_iterator_insert_block_after(itr, block);
  205. }
  206. }
  207. if (!block)
  208. return;
  209. FLAC__StreamMetadata_VorbisComment_Entry entry;
  210. size_t totalLen = strlen(tag) + 1 /* = */ + strlen(value);
  211. entry.entry = (FLAC__byte *)malloc(totalLen + 1);
  212. entry.length = totalLen;
  213. StringCchPrintfA((char *)entry.entry, totalLen+1, "%s=%s", tag, value);
  214. int pos = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, tag);
  215. if (pos < 0)
  216. {
  217. //new comment
  218. FLAC__metadata_object_vorbiscomment_append_comment(block, entry, true);
  219. // would love to not copy, but we can't guarantee that FLAC links to the same CRT as us
  220. }
  221. else
  222. {
  223. FLAC__metadata_object_vorbiscomment_set_comment(block, pos, entry, true);
  224. // would love to not copy, but we can't guarantee that FLAC links to the same CRT as us
  225. }
  226. free(entry.entry);
  227. }
  228. void FLACMetadata::RemoveMetadata(const char *tag)
  229. {
  230. if (!block)
  231. return;
  232. FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, tag);
  233. }
  234. void FLACMetadata::RemoveMetadata(int n)
  235. {
  236. if (!block)
  237. return;
  238. FLAC__metadata_object_vorbiscomment_delete_comment(block, (unsigned int)n);
  239. }
  240. static FLAC__StreamMetadata *GetOrMakePadding(FLAC__Metadata_Chain *chain, FLAC__Metadata_Iterator *itr)
  241. {
  242. FLAC__metadata_iterator_init(itr, chain);
  243. while (1)
  244. {
  245. if (FLAC__METADATA_TYPE_PADDING == FLAC__metadata_iterator_get_block_type(itr))
  246. {
  247. FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
  248. return block;
  249. }
  250. if (FLAC__metadata_iterator_next(itr) == false)
  251. break;
  252. }
  253. FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
  254. if (padding)
  255. FLAC__metadata_iterator_insert_block_after(itr, padding);
  256. return padding;
  257. }
  258. bool FLACMetadata::Save(const wchar_t *filename)
  259. {
  260. if (FLAC__metadata_chain_check_if_tempfile_needed(chain, true))
  261. {
  262. // since we needed to write a tempfile, let's add some more padding so it doesn't happen again
  263. FLAC__metadata_chain_sort_padding(chain);
  264. FLAC__StreamMetadata *padding = GetOrMakePadding(chain, itr);
  265. if (padding && padding->length < 16384)
  266. padding->length = 16384; // TODO: configurable padding size
  267. HANDLE hfile = CreateFileW(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
  268. MetadataReader reader(hfile);
  269. if (reader.handle == INVALID_HANDLE_VALUE)
  270. return false;
  271. wchar_t tempPath[MAX_PATH-14] = {0}, tempFile[MAX_PATH] = {0};
  272. GetTempPathW(MAX_PATH-14, tempPath);
  273. GetTempFileNameW(tempPath, L"waf", 0, tempFile);
  274. HANDLE hTempFile = CreateFileW(tempFile, GENERIC_READ|GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
  275. MetadataReader tempReader(hTempFile);
  276. FLAC__bool res = FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, false, &reader, unicodeIO, &tempReader, unicodeIO);
  277. CloseHandle(hfile);
  278. CloseHandle(hTempFile);
  279. if (!MoveFileW(tempFile, filename))
  280. {
  281. if (CopyFileW(tempFile, filename, FALSE))
  282. {
  283. DeleteFileW(tempFile);
  284. }
  285. else
  286. {
  287. DeleteFileW(tempFile);
  288. return false;
  289. }
  290. }
  291. return !!res;
  292. }
  293. else
  294. {
  295. HANDLE hfile = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
  296. MetadataReader reader(hfile);
  297. if (reader.handle == INVALID_HANDLE_VALUE)
  298. return false;
  299. FLAC__bool res = FLAC__metadata_chain_write_with_callbacks(chain, true, &reader, unicodeIO);
  300. CloseHandle(hfile);
  301. return !!res;
  302. }
  303. }
  304. bool FLACMetadata::GetLengthMilliseconds(unsigned __int64 *length)
  305. {
  306. if (!streamInfo)
  307. return false;
  308. *length = (__int64)((double)(FLAC__int64)streamInfo->data.stream_info.total_samples / (double)streamInfo->data.stream_info.sample_rate * 1000.0 + 0.5);
  309. return true;
  310. }
  311. int FLACMetadata::GetNumMetadataItems()
  312. {
  313. if (block) return block->data.vorbis_comment.num_comments;
  314. else return 0;
  315. }
  316. const char* FLACMetadata::EnumMetadata(int n, char *tag, int taglen)
  317. {
  318. if (tag) tag[0]=0;
  319. if (!block) return 0;
  320. const char *entry = (const char *)block->data.vorbis_comment.comments[n].entry;
  321. const char *metadata = strchr(entry, '='); // find the first equal
  322. if (metadata)
  323. {
  324. if (tag) lstrcpynA(tag,entry,min(metadata-entry+1,taglen));
  325. return metadata+1;
  326. }
  327. else return 0;
  328. }
  329. void FLACMetadata::SetTag(int pos, const char *tag)
  330. {
  331. char * value = (char*)EnumMetadata(pos,0,0);
  332. value = _strdup(value?value:"");
  333. FLAC__StreamMetadata_VorbisComment_Entry entry;
  334. size_t totalLen = strlen(tag) + 1 /* = */ + strlen(value);
  335. entry.entry = (FLAC__byte *)malloc(totalLen + 1);
  336. entry.length = totalLen;
  337. StringCchPrintfA((char *)entry.entry, totalLen+1, "%s=%s", tag, value);
  338. FLAC__metadata_object_vorbiscomment_set_comment(block, pos, entry, true);
  339. free(value);
  340. }
  341. bool FLACMetadata::GetPicture(FLAC__StreamMetadata_Picture_Type type, void **data, size_t *len, wchar_t **mimeType)
  342. {
  343. if (!chain || !itr)
  344. return false;
  345. FLAC__metadata_iterator_init(itr, chain);
  346. while (1)
  347. {
  348. if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
  349. {
  350. FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
  351. FLAC__StreamMetadata_Picture &picture = block->data.picture;
  352. if (picture.type == type)
  353. {
  354. *len = picture.data_length;
  355. *data = WASABI_API_MEMMGR->sysMalloc(picture.data_length);
  356. if (!*data)
  357. return false;
  358. memcpy(*data, picture.data, picture.data_length);
  359. char *type = 0;
  360. if (picture.mime_type)
  361. type = strchr(picture.mime_type, '/');
  362. if (type && *type)
  363. {
  364. type++;
  365. char *type2 = strchr(type, '/');
  366. if (type2 && *type2) type2++;
  367. else type2 = type;
  368. int typelen = MultiByteToWideChar(CP_ACP, 0, type2, -1, 0, 0);
  369. *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(typelen * sizeof(wchar_t));
  370. if (*mimeType)
  371. MultiByteToWideChar(CP_ACP, 0, type, -1, *mimeType, typelen);
  372. }
  373. else
  374. *mimeType = 0; // unknown!
  375. return true;
  376. }
  377. }
  378. if (FLAC__metadata_iterator_next(itr) == false)
  379. break;
  380. }
  381. return false;
  382. }
  383. bool FLACMetadata::RemovePicture(FLAC__StreamMetadata_Picture_Type type)
  384. {
  385. if (!chain || !itr)
  386. return false;
  387. FLAC__metadata_iterator_init(itr, chain);
  388. while (1)
  389. {
  390. if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
  391. {
  392. FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
  393. FLAC__StreamMetadata_Picture &picture = block->data.picture;
  394. if (picture.type == type)
  395. {
  396. FLAC__metadata_iterator_delete_block(itr, false);
  397. return true;
  398. }
  399. }
  400. if (FLAC__metadata_iterator_next(itr) == false)
  401. break;
  402. }
  403. return false;
  404. }
  405. bool FLACMetadata::SetPicture(FLAC__StreamMetadata_Picture_Type type, void *data, size_t len, const wchar_t *mimeType, int width, int height)
  406. {
  407. if (!chain || !itr)
  408. return false;
  409. FLAC__metadata_iterator_init(itr, chain);
  410. while (1)
  411. {
  412. if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
  413. {
  414. FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
  415. FLAC__StreamMetadata_Picture &picture = block->data.picture;
  416. if (picture.type == type)
  417. {
  418. FLAC__metadata_object_picture_set_data(block, (FLAC__byte *)data, len, true);
  419. picture.width = width;
  420. picture.height = height;
  421. picture.depth = 32;
  422. picture.colors = 0;
  423. FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"", true);// TODO?
  424. char mime[256] = {0};
  425. if (wcsstr(mimeType, L"/") != 0)
  426. {
  427. StringCchPrintfA(mime, 256, "%S", mimeType);
  428. }
  429. else
  430. {
  431. StringCchPrintfA(mime, 256, "image/%S", mimeType);
  432. }
  433. FLAC__metadata_object_picture_set_mime_type(block, mime, true);
  434. return true;
  435. }
  436. }
  437. if (FLAC__metadata_iterator_next(itr) == false)
  438. break;
  439. }
  440. // not found. let's add it
  441. FLAC__StreamMetadata *newBlock = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
  442. FLAC__metadata_object_picture_set_data(newBlock, (FLAC__byte *)data, len, true);
  443. FLAC__StreamMetadata_Picture &picture = newBlock->data.picture;
  444. picture.type = type;
  445. picture.width = width;
  446. picture.height = height;
  447. picture.depth = 32;
  448. picture.colors = 0;
  449. FLAC__metadata_object_picture_set_description(newBlock, (FLAC__byte *)"", true);// TODO?
  450. char mime[256] = {0};
  451. StringCchPrintfA(mime, 256, "image/%S", mimeType);
  452. FLAC__metadata_object_picture_set_mime_type(newBlock, mime, true);
  453. FLAC__metadata_iterator_insert_block_after(itr, newBlock);
  454. return true;
  455. }
  456. bool FLACMetadata::GetIndexPicture(int index, FLAC__StreamMetadata_Picture_Type *type, void **data, size_t *len, wchar_t **mimeType)
  457. {
  458. if (!chain || !itr)
  459. return false;
  460. int i=0;
  461. FLAC__metadata_iterator_init(itr, chain);
  462. while (1)
  463. {
  464. if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
  465. {
  466. FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
  467. FLAC__StreamMetadata_Picture &picture = block->data.picture;
  468. if (i++ == index)
  469. {
  470. *type = picture.type;
  471. *len = picture.data_length;
  472. *data = WASABI_API_MEMMGR->sysMalloc(picture.data_length);
  473. if (!*data)
  474. return false;
  475. memcpy(*data, picture.data, picture.data_length);
  476. char *type = 0;
  477. if (picture.mime_type)
  478. type = strchr(picture.mime_type, '/');
  479. if (type && *type)
  480. {
  481. type++;
  482. int typelen = MultiByteToWideChar(CP_ACP, 0, type, -1, 0, 0);
  483. *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(typelen * sizeof(wchar_t));
  484. if (*mimeType)
  485. MultiByteToWideChar(CP_ACP, 0, type, -1, *mimeType, typelen);
  486. }
  487. else
  488. *mimeType = 0; // unknown!
  489. return true;
  490. }
  491. }
  492. if (FLAC__metadata_iterator_next(itr) == false)
  493. break;
  494. }
  495. return false;
  496. }