diff --git a/AudioUnit/AmuseContainerMainMenu.xib b/AudioUnit/AmuseContainerMainMenu.xib index f04a06a..a7cc169 100644 --- a/AudioUnit/AmuseContainerMainMenu.xib +++ b/AudioUnit/AmuseContainerMainMenu.xib @@ -17,6 +17,7 @@ + @@ -69,7 +70,7 @@ - + @@ -149,7 +150,7 @@ - + @@ -166,121 +167,75 @@ - + - + - + - - + + - - + + - + + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -715,10 +669,10 @@ - - - - + + + + diff --git a/AudioUnit/AmuseContainingApp.mm b/AudioUnit/AmuseContainingApp.mm index 446601b..0c7c4a0 100644 --- a/AudioUnit/AmuseContainingApp.mm +++ b/AudioUnit/AmuseContainingApp.mm @@ -3,6 +3,7 @@ #import #import "AudioUnitViewController.hpp" #import "AudioGroupFilePresenter.hpp" +#include @class DataOutlineController; @class SamplesTableController; @@ -37,16 +38,17 @@ { IBOutlet NSWindow* mainWindow; IBOutlet NSOutlineView* dataOutline; + IBOutlet NSSearchField* dataSearchField; IBOutlet NSTableView* sfxTable; IBOutlet NSTableView* samplesTable; IBOutlet NSTextView* creditsView; AudioGroupFilePresenter* groupFilePresenter; - DataOutlineController* dataController; SamplesTableController* samplesController; SFXTableController* sfxController; } +- (BOOL)importURL:(NSURL*)url; @end @interface MainTabView : NSTabView @@ -98,17 +100,6 @@ @end -@interface DataOutlineController : NSObject -{ - -} -@end - -@implementation DataOutlineController - - - -@end @interface SamplesTableController : NSObject { @@ -158,9 +149,8 @@ groupFilePresenter = [AudioGroupFilePresenter new]; - dataController = [DataOutlineController new]; - dataOutline.dataSource = dataController; - dataOutline.delegate = dataController; + dataOutline.dataSource = groupFilePresenter; + dataOutline.delegate = groupFilePresenter; [dataOutline reloadItem:nil reloadChildren:YES]; samplesController = [SamplesTableController new]; @@ -179,9 +169,34 @@ return YES; } -- (IBAction)quitApp:(id)sender +- (BOOL)importURL:(NSURL*)url { - [NSApp terminate:sender]; + amuse::ContainerRegistry::Type containerType; + std::vector> data = + amuse::ContainerRegistry::LoadContainer(url.path.UTF8String, containerType); + if (data.empty()) + { + NSString* err = [NSString stringWithFormat:@"Unable to load Audio Groups from %s", url.path.UTF8String]; + NSAlert* alert = [[NSAlert alloc] init]; + alert.informativeText = err; + alert.messageText = @"Invalid Data File"; + [alert runModal]; + return false; + } + + std::string name(amuse::ContainerRegistry::TypeToName(containerType)); + return [groupFilePresenter addCollectionName:std::move(name) items:std::move(data)]; +} + +- (IBAction)importFile:(id)sender +{ + __block NSOpenPanel* panel = [NSOpenPanel openPanel]; + [panel beginSheetModalForWindow:mainWindow completionHandler:^(NSInteger result) { + if (result == NSFileHandlingPanelOKButton) + { + [self importURL:panel.URL]; + } + }]; } @end diff --git a/AudioUnit/AudioGroupFilePresenter.hpp b/AudioUnit/AudioGroupFilePresenter.hpp index df70dba..6c71023 100644 --- a/AudioUnit/AudioGroupFilePresenter.hpp +++ b/AudioUnit/AudioGroupFilePresenter.hpp @@ -5,20 +5,44 @@ #import #include #include +#include "optional.hpp" +#include +#include @class AudioGroupFilePresenter; +@class AudioGroupDataToken; +@class AudioGroupCollectionToken; struct AudioGroupDataCollection { + std::string m_name; NSURL* m_proj; NSURL* m_pool; NSURL* m_sdir; NSURL* m_samp; + NSURL* m_meta; + + AudioGroupDataToken* m_token; - std::unique_ptr m_projData; - std::unique_ptr m_poolData; - std::unique_ptr m_sdirData; - std::unique_ptr m_sampData; + std::vector m_projData; + std::vector m_poolData; + std::vector m_sdirData; + std::vector m_sampData; + + struct MetaData + { + amuse::DataFormat fmt; + uint32_t absOffs; + uint32_t active; + MetaData(amuse::DataFormat fmtIn, uint32_t absOffsIn, uint32_t activeIn) + : fmt(fmtIn), absOffs(absOffsIn), active(activeIn) {} + MetaData(athena::io::FileReader& r) + : fmt(amuse::DataFormat(r.readUint32Big())), absOffs(r.readUint32Big()), active(r.readUint32Big()) {} + }; + std::experimental::optional m_metaData; + + std::experimental::optional m_loadedData; + std::experimental::optional m_loadedProj; void moveURL(NSURL* oldUrl, NSURL* newUrl); @@ -26,24 +50,82 @@ struct AudioGroupDataCollection bool loadPool(AudioGroupFilePresenter* presenter); bool loadSdir(AudioGroupFilePresenter* presenter); bool loadSamp(AudioGroupFilePresenter* presenter); + bool loadMeta(AudioGroupFilePresenter* presenter); - AudioGroupDataCollection(NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp) - : m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp) {} - bool isDataComplete () const {return m_projData && m_poolData && m_sdirData && m_sampData;} + AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, NSURL* sdir, NSURL* samp, NSURL* meta); + bool isDataComplete() const {return m_projData.size() && m_poolData.size() && m_sdirData.size() && m_sampData.size() && m_metaData;} + bool _attemptLoad(AudioGroupFilePresenter* presenter); }; -@interface AudioGroupFilePresenter : NSObject +template +class IteratorTracker +{ + typename std::map::const_iterator m_audioGroupOutlineBegin; + typename std::map::const_iterator m_audioGroupOutlineEnd; + typename std::map::const_iterator m_audioGroupOutlineIt; + size_t m_audioGroupOutlineIdx = 0; + +public: + IteratorTracker(typename std::map::const_iterator begin, + typename std::map::const_iterator end) + : m_audioGroupOutlineBegin(begin), m_audioGroupOutlineEnd(end), m_audioGroupOutlineIt(begin) {} + typename std::map::const_iterator seekToIndex(size_t idx) + { + if (idx == m_audioGroupOutlineIdx) + return m_audioGroupOutlineIt; + if (idx < m_audioGroupOutlineIdx) + { + for (; idx < m_audioGroupOutlineIdx && m_audioGroupOutlineIt != m_audioGroupOutlineBegin ; + --m_audioGroupOutlineIdx, --m_audioGroupOutlineIt) {} + return m_audioGroupOutlineIt; + } + for (; idx > m_audioGroupOutlineIdx && m_audioGroupOutlineIt != m_audioGroupOutlineEnd ; + ++m_audioGroupOutlineIdx, ++m_audioGroupOutlineIt) {} + return m_audioGroupOutlineIt; + } +}; + +struct AudioGroupCollection +{ + NSURL* m_url; + + AudioGroupCollectionToken* m_token; + std::map m_groups; + std::experimental::optional> m_iteratorTracker; + + AudioGroupCollection(NSURL* url); + void addCollection(std::vector>&& collection); + void update(AudioGroupFilePresenter* presenter); +}; + +@interface AudioGroupDataToken : NSObject +{ +@public + AudioGroupDataCollection* m_collection; +} +- (id)initWithDataCollection:(AudioGroupDataCollection*)collection; +@end + +@interface AudioGroupCollectionToken : NSObject +{ +@public + AudioGroupCollection* m_collection; +} +- (id)initWithCollection:(AudioGroupCollection*)collection; +@end + +@interface AudioGroupFilePresenter : NSObject { NSURL* m_groupURL; NSOperationQueue* m_dataQueue; - std::map m_audioGroupCollections; + std::map m_audioGroupCollections; + NSOutlineView* lastOutlineView; - std::map::const_iterator m_audioGroupOutlineIt; - size_t m_audioGroupOutlineIdx; + std::experimental::optional> m_iteratorTracker; } - +- (BOOL)addCollectionName:(std::string&&)name items:(std::vector>&&)collection; - (void)update; - +- (void)resetIterators; @end #endif // __AMUSE_AUDIOUNIT_AUDIOGROUPFILEPRESENTER_HPP__ diff --git a/AudioUnit/AudioGroupFilePresenter.mm b/AudioUnit/AudioGroupFilePresenter.mm index 9adba9e..d5e4468 100644 --- a/AudioUnit/AudioGroupFilePresenter.mm +++ b/AudioUnit/AudioGroupFilePresenter.mm @@ -1,7 +1,30 @@ #include "AudioGroupFilePresenter.hpp" #include +#include #import +@implementation AudioGroupDataToken + +- (id)initWithDataCollection:(AudioGroupDataCollection *)collection +{ + self = [super init]; + m_collection = collection; + return self; +} + +@end + +@implementation AudioGroupCollectionToken + +- (id)initWithCollection:(AudioGroupCollection *)collection +{ + self = [super init]; + m_collection = collection; + return self; +} + +@end + @implementation AudioGroupFilePresenter - (NSURL*)presentedItemURL @@ -14,6 +37,138 @@ return m_dataQueue; } +AudioGroupCollection::AudioGroupCollection(NSURL* url) +: m_url(url), m_token([[AudioGroupCollectionToken alloc] initWithCollection:this]) {} + +void AudioGroupCollection::addCollection(std::vector>&& collection) +{ + for (std::pair& pair : collection) + { + NSURL* collectionUrl = [m_url URLByAppendingPathComponent:@(pair.first.c_str())]; + + amuse::IntrusiveAudioGroupData& dataIn = pair.second; + auto search = m_groups.find(pair.first); + if (search == m_groups.end()) + { + search = m_groups.emplace(pair.first, + AudioGroupDataCollection{pair.first, + [collectionUrl URLByAppendingPathComponent:@"proj"], + [collectionUrl URLByAppendingPathComponent:@"pool"], + [collectionUrl URLByAppendingPathComponent:@"sdir"], + [collectionUrl URLByAppendingPathComponent:@"samp"], + [collectionUrl URLByAppendingPathComponent:@"meta"]}).first; + } + + AudioGroupDataCollection& dataCollection = search->second; + dataCollection.m_projData.resize(dataIn.getProjSize()); + memmove(dataCollection.m_projData.data(), dataIn.getProj(), dataIn.getProjSize()); + + dataCollection.m_poolData.resize(dataIn.getPoolSize()); + memmove(dataCollection.m_poolData.data(), dataIn.getPool(), dataIn.getPoolSize()); + + dataCollection.m_sdirData.resize(dataIn.getSdirSize()); + memmove(dataCollection.m_sdirData.data(), dataIn.getSdir(), dataIn.getSdirSize()); + + dataCollection.m_sampData.resize(dataIn.getSampSize()); + memmove(dataCollection.m_sampData.data(), dataIn.getSamp(), dataIn.getSampSize()); + + dataCollection.m_metaData.emplace(dataIn.getDataFormat(), dataIn.getAbsoluteProjOffsets(), true); + } +} + +void AudioGroupCollection::update(AudioGroupFilePresenter* presenter) +{ + NSFileManager* fman = [NSFileManager defaultManager]; + NSArray* contents = + [fman contentsOfDirectoryAtURL:m_url + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants | + NSDirectoryEnumerationSkipsHiddenFiles + error:nil]; + if (!contents) + return; + + for (NSURL* path in contents) + { + NSNumber* isDir; + [path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil]; + + if (isDir.boolValue) + { + auto search = m_groups.find(path.lastPathComponent.UTF8String); + if (search == m_groups.end()) + { + std::string nameStr = path.lastPathComponent.UTF8String; + search = + m_groups.emplace(nameStr, + AudioGroupDataCollection{nameStr, + [path URLByAppendingPathComponent:@"proj"], + [path URLByAppendingPathComponent:@"pool"], + [path URLByAppendingPathComponent:@"sdir"], + [path URLByAppendingPathComponent:@"samp"], + [path URLByAppendingPathComponent:@"meta"]}).first; + search->second._attemptLoad(presenter); + } + } + } +} + +AudioGroupDataCollection::AudioGroupDataCollection(const std::string& name, NSURL* proj, NSURL* pool, + NSURL* sdir, NSURL* samp, NSURL* meta) +: m_name(name), m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), m_meta(meta), + m_token([[AudioGroupDataToken alloc] initWithDataCollection:this]) {} + +bool AudioGroupDataCollection::_attemptLoad(AudioGroupFilePresenter* presenter) +{ + if (!isDataComplete()) + return false; + if (m_metaData && m_loadedProj) + return true; + if (!loadProj(presenter)) + return false; + if (!loadPool(presenter)) + return false; + if (!loadSdir(presenter)) + return false; + if (!loadSamp(presenter)) + return false; + if (!loadMeta(presenter)) + return false; + + switch (m_metaData->fmt) + { + case amuse::DataFormat::GCN: + default: + m_loadedData.emplace(m_projData.data(), m_projData.size(), + m_poolData.data(), m_poolData.size(), + m_sdirData.data(), m_sdirData.size(), + m_sampData.data(), m_sampData.size(), + amuse::GCNDataTag{}); + break; + case amuse::DataFormat::N64: + m_loadedData.emplace(m_projData.data(), m_projData.size(), + m_poolData.data(), m_poolData.size(), + m_sdirData.data(), m_sdirData.size(), + m_sampData.data(), m_sampData.size(), + m_metaData->absOffs, amuse::N64DataTag{}); + break; + case amuse::DataFormat::PC: + m_loadedData.emplace(m_projData.data(), m_projData.size(), + m_poolData.data(), m_poolData.size(), + m_sdirData.data(), m_sdirData.size(), + m_sampData.data(), m_sampData.size(), + m_metaData->absOffs, amuse::PCDataTag{}); + break; + } + + if (m_metaData && m_loadedProj) + { + m_loadedProj.emplace(amuse::AudioGroupProject::CreateAudioGroupProject(*m_loadedData)); + return true; + } + return false; +} + void AudioGroupDataCollection::moveURL(NSURL* oldUrl, NSURL* newUrl) { if (m_proj) @@ -46,7 +201,7 @@ bool AudioGroupDataCollection::loadProj(AudioGroupFilePresenter* presenter) if (!coord) return false; NSError* err; - __block std::unique_ptr& ret = m_projData; + __block std::vector& ret = m_projData; [coord coordinateReadingItemAtURL:m_proj options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err byAccessor:^(NSURL* newUrl) @@ -54,9 +209,11 @@ bool AudioGroupDataCollection::loadProj(AudioGroupFilePresenter* presenter) athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); if (r.hasError()) return; - ret = r.readUBytes(r.length()); + size_t len = r.length(); + ret.resize(len); + r.readUBytesToBuf(ret.data(), len); }]; - return m_projData.operator bool(); + return ret.size(); } bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter) @@ -67,7 +224,7 @@ bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter) if (!coord) return false; NSError* err; - __block std::unique_ptr& ret = m_poolData; + __block std::vector& ret = m_poolData; [coord coordinateReadingItemAtURL:m_pool options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err byAccessor:^(NSURL* newUrl) @@ -75,9 +232,11 @@ bool AudioGroupDataCollection::loadPool(AudioGroupFilePresenter* presenter) athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); if (r.hasError()) return; - ret = r.readUBytes(r.length()); + size_t len = r.length(); + ret.resize(len); + r.readUBytesToBuf(ret.data(), len); }]; - return m_poolData.operator bool(); + return ret.size(); } bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter) @@ -88,7 +247,7 @@ bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter) if (!coord) return false; NSError* err; - __block std::unique_ptr& ret = m_sdirData; + __block std::vector& ret = m_sdirData; [coord coordinateReadingItemAtURL:m_sdir options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err byAccessor:^(NSURL* newUrl) @@ -96,9 +255,11 @@ bool AudioGroupDataCollection::loadSdir(AudioGroupFilePresenter* presenter) athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); if (r.hasError()) return; - ret = r.readUBytes(r.length()); + size_t len = r.length(); + ret.resize(len); + r.readUBytesToBuf(ret.data(), len); }]; - return m_sdirData.operator bool(); + return ret.size(); } bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter) @@ -109,7 +270,7 @@ bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter) if (!coord) return false; NSError* err; - __block std::unique_ptr& ret = m_sampData; + __block std::vector& ret = m_sampData; [coord coordinateReadingItemAtURL:m_samp options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err byAccessor:^(NSURL* newUrl) @@ -117,63 +278,189 @@ bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter) athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); if (r.hasError()) return; - ret = r.readUBytes(r.length()); + size_t len = r.length(); + ret.resize(len); + r.readUBytesToBuf(ret.data(), len); }]; - return m_sampData.operator bool(); + return ret.size(); +} + +bool AudioGroupDataCollection::loadMeta(AudioGroupFilePresenter* presenter) +{ + if (!m_meta) + return false; + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:presenter]; + if (!coord) + return false; + NSError* err; + __block std::experimental::optional& ret = m_metaData; + [coord coordinateReadingItemAtURL:m_meta + options:NSFileCoordinatorReadingResolvesSymbolicLink error:&err + byAccessor:^(NSURL* newUrl) + { + athena::io::FileReader r([[newUrl path] UTF8String], 1024 * 32, false); + if (r.hasError()) + return; + ret.emplace(r); + }]; + return ret.operator bool(); } - (void)presentedSubitemDidAppearAtURL:(NSURL*)url { - NSURL* dir = nil; if ([url.lastPathComponent isEqualToString:@"proj"] || [url.lastPathComponent isEqualToString:@"pool"] || [url.lastPathComponent isEqualToString:@"sdir"] || [url.lastPathComponent isEqualToString:@"samp"]) - dir = url.baseURL; - - auto search = m_audioGroupCollections.find(dir.lastPathComponent.UTF8String); - if (search == m_audioGroupCollections.end()) - { - search = - m_audioGroupCollections.emplace(dir.lastPathComponent.UTF8String, - AudioGroupDataCollection{ - [dir URLByAppendingPathComponent:@"proj"], - [dir URLByAppendingPathComponent:@"pool"], - [dir URLByAppendingPathComponent:@"sdir"], - [dir URLByAppendingPathComponent:@"samp"]}).first; - } + [self update]; } - (void)presentedSubitemAtURL:(NSURL*)oldUrl didMoveToURL:(NSURL*)newUrl { - for (auto it = m_audioGroupCollections.begin() ; it != m_audioGroupCollections.end() ; ++it) + for (auto& pair : m_audioGroupCollections) { - std::pair& pair = *it; - pair.second.moveURL(oldUrl, newUrl); + for (auto& pair2 : pair.second.m_groups) + { + pair2.second.moveURL(oldUrl, newUrl); + } } } - (NSInteger)outlineView:(NSOutlineView*)outlineView numberOfChildrenOfItem:(nullable id)item { + lastOutlineView = outlineView; if (!item) return m_audioGroupCollections.size(); - return 0; + + AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection; + return collection.m_groups.size(); } - (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(nullable id)item { if (!item) { - + auto search = m_iteratorTracker->seekToIndex(index); + if (search == m_audioGroupCollections.end()) + return nil; + return search->second.m_token; } - return nil; + + AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection; + auto search = collection.m_iteratorTracker->seekToIndex(index); + if (search == collection.m_groups.end()) + return nil; + return search->second.m_token; } - (BOOL)outlineView:(NSOutlineView*)outlineView isItemExpandable:(id)item { + if ([item isKindOfClass:[AudioGroupCollectionToken class]]) + return YES; return NO; } +- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item +{ + if ([item isKindOfClass:[AudioGroupCollectionToken class]]) + { + AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection; + if ([tableColumn.identifier isEqualToString:@"CollectionColumn"]) + return [NSNumber numberWithBool:true]; + else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"]) + return [NSString stringWithFormat:@"%" PRISize " groups", collection.m_groups.size()]; + } + else if ([item isKindOfClass:[AudioGroupDataToken class]]) + { + AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection; + if ([tableColumn.identifier isEqualToString:@"CollectionColumn"]) + return [NSNumber numberWithBool:data.m_metaData->active]; + else if ([tableColumn.identifier isEqualToString:@"DetailsColumn"]) + { + if (!data.m_loadedProj) + return @""; + return [NSString stringWithFormat:@"%zu SongGroups, %zu SFXGroups", + data.m_loadedProj->songGroups().size(), data.m_loadedProj->sfxGroups().size()]; + } + } + + return nil; +} + +- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(nonnull id)cell forTableColumn:(nullable NSTableColumn *)tableColumn item:(nonnull id)item +{ + if ([item isKindOfClass:[AudioGroupCollectionToken class]]) + { + AudioGroupCollection& collection = *((AudioGroupCollectionToken*)item)->m_collection; + if ([tableColumn.identifier isEqualToString:@"CollectionColumn"]) + ((NSButtonCell*)cell).title = collection.m_url.lastPathComponent; + } + else if ([item isKindOfClass:[AudioGroupDataToken class]]) + { + AudioGroupDataCollection& data = *((AudioGroupDataToken*)item)->m_collection; + if ([tableColumn.identifier isEqualToString:@"CollectionColumn"]) + ((NSButtonCell*)cell).title = @(data.m_name.c_str()); + } +} + +- (BOOL)addCollectionName:(std::string&&)name items:(std::vector>&&)collection +{ + NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self]; + if (!coord) + return false; + + NSURL* dir = [m_groupURL URLByAppendingPathComponent:@(name.c_str())]; + __block AudioGroupCollection& insert = m_audioGroupCollections.emplace(name, dir).first->second; + insert.addCollection(std::move(collection)); + + [coord coordinateWritingItemAtURL:m_groupURL options:0 error:nil + byAccessor:^(NSURL* newUrl) + { + for (std::pair& pair : insert.m_groups) + { + NSURL* collectionUrl = [insert.m_url URLByAppendingPathComponent:@(pair.first.c_str())]; + [[NSFileManager defaultManager] createDirectoryAtURL:collectionUrl withIntermediateDirectories:YES attributes:nil error:nil]; + + FILE* fp = fopen(pair.second.m_proj.path.UTF8String, "wb"); + if (fp) + { + fwrite(pair.second.m_projData.data(), 1, pair.second.m_projData.size(), fp); + fclose(fp); + } + + fp = fopen(pair.second.m_pool.path.UTF8String, "wb"); + if (fp) + { + fwrite(pair.second.m_poolData.data(), 1, pair.second.m_poolData.size(), fp); + fclose(fp); + } + + fp = fopen(pair.second.m_sdir.path.UTF8String, "wb"); + if (fp) + { + fwrite(pair.second.m_sdirData.data(), 1, pair.second.m_sdirData.size(), fp); + fclose(fp); + } + + fp = fopen(pair.second.m_samp.path.UTF8String, "wb"); + if (fp) + { + fwrite(pair.second.m_sampData.data(), 1, pair.second.m_sampData.size(), fp); + fclose(fp); + } + + fp = fopen(pair.second.m_meta.path.UTF8String, "wb"); + if (fp) + { + fwrite(&*pair.second.m_metaData, 1, sizeof(*pair.second.m_metaData), fp); + fclose(fp); + } + } + }]; + + return true; +} + - (void)update { NSFileCoordinator* coord = [[NSFileCoordinator alloc] initWithFilePresenter:self]; @@ -181,41 +468,47 @@ bool AudioGroupDataCollection::loadSamp(AudioGroupFilePresenter* presenter) return; NSError* coordErr; __block NSError* managerErr; - __block std::map& theMap = m_audioGroupCollections; + __block std::map& theMap = m_audioGroupCollections; + __block AudioGroupFilePresenter* presenter = self; [coord coordinateReadingItemAtURL:m_groupURL options:NSFileCoordinatorReadingResolvesSymbolicLink error:&coordErr byAccessor:^(NSURL* newUrl) - { - NSFileManager* fman = [NSFileManager defaultManager]; - NSArray* contents = - [fman contentsOfDirectoryAtURL:newUrl - includingPropertiesForKeys:@[NSURLIsDirectoryKey] - options:NSDirectoryEnumerationSkipsSubdirectoryDescendants | - NSDirectoryEnumerationSkipsHiddenFiles - error:&managerErr]; - if (!contents) - return; + { + NSFileManager* fman = [NSFileManager defaultManager]; + NSArray* contents = + [fman contentsOfDirectoryAtURL:newUrl + includingPropertiesForKeys:@[NSURLIsDirectoryKey] + options:NSDirectoryEnumerationSkipsSubdirectoryDescendants | + NSDirectoryEnumerationSkipsHiddenFiles + error:&managerErr]; + if (!contents) + return; - for (NSURL* path in contents) - { - NSNumber* isDir; - [path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil]; - - if (isDir.boolValue) - { - auto search = theMap.find(path.lastPathComponent.UTF8String); - if (search == theMap.end()) - { - search = - theMap.emplace(path.lastPathComponent.UTF8String, - AudioGroupDataCollection{ - [path URLByAppendingPathComponent:@"proj"], - [path URLByAppendingPathComponent:@"pool"], - [path URLByAppendingPathComponent:@"sdir"], - [path URLByAppendingPathComponent:@"samp"]}).first; - } - } - } - }]; + for (NSURL* path in contents) + { + NSNumber* isDir; + [path getResourceValue:&isDir forKey:NSURLIsDirectoryKey error:nil]; + + if (isDir.boolValue) + { + auto search = theMap.find(path.lastPathComponent.UTF8String); + if (search == theMap.end()) + { + search = theMap.emplace(path.lastPathComponent.UTF8String, path).first; + search->second.update(presenter); + } + } + } + }]; + + [self resetIterators]; +} + +- (void)resetIterators +{ + m_iteratorTracker.emplace(m_audioGroupCollections.begin(), m_audioGroupCollections.end()); + for (auto& pair : m_audioGroupCollections) + pair.second.m_iteratorTracker.emplace(pair.second.m_groups.begin(), pair.second.m_groups.end()); + [lastOutlineView reloadItem:nil reloadChildren:YES]; } - (id)init diff --git a/AudioUnit/CMakeLists.txt b/AudioUnit/CMakeLists.txt index 13b4e71..ea1fea7 100644 --- a/AudioUnit/CMakeLists.txt +++ b/AudioUnit/CMakeLists.txt @@ -57,7 +57,7 @@ if (APPLE AND (NOT CMAKE_OSX_DEPLOYMENT_TARGET OR CMAKE_OSX_DEPLOYMENT_TARGET VE AmuseContainingApp.mm AudioGroupFilePresenter.mm PROPERTIES COMPILE_FLAGS -fobjc-arc) target_link_libraries(amuse-au-container amuse boo soxr ${AUDIOUNIT_LIBRARY} ${COREAUDIOKIT_LIBRARY} - ${AVFOUNDATION_LIBRARY} ${BOO_SYS_LIBS} logvisor athena-core) + ${AVFOUNDATION_LIBRARY} ${ZLIB_LIBRARIES} ${BOO_SYS_LIBS} logvisor athena-core) set(APPLE_BUNDLE_ID "io.github.axiodl.Amuse") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/AmuseContainer.entitlements.in diff --git a/include/amuse/AudioGroupData.hpp b/include/amuse/AudioGroupData.hpp index 4328d70..9a6d2ad 100644 --- a/include/amuse/AudioGroupData.hpp +++ b/include/amuse/AudioGroupData.hpp @@ -12,35 +12,70 @@ class AudioGroupData friend class Engine; protected: unsigned char* m_proj; + size_t m_projSz; unsigned char* m_pool; + size_t m_poolSz; unsigned char* m_sdir; + size_t m_sdirSz; unsigned char* m_samp; + size_t m_sampSz; + DataFormat m_fmt; bool m_absOffs; - AudioGroupData(unsigned char* proj, unsigned char* pool, - unsigned char* sdir, unsigned char* samp, + AudioGroupData(unsigned char* proj, size_t projSz, + unsigned char* pool, size_t poolSz, + unsigned char* sdir, size_t sdirSz, + unsigned char* samp, size_t sampSz, DataFormat fmt, bool absOffs) - : m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), + : m_proj(proj), m_projSz(projSz), + m_pool(pool), m_poolSz(poolSz), + m_sdir(sdir), m_sdirSz(sdirSz), + m_samp(samp), m_sampSz(sampSz), m_fmt(fmt), m_absOffs(absOffs) {} public: - AudioGroupData(unsigned char* proj, unsigned char* pool, - unsigned char* sdir, unsigned char* samp, GCNDataTag) - : m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), + AudioGroupData(unsigned char* proj, size_t projSz, + unsigned char* pool, size_t poolSz, + unsigned char* sdir, size_t sdirSz, + unsigned char* samp, size_t sampSz, GCNDataTag) + : m_proj(proj), m_projSz(projSz), + m_pool(pool), m_poolSz(poolSz), + m_sdir(sdir), m_sdirSz(sdirSz), + m_samp(samp), m_sampSz(sampSz), m_fmt(DataFormat::GCN), m_absOffs(true) {} - AudioGroupData(unsigned char* proj, unsigned char* pool, - unsigned char* sdir, unsigned char* samp, bool absOffs, N64DataTag) - : m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), + AudioGroupData(unsigned char* proj, size_t projSz, + unsigned char* pool, size_t poolSz, + unsigned char* sdir, size_t sdirSz, + unsigned char* samp, size_t sampSz, bool absOffs, N64DataTag) + : m_proj(proj), m_projSz(projSz), + m_pool(pool), m_poolSz(poolSz), + m_sdir(sdir), m_sdirSz(sdirSz), + m_samp(samp), m_sampSz(sampSz), m_fmt(DataFormat::N64), m_absOffs(absOffs) {} - AudioGroupData(unsigned char* proj, unsigned char* pool, - unsigned char* sdir, unsigned char* samp, bool absOffs, PCDataTag) - : m_proj(proj), m_pool(pool), m_sdir(sdir), m_samp(samp), + AudioGroupData(unsigned char* proj, size_t projSz, + unsigned char* pool, size_t poolSz, + unsigned char* sdir, size_t sdirSz, + unsigned char* samp, size_t sampSz, bool absOffs, PCDataTag) + : m_proj(proj), m_projSz(projSz), + m_pool(pool), m_poolSz(poolSz), + m_sdir(sdir), m_sdirSz(sdirSz), + m_samp(samp), m_sampSz(sampSz), m_fmt(DataFormat::PC), m_absOffs(absOffs) {} const unsigned char* getProj() const {return m_proj;} const unsigned char* getPool() const {return m_pool;} const unsigned char* getSdir() const {return m_sdir;} const unsigned char* getSamp() const {return m_samp;} + + unsigned char* getProj() {return m_proj;} + unsigned char* getPool() {return m_pool;} + unsigned char* getSdir() {return m_sdir;} + unsigned char* getSamp() {return m_samp;} + + size_t getProjSize() const {return m_projSz;} + size_t getPoolSize() const {return m_poolSz;} + size_t getSdirSize() const {return m_sdirSz;} + size_t getSampSize() const {return m_sampSz;} operator bool() const { @@ -64,6 +99,8 @@ public: IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other); IntrusiveAudioGroupData& operator=(IntrusiveAudioGroupData&& other); + + void dangleOwnership() {m_owns = false;} }; } diff --git a/include/amuse/ContainerRegistry.hpp b/include/amuse/ContainerRegistry.hpp index ca670f8..a8fb8b5 100644 --- a/include/amuse/ContainerRegistry.hpp +++ b/include/amuse/ContainerRegistry.hpp @@ -37,6 +37,7 @@ public: static const char* TypeToName(Type tp); static Type DetectContainerType(const char* path); static std::vector> LoadContainer(const char* path); + static std::vector> LoadContainer(const char* path, Type& typeOut); static std::vector> LoadSongs(const char* path); }; diff --git a/lib/AudioGroupData.cpp b/lib/AudioGroupData.cpp index a68a241..3b2083e 100644 --- a/lib/AudioGroupData.cpp +++ b/lib/AudioGroupData.cpp @@ -15,7 +15,9 @@ IntrusiveAudioGroupData::~IntrusiveAudioGroupData() } IntrusiveAudioGroupData::IntrusiveAudioGroupData(IntrusiveAudioGroupData&& other) -: AudioGroupData(other.m_proj, other.m_pool, other.m_sdir, other.m_samp, other.m_fmt, other.m_absOffs) +: AudioGroupData(other.m_proj, other.m_projSz, other.m_pool, other.m_poolSz, + other.m_sdir, other.m_sdirSz, other.m_samp, other.m_sampSz, + other.m_fmt, other.m_absOffs) { m_owns = other.m_owns; other.m_owns = false; diff --git a/lib/ContainerRegistry.cpp b/lib/ContainerRegistry.cpp index 20141d6..6ecf036 100644 --- a/lib/ContainerRegistry.cpp +++ b/lib/ContainerRegistry.cpp @@ -119,7 +119,8 @@ static bool IsSongExtension(const char* path, const char*& dotOut) static bool ValidateMP1(FILE* fp) { - FileLength(fp); + if (FileLength(fp) > 40 * 1024 * 1024) + return false; uint32_t magic; fread(&magic, 1, 4, fp); @@ -228,29 +229,34 @@ static std::vector> LoadMP1(FILE ReadString(fp); std::string name = ReadString(fp); - uint32_t len; - fread(&len, 1, 4, fp); - len = SBig(len); - std::unique_ptr pool(new uint8_t[len]); - fread(pool.get(), 1, len, fp); + uint32_t poolLen; + fread(&poolLen, 1, 4, fp); + poolLen = SBig(poolLen); + std::unique_ptr pool(new uint8_t[poolLen]); + fread(pool.get(), 1, poolLen, fp); - fread(&len, 1, 4, fp); - len = SBig(len); - std::unique_ptr proj(new uint8_t[len]); - fread(proj.get(), 1, len, fp); + uint32_t projLen; + fread(&projLen, 1, 4, fp); + projLen = SBig(projLen); + std::unique_ptr proj(new uint8_t[projLen]); + fread(proj.get(), 1, projLen, fp); - fread(&len, 1, 4, fp); - len = SBig(len); - std::unique_ptr samp(new uint8_t[len]); - fread(samp.get(), 1, len, fp); + uint32_t sampLen; + fread(&sampLen, 1, 4, fp); + sampLen = SBig(sampLen); + std::unique_ptr samp(new uint8_t[sampLen]); + fread(samp.get(), 1, sampLen, fp); - fread(&len, 1, 4, fp); - len = SBig(len); - std::unique_ptr sdir(new uint8_t[len]); - fread(sdir.get(), 1, len, fp); + uint32_t sdirLen; + fread(&sdirLen, 1, 4, fp); + sdirLen = SBig(sdirLen); + std::unique_ptr sdir(new uint8_t[sdirLen]); + fread(sdir.get(), 1, sdirLen, fp); - ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), GCNDataTag{}}); + ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), projLen, + pool.release(), poolLen, + sdir.release(), sdirLen, + samp.release(), sampLen, GCNDataTag{}}); } } FSeek(fp, origPos, SEEK_SET); @@ -263,7 +269,8 @@ static std::vector> LoadMP1(FILE static bool ValidateMP1Songs(FILE* fp) { - FileLength(fp); + if (FileLength(fp) > 40 * 1024 * 1024) + return false; uint32_t magic; fread(&magic, 1, 4, fp); @@ -404,7 +411,8 @@ static std::vector> LoadMP1S static bool ValidateMP2(FILE* fp) { - FileLength(fp); + if (FileLength(fp) > 40 * 1024 * 1024) + return false; uint32_t magic; fread(&magic, 1, 4, fp); @@ -541,8 +549,10 @@ static std::vector> LoadMP2(FILE std::unique_ptr samp(new uint8_t[sampSz]); fread(samp.get(), 1, sampSz, fp); - ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), GCNDataTag{}}); + ret.emplace_back(std::move(name), IntrusiveAudioGroupData{proj.release(), projSz, + pool.release(), poolSz, + sdir.release(), sdirSz, + samp.release(), sampSz, GCNDataTag{}}); } } FSeek(fp, origPos, SEEK_SET); @@ -589,6 +599,8 @@ static void SwapN64Rom32(void* data, size_t size) static bool ValidateRS1PC(FILE* fp) { size_t endPos = FileLength(fp); + if (endPos > 100 * 1024 * 1024) + return false; uint32_t fstOff; uint32_t fstSz; @@ -640,41 +652,49 @@ static std::vector> LoadRS1PC(FI fread(entries.get(), fstSz, 1, fp); std::unique_ptr proj; + size_t projSz = 0; std::unique_ptr pool; + size_t poolSz = 0; std::unique_ptr sdir; + size_t sdirSz = 0; std::unique_ptr samp; + size_t sampSz = 0; for (uint32_t i=0 ; i> LoadRS1N64(F const RS1FSTEntry* lastEnt = reinterpret_cast(dataSeg + fstEnd); std::unique_ptr proj; + size_t projSz = 0; std::unique_ptr pool; + size_t poolSz = 0; std::unique_ptr sdir; + size_t sdirSz = 0; std::unique_ptr samp; + size_t sampSz = 0; for (; entry != lastEnt ; ++entry) { @@ -786,6 +810,7 @@ static std::vector> LoadRS1N64(F uLongf outSz = ent.decompSz; uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + projSz = ent.decompSz; } else if (!strncmp("pool_SND", ent.name, 16)) { @@ -800,6 +825,7 @@ static std::vector> LoadRS1N64(F uLongf outSz = ent.decompSz; uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + poolSz = ent.decompSz; } else if (!strncmp("sdir_SND", ent.name, 16)) { @@ -814,6 +840,7 @@ static std::vector> LoadRS1N64(F uLongf outSz = ent.decompSz; uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + sdirSz = ent.decompSz; } else if (!strncmp("samp_SND", ent.name, 16)) { @@ -828,11 +855,12 @@ static std::vector> LoadRS1N64(F uLongf outSz = ent.decompSz; uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + sampSz = ent.decompSz; } } - ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), + ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz, + sdir.release(), sdirSz, samp.release(), sampSz, false, N64DataTag{}}); } @@ -842,7 +870,9 @@ static std::vector> LoadRS1N64(F static bool ValidateBFNPC(FILE* fp) { size_t endPos = FileLength(fp); - + if (endPos > 100 * 1024 * 1024) + return false; + uint32_t fstOff; uint32_t fstSz; if (fread(&fstOff, 1, 4, fp) == 4 && fread(&fstSz, 1, 4, fp) == 4) @@ -893,9 +923,13 @@ static std::vector> LoadBFNPC(FI fread(entries.get(), fstSz, 1, fp); std::unique_ptr proj; + size_t projSz = 0; std::unique_ptr pool; + size_t poolSz = 0; std::unique_ptr sdir; + size_t sdirSz = 0; std::unique_ptr samp; + size_t sampSz = 0; for (uint32_t i=0 ; i> LoadBFNPC(FI proj.reset(new uint8_t[entry.decompSz]); FSeek(fp, entry.offset, SEEK_SET); fread(proj.get(), 1, entry.decompSz, fp); + projSz = entry.decompSz; } else if (!strncmp("pool", entry.name, 16)) { pool.reset(new uint8_t[entry.decompSz]); FSeek(fp, entry.offset, SEEK_SET); fread(pool.get(), 1, entry.decompSz, fp); + poolSz = entry.decompSz; } else if (!strncmp("sdir", entry.name, 16)) { sdir.reset(new uint8_t[entry.decompSz]); FSeek(fp, entry.offset, SEEK_SET); fread(sdir.get(), 1, entry.decompSz, fp); + sdirSz = entry.decompSz; } else if (!strncmp("samp", entry.name, 16)) { samp.reset(new uint8_t[entry.decompSz]); FSeek(fp, entry.offset, SEEK_SET); fread(samp.get(), 1, entry.decompSz, fp); + sampSz = entry.decompSz; } } - ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), + ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz, + sdir.release(), sdirSz, samp.release(), sampSz, true, PCDataTag{}}); } } @@ -1017,9 +1055,13 @@ static std::vector> LoadBFNN64(F const RS1FSTEntry* lastEnt = reinterpret_cast(dataSeg + fstEnd); std::unique_ptr proj; + size_t projSz = 0; std::unique_ptr pool; + size_t poolSz = 0; std::unique_ptr sdir; + size_t sdirSz = 0; std::unique_ptr samp; + size_t sampSz = 0; for (; entry != lastEnt ; ++entry) { @@ -1039,6 +1081,7 @@ static std::vector> LoadBFNN64(F uLongf outSz = ent.decompSz; uncompress(proj.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + projSz = ent.decompSz; } else if (!strncmp("pool", ent.name, 16)) { @@ -1053,6 +1096,7 @@ static std::vector> LoadBFNN64(F uLongf outSz = ent.decompSz; uncompress(pool.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + poolSz = ent.decompSz; } else if (!strncmp("sdir", ent.name, 16)) { @@ -1067,6 +1111,7 @@ static std::vector> LoadBFNN64(F uLongf outSz = ent.decompSz; uncompress(sdir.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + sdirSz = ent.decompSz; } else if (!strncmp("samp", ent.name, 16)) { @@ -1081,11 +1126,12 @@ static std::vector> LoadBFNN64(F uLongf outSz = ent.decompSz; uncompress(samp.get(), &outSz, dataSeg + ent.offset, ent.compSz); } + sampSz = ent.decompSz; } } - ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), + ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projSz, pool.release(), poolSz, + sdir.release(), sdirSz, samp.release(), sampSz, true, N64DataTag{}}); } @@ -1164,7 +1210,9 @@ struct RS23SONHead static bool ValidateRS2(FILE* fp) { size_t endPos = FileLength(fp); - + if (endPos > 600 * 1024 * 1024) + return false; + uint64_t fstOff; fread(&fstOff, 1, 8, fp); fstOff = SBig(fstOff); @@ -1241,8 +1289,8 @@ static std::vector> LoadRS2(FILE char name[128]; snprintf(name, 128, "GroupFile%u", j); - ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), GCNDataTag{}}); + ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), head.projLen, pool.release(), head.poolLen, + sdir.release(), head.sdirLen, samp.release(), head.sampLen, GCNDataTag{}}); } break; @@ -1334,7 +1382,9 @@ struct RS3FSTEntry static bool ValidateRS3(FILE* fp) { size_t endPos = FileLength(fp); - + if (endPos > 600 * 1024 * 1024) + return false; + uint64_t fstOff; fread(&fstOff, 1, 8, fp); fstOff = SBig(fstOff); @@ -1409,8 +1459,8 @@ static std::vector> LoadRS3(FILE char name[128]; snprintf(name, 128, "GroupFile%u", j); - ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), GCNDataTag{}}); + ret.emplace_back(name, IntrusiveAudioGroupData{proj.release(), head.projLen, pool.release(), head.poolLen, + sdir.release(), head.sdirLen, samp.release(), head.sampLen, GCNDataTag{}}); } break; @@ -1538,11 +1588,19 @@ ContainerRegistry::Type ContainerRegistry::DetectContainerType(const char* path) return Type::Invalid; } - + std::vector> ContainerRegistry::LoadContainer(const char* path) +{ + Type typeOut; + return LoadContainer(path, typeOut); +}; + +std::vector> +ContainerRegistry::LoadContainer(const char* path, Type& typeOut) { FILE* fp; + typeOut = Type::Invalid; /* See if provided file is one of four raw chunks */ const char* dot = nullptr; @@ -1603,49 +1661,50 @@ ContainerRegistry::LoadContainer(const char* path) fclose(fp); fp = fopen(projPath, "rb"); - size_t fLen = FileLength(fp); - if (!fLen) + size_t projLen = FileLength(fp); + if (!projLen) return ret; - std::unique_ptr proj(new uint8_t[fLen]); - fread(proj.get(), 1, fLen, fp); + std::unique_ptr proj(new uint8_t[projLen]); + fread(proj.get(), 1, projLen, fp); fp = fopen(poolPath, "rb"); - fLen = FileLength(fp); - if (!fLen) + size_t poolLen = FileLength(fp); + if (!poolLen) return ret; - std::unique_ptr pool(new uint8_t[fLen]); - fread(pool.get(), 1, fLen, fp); + std::unique_ptr pool(new uint8_t[poolLen]); + fread(pool.get(), 1, poolLen, fp); fp = fopen(sdirPath, "rb"); - fLen = FileLength(fp); - if (!fLen) + size_t sdirLen = FileLength(fp); + if (!sdirLen) return ret; - std::unique_ptr sdir(new uint8_t[fLen]); - fread(sdir.get(), 1, fLen, fp); + std::unique_ptr sdir(new uint8_t[sdirLen]); + fread(sdir.get(), 1, sdirLen, fp); fp = fopen(sampPath, "rb"); - fLen = FileLength(fp); - if (!fLen) + size_t sampLen = FileLength(fp); + if (!sampPath) return ret; - std::unique_ptr samp(new uint8_t[fLen]); - fread(samp.get(), 1, fLen, fp); + std::unique_ptr samp(new uint8_t[sampLen]); + fread(samp.get(), 1, sampLen, fp); fclose(fp); /* SDIR-based format detection */ if (*reinterpret_cast(sdir.get() + 8) == 0x0) - ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), + ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, + sdir.release(), sdirLen, samp.release(), sampLen, GCNDataTag{}}); else if (sdir[9] == 0x0) - ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), + ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, + sdir.release(), sdirLen, samp.release(), sampLen, false, N64DataTag{}}); else - ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), pool.release(), - sdir.release(), samp.release(), + ret.emplace_back("Group", IntrusiveAudioGroupData{proj.release(), projLen, pool.release(), poolLen, + sdir.release(), sdirLen, samp.release(), sampLen, false, PCDataTag{}}); + typeOut = Type::Raw4; return ret; } @@ -1657,6 +1716,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadMP1(fp); fclose(fp); + typeOut = Type::MetroidPrime; return ret; } @@ -1664,6 +1724,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadMP2(fp); fclose(fp); + typeOut = Type::MetroidPrime2; return ret; } @@ -1671,6 +1732,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadRS1PC(fp); fclose(fp); + typeOut = Type::RogueSquadronPC; return ret; } @@ -1678,6 +1740,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadRS1N64(fp); fclose(fp); + typeOut = Type::RogueSquadronN64; return ret; } @@ -1685,6 +1748,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadBFNPC(fp); fclose(fp); + typeOut = Type::BattleForNabooPC; return ret; } @@ -1692,6 +1756,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadBFNN64(fp); fclose(fp); + typeOut = Type::BattleForNabooN64; return ret; } @@ -1699,6 +1764,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadRS2(fp); fclose(fp); + typeOut = Type::RogueSquadron2; return ret; } @@ -1706,6 +1772,7 @@ ContainerRegistry::LoadContainer(const char* path) { auto ret = LoadRS3(fp); fclose(fp); + typeOut = Type::RogueSquadron3; return ret; }