MF_API MFFile* MFFile_CreateMemoryFile(const void *pMemory, size_t size, bool writable, bool ownMemory) { MFOpenDataMemory memory; memory.cbSize = sizeof(MFOpenDataMemory); memory.openFlags = MFOF_Read|MFOF_Binary|(writable ? MFOF_Write : 0); memory.pMemoryPointer = (void*)pMemory; memory.fileSize = size; memory.allocated = size; memory.ownsMemory = false; return MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_MemoryFileSystem), &memory); }
MFFile* MFFileSystemZipFile_Open(MFMount *pMount, const char *pFilename, uint32 openFlags) { MFCALLSTACK; MFFile *hFile = NULL; // recurse toc MFTOCEntry *pTOCEntry = MFFileSystem_GetTocEntry(pFilename, pMount->pEntries, pMount->numFiles); if(pTOCEntry) { MFOpenDataZipFile openData; openData.cbSize = sizeof(MFOpenDataZipFile); openData.openFlags = openFlags | MFOF_Zip_AlreadyMounted; openData.pZipArchive = (MFFile*)pMount->pFilesysData; openData.pFilename = MFStr("%s%s", pTOCEntry->pFilesysData ? (char*)pTOCEntry->pFilesysData : "", pTOCEntry->pName); hFile = MFFile_Open(hZipFileSystem, &openData); } return hFile; }
void MFFileSystem_RegisterDefaultArchives(void *) { GET_MODULE_DATA(MFFileSystemState); MFFile *&hDataArchive = pModuleData->hDataArchive; MFFile *&hPatchArchive = pModuleData->hPatchArchive; // try and mount the 'standard' archives... // TODO: ponder removing this code and forcing the use of a filesystem init callback? :/ MFOpenDataNative dataArchive; dataArchive.cbSize = sizeof(MFOpenDataNative); dataArchive.openFlags = MFOF_Read|MFOF_Binary; hDataArchive = 0; const char **pArc = gArchiveNames; while(!hDataArchive && *pArc) { dataArchive.pFilename = MFFile_SystemPath(MFStr(*pArc, MFSystem_GetPlatformString(MFSystem_GetCurrentPlatform()))); hDataArchive = MFFile_Open(pModuleData->hNativeFileSystem, &dataArchive); ++pArc; } MFMountDataNative mountData; mountData.cbSize = sizeof(MFMountDataNative); mountData.priority = MFMP_Normal; if(hDataArchive) { // attempt to cache the zip archive MFOpenDataCachedFile cachedOpen; cachedOpen.cbSize = sizeof(MFOpenDataCachedFile); cachedOpen.openFlags = MFOF_Read | MFOF_Binary | MFOF_Cached_CleanupBaseFile; cachedOpen.maxCacheSize = 1*1024*1024; // 1mb cache for zip archives should be heaps!! cachedOpen.pBaseFile = hDataArchive; MFFile *pCachedFile = MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_CachedFileSystem), &cachedOpen); if(pCachedFile) hDataArchive = pCachedFile; // mount the zip archive. MFMountDataZipFile zipMountData; zipMountData.cbSize = sizeof(MFMountDataZipFile); zipMountData.flags = MFMF_Recursive|MFMF_FlattenDirectoryStructure; zipMountData.priority = MFMP_Normal; zipMountData.pMountpoint = "data"; zipMountData.pZipArchive = hDataArchive; MFFileSystem_Mount(pModuleData->hZipFileSystem, &zipMountData); } mountData.flags = MFMF_DontCacheTOC; mountData.pMountpoint = "home"; mountData.pPath = MFFile_HomePath(); MFFileSystem_Mount(pModuleData->hNativeFileSystem, &mountData); // see if we can mount the patch archive.. hPatchArchive = 0; pArc = gPatchArchiveNames; while(!hPatchArchive && *pArc) { dataArchive.pFilename = MFFile_SystemPath(MFStr(*pArc, MFSystem_GetPlatformString(MFSystem_GetCurrentPlatform()))); hDataArchive = MFFile_Open(pModuleData->hNativeFileSystem, &dataArchive); ++pArc; } if(hPatchArchive) { // attempt to cache the zip archive MFOpenDataCachedFile cachedOpen; cachedOpen.cbSize = sizeof(MFOpenDataCachedFile); cachedOpen.openFlags = MFOF_Read | MFOF_Binary | MFOF_Cached_CleanupBaseFile; cachedOpen.maxCacheSize = 1*1024*1024; // 1mb cache for zip archives should be heaps!! cachedOpen.pBaseFile = hPatchArchive; MFFile *pCachedFile = MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_CachedFileSystem), &cachedOpen); if(pCachedFile) hPatchArchive = pCachedFile; // mount the zip archive. MFMountDataZipFile zipMountData; zipMountData.cbSize = sizeof(MFMountDataZipFile); zipMountData.flags = MFMF_Recursive|MFMF_FlattenDirectoryStructure; zipMountData.priority = MFMP_VeryHigh; zipMountData.pMountpoint = "patch"; zipMountData.pZipArchive = hPatchArchive; MFFileSystem_Mount(pModuleData->hZipFileSystem, &zipMountData); } if(pModuleData->hHTTPFileSystem != -1) { // register the network filesystems MFMountDataHTTP mountDataHTTP; mountDataHTTP.cbSize = sizeof(MFMountDataHTTP); mountDataHTTP.pMountpoint = "http"; mountDataHTTP.priority = MFMP_Normal + 1; mountDataHTTP.flags = MFMF_OnlyAllowExclusiveAccess; MFFileSystem_Mount(pModuleData->hHTTPFileSystem, &mountDataHTTP); } }
void CreateVorbisStream(MFAudioStream *pStream, const char *pFilename) { MFCALLSTACK; MFVorbisStream *pVS = (MFVorbisStream*)MFHeap_Alloc(sizeof(MFVorbisStream)); pStream->pStreamData = pVS; // open vorbis file MFFile* hFile = MFFileSystem_Open(pFilename); if(!hFile) return; // attempt to cache the vorbis stream MFOpenDataCachedFile cachedOpen; cachedOpen.cbSize = sizeof(MFOpenDataCachedFile); cachedOpen.openFlags = MFOF_Read | MFOF_Binary | MFOF_Cached_CleanupBaseFile; cachedOpen.maxCacheSize = 256*1024; // 256k cache for vorbis stream should be heaps!! cachedOpen.pBaseFile = hFile; MFFile *pCachedFile = MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_CachedFileSystem), &cachedOpen); if(pCachedFile) hFile = pCachedFile; // setup vorbis read callbacks ov_callbacks callbacks; callbacks.read_func = MFFile_StdRead; callbacks.seek_func = MFSound_VorbisSeek; callbacks.close_func = MFFile_StdClose; callbacks.tell_func = MFFile_StdTell; // open vorbis file if(ov_test_callbacks(hFile, &pVS->vorbisFile, NULL, 0, callbacks)) { MFDebug_Assert(false, "Not a vorbis file."); MFHeap_Free(pVS); return; } ov_test_open(&pVS->vorbisFile); // get vorbis file info pVS->pInfo = ov_info(&pVS->vorbisFile, -1); #if defined(VORBIS_TREMOR) // pStream->trackLength = (float)ov_pcm_total(&pVS->vorbisFile, -1) / (float)pVS->pInfo->rate; pStream->trackLength = 1000.0f; #else pStream->trackLength = (float)ov_time_total(&pVS->vorbisFile, -1); #endif // fill out the stream info pStream->streamInfo.sampleRate = pVS->pInfo->rate; pStream->streamInfo.channels = pVS->pInfo->channels; pStream->streamInfo.bitsPerSample = 16; pStream->streamInfo.bufferLength = pVS->pInfo->rate; // read the vorbis comment data pVS->pComment = ov_comment(&pVS->vorbisFile, -1); if(pVS->pComment) { const char *pTitle = vorbis_comment_query(pVS->pComment, "TITLE", 0); const char *pArtist = vorbis_comment_query(pVS->pComment, "ALBUM", 0); const char *pAlbum = vorbis_comment_query(pVS->pComment, "ARTIST", 0); const char *pGenre = vorbis_comment_query(pVS->pComment, "GENRE", 0); if(pTitle) MFString_CopyN(pStream->streamInfo.songName, pTitle, sizeof(pStream->streamInfo.songName)-1); if(pArtist) MFString_CopyN(pStream->streamInfo.artistName, pArtist, sizeof(pStream->streamInfo.artistName)-1); if(pAlbum) MFString_CopyN(pStream->streamInfo.albumName, pAlbum, sizeof(pStream->streamInfo.albumName)-1); if(pGenre) MFString_CopyN(pStream->streamInfo.genre, pGenre, sizeof(pStream->streamInfo.genre)-1); } }
void CreateWAVStream(MFAudioStream *pStream, const char *pFilename) { MFCALLSTACK; // open wav file MFFile* hFile = MFFileSystem_Open(pFilename); if(!hFile) return; // attempt to cache the vorbis stream MFOpenDataCachedFile cachedOpen; cachedOpen.cbSize = sizeof(MFOpenDataCachedFile); cachedOpen.openFlags = MFOF_Read | MFOF_Binary | MFOF_Cached_CleanupBaseFile; cachedOpen.maxCacheSize = 256*1024; // 256k cache for wav stream should be heaps!! cachedOpen.pBaseFile = hFile; MFFile *pCachedFile = MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_CachedFileSystem), &cachedOpen); if(pCachedFile) hFile = pCachedFile; RIFFHeader header; MFFile_Read(hFile, &header, sizeof(header)); if(header.RIFF != MFMAKEFOURCC('R', 'I', 'F', 'F') || header.WAVE != MFMAKEFOURCC('W', 'A', 'V', 'E')) return; // not a .wav file... // if everything's good, and it appears to be a valid wav file MFWAVStream *pWS = (MFWAVStream*)MFHeap_AllocAndZero(sizeof(MFWAVStream)); pStream->pStreamData = pWS; pWS->pStream = hFile; size_t read; size_t fptr = sizeof(header); do { MFFile_Seek(hFile, fptr, MFSeek_Begin); WAVChunk dataChunk; MFZeroMemory(&dataChunk, sizeof(dataChunk)); read = MFFile_Read(hFile, &dataChunk, sizeof(dataChunk)); fptr += sizeof(dataChunk) + dataChunk.size; if(dataChunk.id == MFMAKEFOURCC('f', 'm', 't', ' ')) { read = MFFile_Read(hFile, &pWS->format, dataChunk.size); if(pWS->format.cbSize) read = (size_t)MFFile_Seek(hFile, pWS->format.cbSize, MFSeek_Current); } else if(dataChunk.id == MFMAKEFOURCC('d', 'a', 't', 'a')) { pWS->dataOffset = (size_t)MFFile_Tell(hFile); pWS->dataSize = dataChunk.size; } } while(read); // return to the start of the audio data MFFile_Seek(pWS->pStream, (int)pWS->dataOffset, MFSeek_Begin); // calculate the track length pWS->sampleSize = (pWS->format.nChannels * pWS->format.wBitsPerSample) >> 3; pStream->trackLength = (float)(pWS->dataSize / pWS->sampleSize) / (float)pWS->format.nSamplesPerSec; // fill out the stream info pStream->streamInfo.sampleRate = pWS->format.nSamplesPerSec; pStream->streamInfo.channels = pWS->format.nChannels; pStream->streamInfo.bitsPerSample = pWS->format.wBitsPerSample; pStream->streamInfo.bufferLength = pWS->format.nSamplesPerSec; }