aboutsummaryrefslogtreecommitdiff
path: root/pw_tokenizer/detokenize.cc
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2024-01-17 22:13:58 -0800
committerXin Li <delphij@google.com>2024-01-17 22:13:58 -0800
commit28d03a2a1cabbe01d7bcb6cf5166c10e50d3c2c6 (patch)
treec1643be8ab17fc607cea748a8bb1d621a5964873 /pw_tokenizer/detokenize.cc
parentec2628a6ba2d0ecbe3ac10c8c772f6fc6acc345d (diff)
parentf054515492af5132f685cb23fe11891ee77104c9 (diff)
downloadpigweed-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.cc78
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