TrackReference.cpp 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "TrackReference.h"
  2. #include "NanoPBExtensions.h"
  3. #include "Utils.h"
  4. #include "protobuf/spirc.pb.h"
  5. using namespace cspot;
  6. static constexpr auto base62Alphabet =
  7. "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
  8. TrackReference::TrackReference() : type(Type::TRACK) {}
  9. void TrackReference::decodeURI() {
  10. if (gid.size() == 0) {
  11. // Episode GID is being fetched via base62 encoded URI
  12. auto idString = uri.substr(uri.find_last_of(":") + 1, uri.size());
  13. gid = {0};
  14. std::string_view alphabet(base62Alphabet);
  15. for (int x = 0; x < idString.size(); x++) {
  16. size_t d = alphabet.find(idString[x]);
  17. gid = bigNumMultiply(gid, 62);
  18. gid = bigNumAdd(gid, d);
  19. }
  20. #if __cplusplus >= 202002L
  21. if (uri.starts_with("episode")) {
  22. #else
  23. if (uri.find("episode") == 0) {
  24. #endif
  25. type = Type::EPISODE;
  26. }
  27. }
  28. }
  29. bool TrackReference::operator==(const TrackReference& other) const {
  30. return other.gid == gid && other.uri == uri;
  31. }
  32. bool TrackReference::pbEncodeTrackList(pb_ostream_t* stream,
  33. const pb_field_t* field,
  34. void* const* arg) {
  35. auto trackQueue = *static_cast<std::vector<TrackReference>*>(*arg);
  36. static TrackRef msg = TrackRef_init_zero;
  37. // Prepare nanopb callbacks
  38. msg.context.funcs.encode = &bell::nanopb::encodeString;
  39. msg.uri.funcs.encode = &bell::nanopb::encodeString;
  40. msg.gid.funcs.encode = &bell::nanopb::encodeVector;
  41. msg.queued.funcs.encode = &bell::nanopb::encodeBoolean;
  42. for (auto trackRef : trackQueue) {
  43. if (!pb_encode_tag_for_field(stream, field)) {
  44. return false;
  45. }
  46. msg.gid.arg = &trackRef.gid;
  47. msg.uri.arg = &trackRef.uri;
  48. msg.context.arg = &trackRef.context;
  49. msg.queued.arg = &trackRef.queued;
  50. if (!pb_encode_submessage(stream, TrackRef_fields, &msg)) {
  51. return false;
  52. }
  53. }
  54. return true;
  55. }
  56. bool TrackReference::pbDecodeTrackList(pb_istream_t* stream,
  57. const pb_field_t* field, void** arg) {
  58. auto trackQueue = static_cast<std::vector<TrackReference>*>(*arg);
  59. // Push a new reference
  60. trackQueue->push_back(TrackReference());
  61. auto& track = trackQueue->back();
  62. bool eof = false;
  63. pb_wire_type_t wire_type;
  64. pb_istream_t substream;
  65. uint32_t tag;
  66. while (!eof) {
  67. if (!pb_decode_tag(stream, &wire_type, &tag, &eof)) {
  68. // Decoding failed and not eof
  69. if (!eof) {
  70. return false;
  71. }
  72. // EOF
  73. } else {
  74. switch (tag) {
  75. case TrackRef_uri_tag:
  76. case TrackRef_context_tag:
  77. case TrackRef_gid_tag: {
  78. // Make substream
  79. if (!pb_make_string_substream(stream, &substream)) {
  80. return false;
  81. }
  82. uint8_t* destBuffer = nullptr;
  83. // Handle GID
  84. if (tag == TrackRef_gid_tag) {
  85. track.gid.resize(substream.bytes_left);
  86. destBuffer = &track.gid[0];
  87. } else if (tag == TrackRef_context_tag) {
  88. track.context.resize(substream.bytes_left);
  89. destBuffer = reinterpret_cast<uint8_t*>(&track.context[0]);
  90. } else if (tag == TrackRef_uri_tag) {
  91. track.uri.resize(substream.bytes_left);
  92. destBuffer = reinterpret_cast<uint8_t*>(&track.uri[0]);
  93. }
  94. if (!pb_read(&substream, destBuffer, substream.bytes_left)) {
  95. return false;
  96. }
  97. // Close substream
  98. if (!pb_close_string_substream(stream, &substream)) {
  99. return false;
  100. }
  101. break;
  102. }
  103. case TrackRef_queued_tag: {
  104. uint32_t queuedValue;
  105. // Decode boolean
  106. if (!pb_decode_varint32(stream, &queuedValue)) {
  107. return false;
  108. }
  109. // Cast down to bool
  110. track.queued = (bool)queuedValue;
  111. break;
  112. }
  113. default:
  114. // Field not known, skip
  115. pb_skip_field(stream, wire_type);
  116. break;
  117. }
  118. }
  119. }
  120. // Fill in GID when only URI is provided
  121. track.decodeURI();
  122. return true;
  123. }