opcode901_codec.cpp 1.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354
  1. /**
  2. * Opcode 901 is a vendor purchase. The request carries a vendor index, a sale index and an
  3. * optional clock. The clock is decoded so the body is checked whole; nothing reads it yet.
  4. */
  5. #include "opcode901_codec.h"
  6. #include "../../../encoding/bit_reader.h"
  7. #include "../biased_field.h"
  8. namespace sunrise::middleware::web_service::messages::opcode901 {
  9. namespace {
  10. /** The optional clock is a 64-bit signed value with no bias. */
  11. constexpr std::uint8_t kClockWidth = 64;
  12. /** One presence bit precedes the clock. */
  13. constexpr std::uint8_t kPresenceWidth = 1;
  14. /**
  15. * Bits allowed after the last field. Both legal forms end mid byte, so up to seven bits pad it.
  16. * A whole byte left over is data, not padding.
  17. */
  18. constexpr std::size_t kPaddingLimit = 8;
  19. } // namespace
  20. /** Decodes one purchase request body. */
  21. bool parse_request(const Message& message, Request& output) noexcept {
  22. if (message.opcode != kOpcode) {
  23. return false;
  24. }
  25. encoding::bits::Reader reader(message.payload);
  26. Request candidate{};
  27. std::uint64_t present = 0;
  28. if (!read_biased_index(reader, candidate.vendorIndex)
  29. || !read_biased_index(reader, candidate.saleIndex)
  30. || !reader.read(kPresenceWidth, present)) {
  31. return false;
  32. }
  33. candidate.hasClock = present != 0;
  34. if (candidate.hasClock) {
  35. std::uint64_t clock = 0;
  36. if (!reader.read(kClockWidth, clock)) {
  37. return false;
  38. }
  39. candidate.clock = static_cast<std::int64_t>(clock);
  40. }
  41. if (reader.remaining_bits() >= kPaddingLimit) {
  42. return false;
  43. }
  44. output = candidate;
  45. return true;
  46. }
  47. } // namespace sunrise::middleware::web_service::messages::opcode901