123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577 |
- /*
- ** Copyright (C) 2007-2011 Nullsoft, Inc.
- **
- ** This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held
- ** liable for any damages arising from the use of this software.
- **
- ** Permission is granted to anyone to use this software for any purpose, including commercial applications, and to
- ** alter it and redistribute it freely, subject to the following restrictions:
- **
- ** 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software.
- ** If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
- **
- ** 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
- **
- ** 3. This notice may not be removed or altered from any source distribution.
- **
- ** Author: Ben Allison [email protected]
- ** Created: March 1, 2007
- **
- */
- #include "Metadata.h"
- #include <FLAC/all.h>
- #include "StreamFileWin32.h" // for FileSize64
- #include "api__in_flv.h"
- #include <strsafe.h>
- struct MetadataReader
- {
- MetadataReader(HANDLE _handle)
- {
- handle = _handle;
- endOfFile=false;
- }
- HANDLE handle;
- bool endOfFile;
- };
- static size_t win32_read(void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
- {
- MetadataReader *reader = (MetadataReader *)handle;
- DWORD bytesRead=0;
- BOOL result = ReadFile(reader->handle, ptr, size*nmemb, &bytesRead, NULL);
- if (result == TRUE && bytesRead == 0)
- reader->endOfFile=true;
- return bytesRead/size;
- }
- static size_t win32_write(const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle)
- {
- MetadataReader *reader = (MetadataReader *)handle;
- DWORD bytesWritten=0;
- WriteFile(reader->handle, ptr, size*nmemb, &bytesWritten, NULL);
- return bytesWritten/size;
- }
- static __int64 Seek64(HANDLE hf, __int64 distance, DWORD MoveMethod)
- {
- LARGE_INTEGER li;
- li.QuadPart = distance;
- li.LowPart = SetFilePointer (hf, li.LowPart, &li.HighPart, MoveMethod);
- if (li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
- {
- li.QuadPart = -1;
- }
- return li.QuadPart;
- }
- static int win32_seek(FLAC__IOHandle handle, FLAC__int64 offset, int whence)
- {
- MetadataReader *reader = (MetadataReader *)handle;
- if (Seek64(reader->handle, offset, whence) == -1)
- return -1;
- else
- return 0;
-
- }
- static FLAC__int64 win32_tell(FLAC__IOHandle handle)
- {
- MetadataReader *reader = (MetadataReader *)handle;
- return Seek64(reader->handle, 0, FILE_CURRENT);
- }
- static int win32_eof(FLAC__IOHandle handle)
- {
- MetadataReader *reader = (MetadataReader *)handle;
- return !!reader->endOfFile;
- }
- static int win32_close(FLAC__IOHandle handle)
- {
- MetadataReader *reader = (MetadataReader *)handle;
- CloseHandle(reader->handle);
- reader->handle = INVALID_HANDLE_VALUE;
- return 0;
- }
- static FLAC__IOCallbacks unicodeIO =
- {
- win32_read,
- win32_write,
- win32_seek,
- win32_tell,
- win32_eof,
- win32_close,
- };
- FLACMetadata::FLACMetadata()
- {
- chain=FLAC__metadata_chain_new();
- itr = FLAC__metadata_iterator_new();
- block=0;
- streamInfo=0;
- filesize=0;
- }
- FLACMetadata::~FLACMetadata()
- {
- if (chain)
- FLAC__metadata_chain_delete(chain);
- if (itr)
- FLAC__metadata_iterator_delete(itr);
- }
- void FLACMetadata::Reset()
- {
- if (chain)
- FLAC__metadata_chain_delete(chain);
- if (itr)
- FLAC__metadata_iterator_delete(itr);
- chain=FLAC__metadata_chain_new();
- itr = FLAC__metadata_iterator_new();
- block=0;
- streamInfo=0;
- filesize=0;
- }
- const FLAC__StreamMetadata_StreamInfo *FLACMetadata::GetStreamInfo()
- {
- if (streamInfo)
- return &streamInfo->data.stream_info;
- else
- return 0;
- }
- bool FLACMetadata::Open(const wchar_t *filename, bool optimize)
- {
- if (!chain || !itr)
- return false;
- HANDLE hfile = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, 0);
- MetadataReader reader(hfile);
- if (reader.handle == INVALID_HANDLE_VALUE)
- return false;
- filesize = FileSize64(reader.handle);
- FLAC__bool success = FLAC__metadata_chain_read_with_callbacks(chain, &reader, unicodeIO);
- CloseHandle(hfile);
- if (!success)
- return false;
- if (optimize)
- {
- FLAC__metadata_chain_sort_padding(chain);
- FLAC__metadata_chain_merge_padding(chain);
- }
- FLAC__metadata_iterator_init(itr, chain);
- while (1)
- {
- FLAC__MetadataType type=FLAC__metadata_iterator_get_block_type(itr);
- switch (type)
- {
- case FLAC__METADATA_TYPE_VORBIS_COMMENT:
- block = FLAC__metadata_iterator_get_block(itr);
- break;
- case FLAC__METADATA_TYPE_STREAMINFO:
- streamInfo = FLAC__metadata_iterator_get_block(itr);
- break;
- }
- if (FLAC__metadata_iterator_next(itr) == false)
- break;
- }
- return true;
- }
- const char *FLACMetadata::GetMetadata(const char *tag)
- {
- if (!block)
- return 0;
- int pos = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, tag);
- if (pos < 0)
- {
- // fail
- }
- else
- {
- const char *entry = (const char *)block->data.vorbis_comment.comments[pos].entry;
- const char *metadata = strchr(entry, '='); // find the first equal
- if (metadata)
- {
- return metadata+1;
- }
- }
- return 0;
- }
- void FLACMetadata::SetMetadata(const char *tag, const char *value)
- {
- if (!block)
- {
- FLAC__metadata_iterator_init(itr, chain);
- do
- {
- if (FLAC__METADATA_TYPE_VORBIS_COMMENT == FLAC__metadata_iterator_get_block_type(itr))
- {
- block = FLAC__metadata_iterator_get_block(itr);
- break;
- }
- }
- while (FLAC__metadata_iterator_next(itr) != 0);
- if (!block)
- {
- block = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
- FLAC__metadata_iterator_insert_block_after(itr, block);
- }
- }
- if (!block)
- return;
- FLAC__StreamMetadata_VorbisComment_Entry entry;
- size_t totalLen = strlen(tag) + 1 /* = */ + strlen(value);
- entry.entry = (FLAC__byte *)malloc(totalLen + 1);
- entry.length = totalLen;
- StringCchPrintfA((char *)entry.entry, totalLen+1, "%s=%s", tag, value);
- int pos = FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, tag);
- if (pos < 0)
- {
- //new comment
- FLAC__metadata_object_vorbiscomment_append_comment(block, entry, true);
- // would love to not copy, but we can't guarantee that FLAC links to the same CRT as us
- }
- else
- {
- FLAC__metadata_object_vorbiscomment_set_comment(block, pos, entry, true);
- // would love to not copy, but we can't guarantee that FLAC links to the same CRT as us
- }
- free(entry.entry);
- }
- void FLACMetadata::RemoveMetadata(const char *tag)
- {
- if (!block)
- return;
- FLAC__metadata_object_vorbiscomment_remove_entries_matching(block, tag);
- }
- void FLACMetadata::RemoveMetadata(int n)
- {
- if (!block)
- return;
- FLAC__metadata_object_vorbiscomment_delete_comment(block, (unsigned int)n);
- }
- static FLAC__StreamMetadata *GetOrMakePadding(FLAC__Metadata_Chain *chain, FLAC__Metadata_Iterator *itr)
- {
- FLAC__metadata_iterator_init(itr, chain);
- while (1)
- {
- if (FLAC__METADATA_TYPE_PADDING == FLAC__metadata_iterator_get_block_type(itr))
- {
- FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
- return block;
- }
- if (FLAC__metadata_iterator_next(itr) == false)
- break;
- }
- FLAC__StreamMetadata *padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
- if (padding)
- FLAC__metadata_iterator_insert_block_after(itr, padding);
- return padding;
- }
- bool FLACMetadata::Save(const wchar_t *filename)
- {
- if (FLAC__metadata_chain_check_if_tempfile_needed(chain, true))
- {
- // since we needed to write a tempfile, let's add some more padding so it doesn't happen again
- FLAC__metadata_chain_sort_padding(chain);
- FLAC__StreamMetadata *padding = GetOrMakePadding(chain, itr);
- if (padding && padding->length < 16384)
- padding->length = 16384; // TODO: configurable padding size
- HANDLE hfile = CreateFileW(filename, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
- MetadataReader reader(hfile);
- if (reader.handle == INVALID_HANDLE_VALUE)
- return false;
- wchar_t tempPath[MAX_PATH-14] = {0}, tempFile[MAX_PATH] = {0};
- GetTempPathW(MAX_PATH-14, tempPath);
- GetTempFileNameW(tempPath, L"waf", 0, tempFile);
- HANDLE hTempFile = CreateFileW(tempFile, GENERIC_READ|GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
- MetadataReader tempReader(hTempFile);
- FLAC__bool res = FLAC__metadata_chain_write_with_callbacks_and_tempfile(chain, false, &reader, unicodeIO, &tempReader, unicodeIO);
- CloseHandle(hfile);
- CloseHandle(hTempFile);
- if (!MoveFileW(tempFile, filename))
- {
- if (CopyFileW(tempFile, filename, FALSE))
- {
- DeleteFileW(tempFile);
- }
- else
- {
- DeleteFileW(tempFile);
- return false;
- }
- }
- return !!res;
- }
- else
- {
- HANDLE hfile = CreateFileW(filename, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
- MetadataReader reader(hfile);
- if (reader.handle == INVALID_HANDLE_VALUE)
- return false;
- FLAC__bool res = FLAC__metadata_chain_write_with_callbacks(chain, true, &reader, unicodeIO);
- CloseHandle(hfile);
- return !!res;
- }
- }
- bool FLACMetadata::GetLengthMilliseconds(unsigned __int64 *length)
- {
- if (!streamInfo)
- return false;
- *length = (__int64)((double)(FLAC__int64)streamInfo->data.stream_info.total_samples / (double)streamInfo->data.stream_info.sample_rate * 1000.0 + 0.5);
- return true;
- }
- int FLACMetadata::GetNumMetadataItems()
- {
- if (block) return block->data.vorbis_comment.num_comments;
- else return 0;
- }
- const char* FLACMetadata::EnumMetadata(int n, char *tag, int taglen)
- {
- if (tag) tag[0]=0;
- if (!block) return 0;
- const char *entry = (const char *)block->data.vorbis_comment.comments[n].entry;
- const char *metadata = strchr(entry, '='); // find the first equal
- if (metadata)
- {
- if (tag) lstrcpynA(tag,entry,min(metadata-entry+1,taglen));
- return metadata+1;
- }
- else return 0;
- }
- void FLACMetadata::SetTag(int pos, const char *tag)
- {
- char * value = (char*)EnumMetadata(pos,0,0);
- value = _strdup(value?value:"");
- FLAC__StreamMetadata_VorbisComment_Entry entry;
- size_t totalLen = strlen(tag) + 1 /* = */ + strlen(value);
- entry.entry = (FLAC__byte *)malloc(totalLen + 1);
- entry.length = totalLen;
- StringCchPrintfA((char *)entry.entry, totalLen+1, "%s=%s", tag, value);
- FLAC__metadata_object_vorbiscomment_set_comment(block, pos, entry, true);
- free(value);
- }
- bool FLACMetadata::GetPicture(FLAC__StreamMetadata_Picture_Type type, void **data, size_t *len, wchar_t **mimeType)
- {
- if (!chain || !itr)
- return false;
- FLAC__metadata_iterator_init(itr, chain);
- while (1)
- {
- if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
- {
- FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
- FLAC__StreamMetadata_Picture &picture = block->data.picture;
- if (picture.type == type)
- {
- *len = picture.data_length;
- *data = WASABI_API_MEMMGR->sysMalloc(picture.data_length);
- if (!*data)
- return false;
- memcpy(*data, picture.data, picture.data_length);
- char *type = 0;
- if (picture.mime_type)
- type = strchr(picture.mime_type, '/');
- if (type && *type)
- {
- type++;
- char *type2 = strchr(type, '/');
- if (type2 && *type2) type2++;
- else type2 = type;
- int typelen = MultiByteToWideChar(CP_ACP, 0, type2, -1, 0, 0);
- *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(typelen * sizeof(wchar_t));
- if (*mimeType)
- MultiByteToWideChar(CP_ACP, 0, type, -1, *mimeType, typelen);
- }
- else
- *mimeType = 0; // unknown!
- return true;
- }
- }
- if (FLAC__metadata_iterator_next(itr) == false)
- break;
- }
- return false;
- }
- bool FLACMetadata::RemovePicture(FLAC__StreamMetadata_Picture_Type type)
- {
- if (!chain || !itr)
- return false;
- FLAC__metadata_iterator_init(itr, chain);
- while (1)
- {
- if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
- {
- FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
- FLAC__StreamMetadata_Picture &picture = block->data.picture;
- if (picture.type == type)
- {
- FLAC__metadata_iterator_delete_block(itr, false);
- return true;
- }
- }
- if (FLAC__metadata_iterator_next(itr) == false)
- break;
- }
- return false;
- }
- bool FLACMetadata::SetPicture(FLAC__StreamMetadata_Picture_Type type, void *data, size_t len, const wchar_t *mimeType, int width, int height)
- {
- if (!chain || !itr)
- return false;
- FLAC__metadata_iterator_init(itr, chain);
- while (1)
- {
- if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
- {
- FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
- FLAC__StreamMetadata_Picture &picture = block->data.picture;
- if (picture.type == type)
- {
- FLAC__metadata_object_picture_set_data(block, (FLAC__byte *)data, len, true);
- picture.width = width;
- picture.height = height;
- picture.depth = 32;
- picture.colors = 0;
- FLAC__metadata_object_picture_set_description(block, (FLAC__byte *)"", true);// TODO?
- char mime[256] = {0};
- if (wcsstr(mimeType, L"/") != 0)
- {
- StringCchPrintfA(mime, 256, "%S", mimeType);
- }
- else
- {
- StringCchPrintfA(mime, 256, "image/%S", mimeType);
- }
- FLAC__metadata_object_picture_set_mime_type(block, mime, true);
- return true;
- }
- }
- if (FLAC__metadata_iterator_next(itr) == false)
- break;
- }
- // not found. let's add it
- FLAC__StreamMetadata *newBlock = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PICTURE);
- FLAC__metadata_object_picture_set_data(newBlock, (FLAC__byte *)data, len, true);
- FLAC__StreamMetadata_Picture &picture = newBlock->data.picture;
- picture.type = type;
- picture.width = width;
- picture.height = height;
- picture.depth = 32;
- picture.colors = 0;
- FLAC__metadata_object_picture_set_description(newBlock, (FLAC__byte *)"", true);// TODO?
- char mime[256] = {0};
- StringCchPrintfA(mime, 256, "image/%S", mimeType);
- FLAC__metadata_object_picture_set_mime_type(newBlock, mime, true);
- FLAC__metadata_iterator_insert_block_after(itr, newBlock);
- return true;
- }
- bool FLACMetadata::GetIndexPicture(int index, FLAC__StreamMetadata_Picture_Type *type, void **data, size_t *len, wchar_t **mimeType)
- {
- if (!chain || !itr)
- return false;
- int i=0;
- FLAC__metadata_iterator_init(itr, chain);
- while (1)
- {
- if (FLAC__METADATA_TYPE_PICTURE == FLAC__metadata_iterator_get_block_type(itr))
- {
- FLAC__StreamMetadata *block = FLAC__metadata_iterator_get_block(itr);
- FLAC__StreamMetadata_Picture &picture = block->data.picture;
- if (i++ == index)
- {
- *type = picture.type;
- *len = picture.data_length;
- *data = WASABI_API_MEMMGR->sysMalloc(picture.data_length);
- if (!*data)
- return false;
- memcpy(*data, picture.data, picture.data_length);
- char *type = 0;
- if (picture.mime_type)
- type = strchr(picture.mime_type, '/');
- if (type && *type)
- {
- type++;
- int typelen = MultiByteToWideChar(CP_ACP, 0, type, -1, 0, 0);
- *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc(typelen * sizeof(wchar_t));
- if (*mimeType)
- MultiByteToWideChar(CP_ACP, 0, type, -1, *mimeType, typelen);
- }
- else
- *mimeType = 0; // unknown!
- return true;
- }
- }
- if (FLAC__metadata_iterator_next(itr) == false)
- break;
- }
- return false;
- }
|