Formats::Chiptune::Container::Ptr Parse(const Binary::Container& rawData, Builder& target) { if (!FastCheck(rawData)) { return Formats::Chiptune::Container::Ptr(); } const Binary::TypedContainer& data(rawData); const Header& header = *data.GetField<Header>(0); //workaround for some emulators const std::size_t offset = (header.Version == INT_BEGIN) ? offsetof(Header, Version) : sizeof(header); std::size_t restSize = rawData.Size() - offset; const uint8_t* bdata = data.GetField<uint8_t>(offset); //detect as much chunks as possible, in despite of real format issues while (restSize) { const uint_t reg = *bdata; ++bdata; --restSize; if (INT_BEGIN == reg) { target.AddChunks(1); } else if (INT_SKIP == reg) { if (restSize < 1) { ++restSize;//put byte back break; } target.AddChunks(4 * *bdata); ++bdata; --restSize; } else if (MUS_END == reg) { break; } else if (reg <= 15) //register { if (restSize < 1) { ++restSize;//put byte back break; } target.SetRegister(reg, *bdata); ++bdata; --restSize; } else { ++restSize;//put byte back break; } } const std::size_t usedSize = rawData.Size() - restSize; const Binary::Container::Ptr subData = rawData.GetSubcontainer(0, usedSize); return CreateCalculatingCrcContainer(subData, offset, usedSize - offset); }
Archived::Container::Ptr ParseArchive(const Packed::Decoder& decoder, const Binary::Container& data) { const TRDos::CatalogueBuilder::Ptr builder = TRDos::CatalogueBuilder::CreateGeneric(); const std::size_t archSize = data.Size(); std::size_t rawOffset = 0; for (std::size_t flatOffset = 0; rawOffset < archSize;) { const Binary::Container::Ptr rawData = data.GetSubcontainer(rawOffset, archSize - rawOffset); const Formats::Packed::Container::Ptr fileData = decoder.Decode(*rawData); if (!fileData) { break; } const String fileName = ExtractFileName(rawData->Start()); const std::size_t fileSize = fileData->Size(); const std::size_t usedSize = fileData->PackedSize(); const TRDos::File::Ptr file = TRDos::File::Create(fileData, fileName, flatOffset, fileSize); builder->AddFile(file); rawOffset += usedSize; flatOffset += fileSize; } if (rawOffset) { builder->SetRawData(data.GetSubcontainer(0, rawOffset)); return builder->GetResult(); } else { return Archived::Container::Ptr(); } }
bool FastCheck(const Binary::Container& rawData) { if (rawData.Size() < MIN_SIZE) { return false; } const SignatureType& sign = *static_cast<const SignatureType*>(rawData.Start()); return sign == SIGNATURE; }
std::size_t Parse(const Binary::Container& rawData, ImageVisitor& visitor) { SourceStream stream(rawData); try { const RawHeader& header = stream.Get<RawHeader>(); const uint_t id = fromLE(header.ID); Require(id == ID_OLD || id == ID_NEW); Require(header.Sequence == 0); Require(Math::InRange<uint_t>(header.Sides, MIN_SIDES_COUNT, MAX_SIDES_COUNT)); if (header.HasComment()) { const RawComment& comment = stream.Get<RawComment>(); if (const std::size_t size = fromLE(comment.Size)) { stream.GetData(size); } } const bool compressedData = id == ID_NEW; const bool newCompression = header.Version > 20; if (compressedData) { if (!newCompression) { Dbg("Old compression is not supported."); return 0; } const std::size_t packedSize = rawData.Size() - sizeof(header); const Binary::Container::Ptr packed = rawData.GetSubcontainer(sizeof(header), packedSize); if (const Formats::Packed::Container::Ptr fullDecoded = Formats::Packed::Lha::DecodeRawDataAtLeast(*packed, COMPRESSION_ALGORITHM, MAX_IMAGE_SIZE)) { SourceStream subStream(*fullDecoded); ParseSectors(subStream, visitor); const std::size_t usedInPacked = subStream.GetOffset(); Dbg("Used %1% bytes in packed stream", usedInPacked); if (const Formats::Packed::Container::Ptr decoded = Formats::Packed::Lha::DecodeRawDataAtLeast(*packed, COMPRESSION_ALGORITHM, usedInPacked)) { const std::size_t usedSize = decoded->PackedSize(); return sizeof(header) + usedSize; } } Dbg("Failed to decode lha stream"); return 0; } else { ParseSectors(stream, visitor); } return stream.GetOffset(); } catch (const std::exception&) { return 0; } }
Formats::Chiptune::Container::Ptr Decode(const Binary::Container& rawData) const override { if (!Format->Match(rawData)) { return Formats::Chiptune::Container::Ptr(); } const std::size_t realSize = std::min(rawData.Size(), MAX_SIZE); const Binary::Container::Ptr data = rawData.GetSubcontainer(0, realSize); return CreateCalculatingCrcContainer(data, 0, realSize); }
bool FastCheck(const Binary::Container& rawData) { if (rawData.Size() <= sizeof(Header)) { return false; } const Header* const header = static_cast<const Header*>(rawData.Start()); return 0 == std::memcmp(header->Sign, SIGNATURE, sizeof(SIGNATURE)) && MARKER == header->Marker; }
virtual Container::Ptr Decode(const Binary::Container& rawData) const { const void* const data = rawData.Start(); const std::size_t availSize = rawData.Size(); const FullDiskImage::Container container(data, availSize); if (!container.FastCheck()) { return Container::Ptr(); } FullDiskImage::Decoder decoder(container); return CreatePackedContainer(decoder.GetResult(), decoder.GetUsedSize()); }
virtual Container::Ptr Decode(const Binary::Container& rawData) const { if (!Depacker->Match(rawData)) { return Container::Ptr(); } const MSPack::Container container(rawData.Start(), rawData.Size()); if (!container.FastCheck()) { return Container::Ptr(); } MSPack::DataDecoder decoder(container); return CreatePackedContainer(decoder.GetResult(), container.GetUsedSize()); }
virtual Container::Ptr Decode(const Binary::Container& rawData) const { if (!Player->Match(rawData)) { return Container::Ptr(); } const Binary::TypedContainer typedData(rawData); const std::size_t availSize = rawData.Size(); const std::size_t playerSize = CompiledPT24::PLAYER_SIZE; const CompiledPT24::Player& rawPlayer = *typedData.GetField<CompiledPT24::Player>(0); const uint_t dataAddr = fromLE(rawPlayer.DataAddr); if (dataAddr < playerSize) { Dbg("Invalid compile addr"); return Container::Ptr(); } const CompiledPT24::RawHeader& rawHeader = *typedData.GetField<CompiledPT24::RawHeader>(playerSize); const uint_t patternsCount = CompiledPT24::GetPatternsCount(rawHeader, availSize - playerSize); if (!patternsCount) { Dbg("Invalid patterns count"); return Container::Ptr(); } const uint_t compileAddr = dataAddr - playerSize; Dbg("Detected player compiled at %1% (#%1$04x) with %2% patterns", compileAddr, patternsCount); const std::size_t modDataSize = std::min(CompiledPT24::MAX_MODULE_SIZE, availSize - playerSize); const Binary::Container::Ptr modData = rawData.GetSubcontainer(playerSize, modDataSize); const Formats::Chiptune::PatchedDataBuilder::Ptr builder = Formats::Chiptune::PatchedDataBuilder::Create(*modData); //fix samples/ornaments offsets for (uint_t idx = offsetof(CompiledPT24::RawHeader, SamplesOffsets); idx != offsetof(CompiledPT24::RawHeader, PatternsOffset); idx += 2) { builder->FixLEWord(idx, -int_t(dataAddr)); } //fix patterns offsets for (uint_t idx = fromLE(rawHeader.PatternsOffset), lim = idx + 6 * patternsCount; idx != lim; idx += 2) { builder->FixLEWord(idx, -int_t(dataAddr)); } const Binary::Container::Ptr fixedModule = builder->GetResult(); if (Formats::Chiptune::Container::Ptr fixedParsed = Decoder->Decode(*fixedModule)) { return CreatePackedContainer(fixedParsed, playerSize + fixedParsed->Size()); } Dbg("Failed to parse fixed module"); return Container::Ptr(); }
Module::Holder::Ptr CreateModule(const Parameters::Accessor& params, const Binary::Container& rawData, Parameters::Container::Ptr properties) const override { try { const TunePtr tune = std::make_shared<SidTune>(static_cast<const uint_least8_t*>(rawData.Start()), static_cast<uint_least32_t>(rawData.Size())); CheckSidplayError(tune->getStatus()); const unsigned songIdx = tune->selectSong(0); const SidTuneInfo& tuneInfo = *tune->getInfo(); if (tuneInfo.songs() > 1) { Require(HasSidContainer(*properties)); } PropertiesHelper props(*properties); switch (tuneInfo.numberOfInfoStrings()) { default: case 3: //copyright/publisher really props.SetComment(FromStdString(tuneInfo.infoString(2))); case 2: props.SetAuthor(FromStdString(tuneInfo.infoString(1))); case 1: props.SetTitle(FromStdString(tuneInfo.infoString(0))); case 0: break; } const Binary::Container::Ptr data = rawData.GetSubcontainer(0, tuneInfo.dataFileLen()); const Formats::Chiptune::Container::Ptr source = Formats::Chiptune::CreateCalculatingCrcContainer(data, 0, data->Size()); props.SetSource(*source); const uint_t fps = tuneInfo.songSpeed() == SidTuneInfo::SPEED_CIA_1A || tuneInfo.clockSpeed() == SidTuneInfo::CLOCK_NTSC ? 60 : 50; props.SetFramesFrequency(fps); const Information::Ptr info = MakePtr<Information>(GetDuration(params), tune, fps, songIdx); return MakePtr<Holder>(tune, info, properties); } catch (const std::exception&) { return Holder::Ptr(); } }
Container::Ptr Decode(const Binary::Container& rawData) const override { using namespace CompiledSTP; if (!Player->Match(rawData)) { return Container::Ptr(); } const Binary::TypedContainer typedData(rawData); const std::size_t availSize = rawData.Size(); const typename Version::RawPlayer& rawPlayer = *typedData.GetField<typename Version::RawPlayer>(0); const std::size_t playerSize = rawPlayer.GetSize(); if (playerSize >= std::min(availSize, CompiledSTP::MAX_PLAYER_SIZE)) { Dbg("Invalid player"); return Container::Ptr(); } Dbg("Detected player in first %1% bytes", playerSize); const std::size_t modDataSize = std::min(CompiledSTP::MAX_MODULE_SIZE, availSize - playerSize); const Binary::Container::Ptr modData = rawData.GetSubcontainer(playerSize, modDataSize); const Dump metainfo = rawPlayer.GetInfo(); if (CompiledSTP::IsInfoEmpty(metainfo)) { Dbg("Player has empty metainfo"); if (const Binary::Container::Ptr originalModule = Formats::Chiptune::SoundTrackerPro::ParseCompiled(*modData, Formats::Chiptune::SoundTrackerPro::GetStubBuilder())) { const std::size_t originalSize = originalModule->Size(); return CreateContainer(originalModule, playerSize + originalSize); } } else if (const Binary::Container::Ptr fixedModule = Formats::Chiptune::SoundTrackerPro::InsertMetaInformation(*modData, metainfo)) { if (Formats::Chiptune::SoundTrackerPro::ParseCompiled(*fixedModule, Formats::Chiptune::SoundTrackerPro::GetStubBuilder())) { const std::size_t originalSize = fixedModule->Size() - metainfo.size(); return CreateContainer(fixedModule, playerSize + originalSize); } Dbg("Failed to parse fixed module"); } Dbg("Failed to find module after player"); return Container::Ptr(); }
Formats::Chiptune::Container::Ptr Parse(const Binary::Container& data, Builder& target) { if (data.Size() < sizeof(RawHeader)) { return Formats::Chiptune::Container::Ptr(); } try { Format format(data); format.ParseMainPart(target); format.ParseExtendedPart(target); const Binary::Container::Ptr subData = format.GetUsedData(); const std::size_t fixedStart = offsetof(RawHeader, RAM); const std::size_t fixedEnd = sizeof(RawHeader); return CreateCalculatingCrcContainer(subData, fixedStart, fixedEnd - fixedStart); } catch (const std::exception&) { return Formats::Chiptune::Container::Ptr(); } }
bool FastCheck(const Binary::Container& rawData) { if (rawData.Size() <= sizeof(Header)) { return false; } const Header& header = *static_cast<const Header*>(rawData.Start()); std::size_t minDataStart = sizeof(header); for (uint_t reg = 0; reg != header.Buffers.size(); ++reg) { const BufferDescription& buf = header.Buffers[reg]; if (buf.SizeHi != 1 && buf.SizeHi != 4) { return false; } const std::size_t dataOffset = buf.GetAbsoluteOffset(reg); if (dataOffset < minDataStart) { return false; } minDataStart = dataOffset; } return true; }
Formats::Chiptune::Container::Ptr Parse(const Binary::Container& rawData, Builder& target) { if (!FastCheck(rawData)) { return Formats::Chiptune::Container::Ptr(); } try { const std::size_t size = rawData.Size(); const uint8_t* const begin = static_cast<const uint8_t*>(rawData.Start()); const uint8_t* const end = begin + size; const Header& header = *safe_ptr_cast<const Header*>(begin); const uint_t frames = fromLE(header.Duration); target.SetFrames(frames); std::size_t usedBegin = size; std::size_t usedEnd = 0; for (uint_t reg = 0; reg != header.Buffers.size(); ++reg) { target.StartChannel(reg); const BufferDescription& buf = header.Buffers[reg]; const std::size_t offset = buf.GetAbsoluteOffset(reg); Require(offset < size); Stream stream(buf.SizeHi, begin + offset, end); ParseBuffer(frames, stream, target); usedBegin = std::min(usedBegin, offset); usedEnd = std::max<std::size_t>(usedEnd, stream.GetCursor() - begin); } const Binary::Container::Ptr subData = rawData.GetSubcontainer(0, usedEnd); return CreateCalculatingCrcContainer(subData, usedBegin, usedEnd - usedBegin); } catch (const std::exception&) { return Formats::Chiptune::Container::Ptr(); } }
Binary::TypedContainer CreateContainer(const Binary::Container& rawData) { return Binary::TypedContainer(rawData, std::min(rawData.Size(), MAX_SIZE)); }