// This file Copyright © 2013-2022 Mnemosyne LLC. // It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only), // or any future license endorsed by Mnemosyne LLC. // License text can be found in the licenses/ folder. #include #include #include #include #include "transmission.h" #include "quark.h" #include "utils.h" // tr_strvDup() using namespace std::literals; namespace { auto constexpr my_static = std::array{ ""sv, "activeTorrentCount"sv, "activity-date"sv, "activityDate"sv, "added"sv, "added-date"sv, "added.f"sv, "added6"sv, "added6.f"sv, "addedDate"sv, "address"sv, "alt-speed-down"sv, "alt-speed-enabled"sv, "alt-speed-time-begin"sv, "alt-speed-time-day"sv, "alt-speed-time-enabled"sv, "alt-speed-time-end"sv, "alt-speed-up"sv, "announce"sv, "announce-list"sv, "announceState"sv, "anti-brute-force-enabled"sv, "anti-brute-force-threshold"sv, "arguments"sv, "availability"sv, "bandwidth-priority"sv, "bandwidthPriority"sv, "bind-address-ipv4"sv, "bind-address-ipv6"sv, "bitfield"sv, "blocklist-date"sv, "blocklist-enabled"sv, "blocklist-size"sv, "blocklist-updates-enabled"sv, "blocklist-url"sv, "blocks"sv, "bytesCompleted"sv, "cache-size-mb"sv, "clientIsChoked"sv, "clientIsInterested"sv, "clientName"sv, "comment"sv, "comment_utf_8"sv, "compact-view"sv, "complete"sv, "config-dir"sv, "cookies"sv, "corrupt"sv, "corruptEver"sv, "created by"sv, "created by.utf-8"sv, "creation date"sv, "creator"sv, "cumulative-stats"sv, "current-stats"sv, "date"sv, "dateCreated"sv, "default-trackers"sv, "delete-local-data"sv, "desiredAvailable"sv, "destination"sv, "details-window-height"sv, "details-window-width"sv, "dht-enabled"sv, "dnd"sv, "done-date"sv, "doneDate"sv, "download-dir"sv, "download-dir-free-space"sv, "download-queue-enabled"sv, "download-queue-size"sv, "downloadCount"sv, "downloadDir"sv, "downloadLimit"sv, "downloadLimited"sv, "downloadSpeed"sv, "downloaded"sv, "downloaded-bytes"sv, "downloadedBytes"sv, "downloadedEver"sv, "downloaders"sv, "downloading-time-seconds"sv, "dropped"sv, "dropped6"sv, "e"sv, "editDate"sv, "encoding"sv, "encryption"sv, "error"sv, "errorString"sv, "eta"sv, "etaIdle"sv, "fields"sv, "file-count"sv, "fileStats"sv, "filename"sv, "files"sv, "files-added"sv, "files-unwanted"sv, "files-wanted"sv, "filesAdded"sv, "filter-mode"sv, "filter-text"sv, "filter-trackers"sv, "flagStr"sv, "flags"sv, "format"sv, "fromCache"sv, "fromDht"sv, "fromIncoming"sv, "fromLpd"sv, "fromLtep"sv, "fromPex"sv, "fromTracker"sv, "group"sv, "hasAnnounced"sv, "hasScraped"sv, "hashString"sv, "have"sv, "haveUnchecked"sv, "haveValid"sv, "honorsSessionLimits"sv, "host"sv, "id"sv, "idle-limit"sv, "idle-mode"sv, "idle-seeding-limit"sv, "idle-seeding-limit-enabled"sv, "ids"sv, "incomplete"sv, "incomplete-dir"sv, "incomplete-dir-enabled"sv, "info"sv, "inhibit-desktop-hibernation"sv, "ipv4"sv, "ipv6"sv, "isBackup"sv, "isDownloadingFrom"sv, "isEncrypted"sv, "isFinished"sv, "isIncoming"sv, "isPrivate"sv, "isStalled"sv, "isUTP"sv, "isUploadingTo"sv, "labels"sv, "lastAnnouncePeerCount"sv, "lastAnnounceResult"sv, "lastAnnounceStartTime"sv, "lastAnnounceSucceeded"sv, "lastAnnounceTime"sv, "lastAnnounceTimedOut"sv, "lastScrapeResult"sv, "lastScrapeStartTime"sv, "lastScrapeSucceeded"sv, "lastScrapeTime"sv, "lastScrapeTimedOut"sv, "leecherCount"sv, "leftUntilDone"sv, "length"sv, "location"sv, "lpd-enabled"sv, "m"sv, "magnetLink"sv, "main-window-height"sv, "main-window-is-maximized"sv, "main-window-layout-order"sv, "main-window-width"sv, "main-window-x"sv, "main-window-y"sv, "manualAnnounceTime"sv, "max-peers"sv, "maxConnectedPeers"sv, "memory-bytes"sv, "memory-units"sv, "message-level"sv, "metadataPercentComplete"sv, "metadata_size"sv, "metainfo"sv, "method"sv, "min_request_interval"sv, "move"sv, "msg_type"sv, "mtimes"sv, "name"sv, "name.utf-8"sv, "nextAnnounceTime"sv, "nextScrapeTime"sv, "nodes"sv, "nodes6"sv, "open-dialog-dir"sv, "p"sv, "path"sv, "path.utf-8"sv, "paused"sv, "pausedTorrentCount"sv, "peer-congestion-algorithm"sv, "peer-id-ttl-hours"sv, "peer-limit"sv, "peer-limit-global"sv, "peer-limit-per-torrent"sv, "peer-port"sv, "peer-port-random-high"sv, "peer-port-random-low"sv, "peer-port-random-on-start"sv, "peer-socket-tos"sv, "peerIsChoked"sv, "peerIsInterested"sv, "peers"sv, "peers2"sv, "peers2-6"sv, "peersConnected"sv, "peersFrom"sv, "peersGettingFromUs"sv, "peersSendingToUs"sv, "percentComplete"sv, "percentDone"sv, "pex-enabled"sv, "piece"sv, "piece length"sv, "pieceCount"sv, "pieceSize"sv, "pieces"sv, "play-download-complete-sound"sv, "port"sv, "port-forwarding-enabled"sv, "port-is-open"sv, "preallocation"sv, "prefetch-enabled"sv, "primary-mime-type"sv, "priorities"sv, "priority"sv, "priority-high"sv, "priority-low"sv, "priority-normal"sv, "private"sv, "progress"sv, "prompt-before-exit"sv, "queue-move-bottom"sv, "queue-move-down"sv, "queue-move-top"sv, "queue-move-up"sv, "queue-stalled-enabled"sv, "queue-stalled-minutes"sv, "queuePosition"sv, "rateDownload"sv, "rateToClient"sv, "rateToPeer"sv, "rateUpload"sv, "ratio-limit"sv, "ratio-limit-enabled"sv, "ratio-mode"sv, "read-clipboard"sv, "recent-download-dir-1"sv, "recent-download-dir-2"sv, "recent-download-dir-3"sv, "recent-download-dir-4"sv, "recheckProgress"sv, "remote-session-enabled"sv, "remote-session-host"sv, "remote-session-password"sv, "remote-session-port"sv, "remote-session-requres-authentication"sv, "remote-session-username"sv, "removed"sv, "rename-partial-files"sv, "reqq"sv, "result"sv, "rpc-authentication-required"sv, "rpc-bind-address"sv, "rpc-enabled"sv, "rpc-host-whitelist"sv, "rpc-host-whitelist-enabled"sv, "rpc-password"sv, "rpc-port"sv, "rpc-socket-mode"sv, "rpc-url"sv, "rpc-username"sv, "rpc-version"sv, "rpc-version-minimum"sv, "rpc-version-semver"sv, "rpc-whitelist"sv, "rpc-whitelist-enabled"sv, "scrape"sv, "scrape-paused-torrents-enabled"sv, "scrapeState"sv, "script-torrent-added-enabled"sv, "script-torrent-added-filename"sv, "script-torrent-done-enabled"sv, "script-torrent-done-filename"sv, "script-torrent-done-seeding-enabled"sv, "script-torrent-done-seeding-filename"sv, "seconds-active"sv, "secondsActive"sv, "secondsDownloading"sv, "secondsSeeding"sv, "seed-queue-enabled"sv, "seed-queue-size"sv, "seedIdleLimit"sv, "seedIdleMode"sv, "seedRatioLimit"sv, "seedRatioLimited"sv, "seedRatioMode"sv, "seederCount"sv, "seeding-time-seconds"sv, "session-count"sv, "session-id"sv, "sessionCount"sv, "show-backup-trackers"sv, "show-extra-peer-details"sv, "show-filterbar"sv, "show-notification-area-icon"sv, "show-options-window"sv, "show-statusbar"sv, "show-toolbar"sv, "show-tracker-scrapes"sv, "sitename"sv, "size-bytes"sv, "size-units"sv, "sizeWhenDone"sv, "sort-mode"sv, "sort-reversed"sv, "source"sv, "speed"sv, "speed-Bps"sv, "speed-bytes"sv, "speed-limit-down"sv, "speed-limit-down-enabled"sv, "speed-limit-up"sv, "speed-limit-up-enabled"sv, "speed-units"sv, "start-added-torrents"sv, "start-minimized"sv, "startDate"sv, "status"sv, "statusbar-stats"sv, "tag"sv, "tier"sv, "time-checked"sv, "torrent-added"sv, "torrent-added-notification-command"sv, "torrent-added-notification-enabled"sv, "torrent-complete-notification-command"sv, "torrent-complete-notification-enabled"sv, "torrent-complete-sound-command"sv, "torrent-complete-sound-enabled"sv, "torrent-duplicate"sv, "torrent-get"sv, "torrent-set"sv, "torrent-set-location"sv, "torrentCount"sv, "torrentFile"sv, "torrents"sv, "totalSize"sv, "total_size"sv, "trackerAdd"sv, "trackerList"sv, "trackerRemove"sv, "trackerReplace"sv, "trackerStats"sv, "trackers"sv, "trash-can-enabled"sv, "trash-original-torrent-files"sv, "umask"sv, "units"sv, "upload-slots-per-torrent"sv, "uploadLimit"sv, "uploadLimited"sv, "uploadRatio"sv, "uploadSpeed"sv, "upload_only"sv, "uploaded"sv, "uploaded-bytes"sv, "uploadedBytes"sv, "uploadedEver"sv, "url-list"sv, "use-global-speed-limit"sv, "use-speed-limit"sv, "user-has-given-informed-consent"sv, "ut_comment"sv, "ut_holepunch"sv, "ut_metadata"sv, "ut_pex"sv, "ut_recommend"sv, "utp-enabled"sv, "v"sv, "version"sv, "wanted"sv, "watch-dir"sv, "watch-dir-enabled"sv, "webseeds"sv, "webseedsSendingToUs"sv }; bool constexpr quarks_are_sorted() { for (size_t i = 1; i < std::size(my_static); ++i) { if (my_static[i - 1] >= my_static[i]) { return false; } } return true; } static_assert(quarks_are_sorted(), "Predefined quarks must be sorted by their string value"); static_assert(std::size(my_static) == TR_N_KEYS); auto& my_runtime{ *new std::vector{} }; } // namespace std::optional tr_quark_lookup(std::string_view key) { // is it in our static array? auto constexpr sbegin = std::begin(my_static); auto constexpr send = std::end(my_static); auto const sit = std::lower_bound(sbegin, send, key); if (sit != send && *sit == key) { return std::distance(sbegin, sit); } /* was it added during runtime? */ auto const rbegin = std::begin(my_runtime); auto const rend = std::end(my_runtime); auto const rit = std::find(rbegin, rend, key); if (rit != rend) { return TR_N_KEYS + std::distance(rbegin, rit); } return {}; } tr_quark tr_quark_new(std::string_view str) { if (auto const prior = tr_quark_lookup(str); prior) { return *prior; } auto const ret = TR_N_KEYS + std::size(my_runtime); my_runtime.emplace_back(tr_strvDup(str), std::size(str)); return ret; } std::string_view tr_quark_get_string_view(tr_quark q) { return q < TR_N_KEYS ? my_static[q] : my_runtime[q - TR_N_KEYS]; } char const* tr_quark_get_string(tr_quark q, size_t* len) { auto const tmp = tr_quark_get_string_view(q); if (len != nullptr) { *len = std::size(tmp); } return std::data(tmp); }