// Copyright (c) 2015-2026 Vector 35 Inc // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. #include "binaryninjaapi.h" using namespace BinaryNinja; using namespace std; DownloadInstance::DownloadInstance(DownloadProvider* provider) { BNDownloadInstanceCallbacks cb; cb.context = this; cb.destroyInstance = DestroyInstanceCallback; cb.performRequest = PerformRequestCallback; cb.performCustomRequest = PerformCustomRequestCallback; cb.freeResponse = PerformFreeResponse; AddRefForRegistration(); m_object = BNInitDownloadInstance(provider->GetObject(), &cb); } DownloadInstance::DownloadInstance(BNDownloadInstance* instance) { m_object = instance; } void DownloadInstance::DestroyInstanceCallback(void* ctxt) { DownloadInstance* instance = (DownloadInstance*)ctxt; instance->DestroyInstance(); } int DownloadInstance::PerformRequestCallback(void* ctxt, const char* url) { CallbackRef instance(ctxt); return instance->PerformRequest(url); } int DownloadInstance::PerformCustomRequestCallback(void* ctxt, const char* method, const char* url, uint64_t headerCount, const char* const* headerKeys, const char* const* headerValues, BNDownloadInstanceResponse** response) { CallbackRef instance(ctxt); unordered_map headers; for (uint64_t i = 0; i < headerCount; i++) { headers[headerKeys[i]] = headerValues[i]; } Response apiResponse; int status = instance->PerformCustomRequest(method, url, headers, apiResponse); char** keys = new char*[apiResponse.headers.size()]; char** values = new char*[apiResponse.headers.size()]; uint64_t i = 0; for (const auto& pair : apiResponse.headers) { keys[i] = BNAllocString(pair.first.c_str()); values[i] = BNAllocString(pair.second.c_str()); i++; } *response = new BNDownloadInstanceResponse; (*response)->statusCode = apiResponse.statusCode; (*response)->headerCount = apiResponse.headers.size(); (*response)->headerKeys = keys; (*response)->headerValues = values; return status; } void DownloadInstance::PerformFreeResponse(void* ctxt, BNDownloadInstanceResponse* response) { for (uint64_t i = 0; i < response->headerCount; i++) { BNFreeString(response->headerKeys[i]); BNFreeString(response->headerValues[i]); } delete[] response->headerKeys; delete[] response->headerValues; delete response; } int64_t DownloadInstance::ReadDataCallback(uint8_t* data, uint64_t len) { return BNReadDataForDownloadInstance(m_object, data, len); } uint64_t DownloadInstance::WriteDataCallback(uint8_t* data, uint64_t len) { return BNWriteDataForDownloadInstance(m_object, data, len); } bool DownloadInstance::NotifyProgressCallback(uint64_t progress, uint64_t total) { return BNNotifyProgressForDownloadInstance(m_object, progress, total); } void DownloadInstance::SetError(const string& error) { BNSetErrorForDownloadInstance(m_object, error.c_str()); } string DownloadInstance::GetError() const { char* str = BNGetErrorForDownloadInstance(m_object); string result = str; BNFreeString(str); return result; } int DownloadInstance::PerformRequest(const string& url, BNDownloadInstanceOutputCallbacks* callbacks) { return BNPerformDownloadRequest(m_object, url.c_str(), callbacks); } int DownloadInstance::PerformCustomRequest(const string& method, const string& url, const std::unordered_map& headers, Response& response, BNDownloadInstanceInputOutputCallbacks* callbacks) { const char** headerKeys = new const char*[headers.size()]; const char** headerValues = new const char*[headers.size()]; uint64_t i = 0; for (auto it = headers.begin(); it != headers.end(); ++it) { headerKeys[i] = it->first.c_str(); headerValues[i] = it->second.c_str(); i++; } BNDownloadInstanceResponse* bnResponse; int result = BNPerformCustomRequest( m_object, method.c_str(), url.c_str(), headers.size(), headerKeys, headerValues, &bnResponse, callbacks); response.statusCode = bnResponse->statusCode; for (uint64_t i = 0; i < bnResponse->headerCount; i++) { response.headers[bnResponse->headerKeys[i]] = bnResponse->headerValues[i]; } BNFreeDownloadInstanceResponse(bnResponse); delete[] headerKeys; delete[] headerValues; return result; } void DownloadInstance::DestroyInstance() { ReleaseForRegistration(); } CoreDownloadInstance::CoreDownloadInstance(BNDownloadInstance* instance) : DownloadInstance(instance) {} int CoreDownloadInstance::PerformRequest(const std::string& url) { (void)url; return -1; } int CoreDownloadInstance::PerformCustomRequest(const std::string& method, const std::string& url, const std::unordered_map& headers, Response& response) { (void)method; (void)url; (void)headers; response.statusCode = -1; return -1; } DownloadProvider::DownloadProvider(const string& name) : m_nameForRegister(name) {} DownloadProvider::DownloadProvider(BNDownloadProvider* provider) { m_object = provider; } BNDownloadInstance* DownloadProvider::CreateInstanceCallback(void* ctxt) { DownloadProvider* provider = (DownloadProvider*)ctxt; Ref instance = provider->CreateNewInstance(); return instance ? BNNewDownloadInstanceReference(instance->GetObject()) : nullptr; } vector> DownloadProvider::GetList() { size_t count; BNDownloadProvider** list = BNGetDownloadProviderList(&count); vector> result; result.reserve(count); for (size_t i = 0; i < count; i++) result.push_back(new CoreDownloadProvider(list[i])); BNFreeDownloadProviderList(list); return result; } Ref DownloadProvider::GetByName(const string& name) { BNDownloadProvider* result = BNGetDownloadProviderByName(name.c_str()); if (!result) return nullptr; return new CoreDownloadProvider(result); } void DownloadProvider::Register(DownloadProvider* provider) { BNDownloadProviderCallbacks cb; cb.context = provider; cb.createInstance = CreateInstanceCallback; provider->m_object = BNRegisterDownloadProvider(provider->m_nameForRegister.c_str(), &cb); } CoreDownloadProvider::CoreDownloadProvider(BNDownloadProvider* provider) : DownloadProvider(provider) {} Ref CoreDownloadProvider::CreateNewInstance() { BNDownloadInstance* result = BNCreateDownloadProviderInstance(m_object); if (!result) return nullptr; return new CoreDownloadInstance(result); }