diff options
author | Xin Li <delphij@google.com> | 2024-01-17 22:13:58 -0800 |
---|---|---|
committer | Xin Li <delphij@google.com> | 2024-01-17 22:13:58 -0800 |
commit | 28d03a2a1cabbe01d7bcb6cf5166c10e50d3c2c6 (patch) | |
tree | c1643be8ab17fc607cea748a8bb1d621a5964873 /pw_tokenizer/detokenize.cc | |
parent | ec2628a6ba2d0ecbe3ac10c8c772f6fc6acc345d (diff) | |
parent | f054515492af5132f685cb23fe11891ee77104c9 (diff) | |
download | pigweed-28d03a2a1cabbe01d7bcb6cf5166c10e50d3c2c6.tar.gz |
Merge Android 24Q1 Release (ab/11220357)temp_319669529
Bug: 319669529
Merged-In: Iba357b308a79d0c8b560acd4f72b5423c9c83294
Change-Id: Icdf552029fb97a34e83c6dd7799433fc473a2506
Diffstat (limited to 'pw_tokenizer/detokenize.cc')
-rw-r--r-- | pw_tokenizer/detokenize.cc | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/pw_tokenizer/detokenize.cc b/pw_tokenizer/detokenize.cc index 5e3262f86..b0557985e 100644 --- a/pw_tokenizer/detokenize.cc +++ b/pw_tokenizer/detokenize.cc @@ -19,11 +19,76 @@ #include "pw_bytes/bit.h" #include "pw_bytes/endian.h" +#include "pw_tokenizer/base64.h" #include "pw_tokenizer/internal/decode.h" +#include "pw_tokenizer/nested_tokenization.h" namespace pw::tokenizer { namespace { +class NestedMessageDetokenizer { + public: + NestedMessageDetokenizer(const Detokenizer& detokenizer) + : detokenizer_(detokenizer) {} + + void Detokenize(std::string_view chunk) { + for (char next_char : chunk) { + Detokenize(next_char); + } + } + + void Detokenize(char next_char) { + switch (state_) { + case kNonMessage: + if (next_char == PW_TOKENIZER_NESTED_PREFIX) { + message_buffer_.push_back(next_char); + state_ = kMessage; + } else { + output_.push_back(next_char); + } + break; + case kMessage: + if (base64::IsValidChar(next_char)) { + message_buffer_.push_back(next_char); + } else { + HandleEndOfMessage(); + if (next_char == PW_TOKENIZER_NESTED_PREFIX) { + message_buffer_.push_back(next_char); + } else { + output_.push_back(next_char); + state_ = kNonMessage; + } + } + break; + } + } + + std::string Flush() { + if (state_ == kMessage) { + HandleEndOfMessage(); + state_ = kNonMessage; + } + return std::move(output_); + } + + private: + void HandleEndOfMessage() { + if (auto result = detokenizer_.DetokenizeBase64Message(message_buffer_); + result.ok()) { + output_ += result.BestString(); + } else { + output_ += message_buffer_; // Keep the original if it doesn't decode. + } + message_buffer_.clear(); + } + + const Detokenizer& detokenizer_; + std::string output_; + std::string message_buffer_; + + enum { kNonMessage, kMessage } state_ = kNonMessage; +}; + std::string UnknownTokenMessage(uint32_t value) { std::string output(PW_TOKENIZER_ARG_DECODING_ERROR_PREFIX "unknown token "); @@ -126,4 +191,17 @@ DetokenizedString Detokenizer::Detokenize( : encoded.subspan(sizeof(token))); } +DetokenizedString Detokenizer::DetokenizeBase64Message( + std::string_view text) const { + std::string buffer(text); + buffer.resize(PrefixedBase64DecodeInPlace(buffer)); + return Detokenize(buffer); +} + +std::string Detokenizer::DetokenizeBase64(std::string_view text) const { + NestedMessageDetokenizer nested_detokenizer(*this); + nested_detokenizer.Detokenize(text); + return nested_detokenizer.Flush(); +} + } // namespace pw::tokenizer |