/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/traceconv/trace_to_text.h"

#include "perfetto/base/logging.h"
#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/scoped_file.h"
#include "perfetto/ext/protozero/proto_ring_buffer.h"
#include "src/traceconv/trace.descriptor.h"
#include "src/traceconv/winscope.descriptor.h"
#include "src/traceconv/utils.h"

#include "protos/perfetto/trace/trace.pbzero.h"
#include "protos/perfetto/trace/trace_packet.pbzero.h"

#include "src/trace_processor/util/descriptors.h"
#include "src/trace_processor/util/gzip_utils.h"
#include "src/trace_processor/util/protozero_to_text.h"
#include "src/trace_processor/util/trace_type.h"

namespace perfetto {
namespace trace_to_text {
namespace {

using perfetto::trace_processor::DescriptorPool;
using trace_processor::TraceType;
using trace_processor::util::GzipDecompressor;

template <size_t N>
static void WriteToOutput(std::ostream* output, const char (&str)[N]) {
  output->write(str, sizeof(str) - 1);
}

// Online algorithm to covert trace binary to text format.
// Usage:
//  - Feed the trace-binary in a sequence of memblock, and it will continue to
//    write the output in given std::ostream*.
class OnlineTraceToText {
 public:
  OnlineTraceToText(std::ostream* output) : output_(output) {
    pool_.AddFromFileDescriptorSet(kTraceDescriptor.data(),
                                   kTraceDescriptor.size());
    pool_.AddFromFileDescriptorSet(kWinscopeDescriptor.data(),
                                   kWinscopeDescriptor.size());
  }
  OnlineTraceToText(const OnlineTraceToText&) = delete;
  OnlineTraceToText& operator=(const OnlineTraceToText&) = delete;
  void Feed(const uint8_t* data, size_t len);
  bool ok() const { return ok_; }

 private:
  std::string TracePacketToText(protozero::ConstBytes packet,
                                uint32_t indent_depth);
  void PrintCompressedPackets(protozero::ConstBytes packets);

  bool ok_ = true;
  std::ostream* output_;
  protozero::ProtoRingBuffer ring_buffer_;
  DescriptorPool pool_;
  size_t bytes_processed_ = 0;
  size_t packet_ = 0;
};

std::string OnlineTraceToText::TracePacketToText(protozero::ConstBytes packet,
                                                 uint32_t indent_depth) {
  namespace pb0_to_text = trace_processor::protozero_to_text;
  return pb0_to_text::ProtozeroToText(pool_, ".perfetto.protos.TracePacket",
                                      packet, pb0_to_text::kIncludeNewLines,
                                      indent_depth);
}

void OnlineTraceToText::PrintCompressedPackets(protozero::ConstBytes packets) {
  WriteToOutput(output_, "compressed_packets {\n");
  if (trace_processor::util::IsGzipSupported()) {
    std::vector<uint8_t> whole_data =
        GzipDecompressor::DecompressFully(packets.data, packets.size);
    protos::pbzero::Trace::Decoder decoder(whole_data.data(),
                                           whole_data.size());
    for (auto it = decoder.packet(); it; ++it) {
      WriteToOutput(output_, "  packet {\n");
      std::string text = TracePacketToText(*it, 2);
      output_->write(text.data(), std::streamsize(text.size()));
      WriteToOutput(output_, "\n  }\n");
    }
  } else {
    static const char kErrMsg[] =
        "Cannot decode compressed packets. zlib not enabled in the build "
        "config";
    WriteToOutput(output_, kErrMsg);
    static bool log_once = [] {
      PERFETTO_ELOG("%s", kErrMsg);
      return true;
    }();
    base::ignore_result(log_once);
  }
  WriteToOutput(output_, "}\n");
}

void OnlineTraceToText::Feed(const uint8_t* data, size_t len) {
  ring_buffer_.Append(data, static_cast<size_t>(len));
  while (true) {
    auto token = ring_buffer_.ReadMessage();
    if (token.fatal_framing_error) {
      PERFETTO_ELOG("Failed to tokenize trace packet");
      ok_ = false;
      return;
    }
    if (!token.valid()) {
      // no need to set `ok_ = false` here because this just means
      // we've run out of packets in the ring buffer.
      break;
    }

    if (token.field_id != protos::pbzero::Trace::kPacketFieldNumber) {
      PERFETTO_ELOG("Skipping invalid field");
      continue;
    }
    protos::pbzero::TracePacket::Decoder decoder(token.start, token.len);
    bytes_processed_ += token.len;
    if ((packet_++ & 0x3f) == 0) {
      fprintf(stderr, "Processing trace: %8zu KB%c", bytes_processed_ / 1024,
              kProgressChar);
      fflush(stderr);
    }
    if (decoder.has_compressed_packets()) {
      PrintCompressedPackets(decoder.compressed_packets());
    } else {
      WriteToOutput(output_, "packet {\n");
      protozero::ConstBytes packet = {token.start, token.len};
      std::string text = TracePacketToText(packet, 1 /* indent_depth */);
      output_->write(text.data(), std::streamsize(text.size()));
      WriteToOutput(output_, "\n}\n");
    }
  }
}

class InputReader {
 public:
  InputReader(std::istream* input) : input_(input) {}
  // Request the input-stream to read next |len_limit| bytes and load
  // it in |data|. It also updates the |len| with actual number of bytes loaded
  // in |data|. This can be less than requested |len_limit| if we have reached
  // at the end of the file.
  bool Read(uint8_t* data, uint32_t* len, uint32_t len_limit) {
    if (input_->eof())
      return false;
    input_->read(reinterpret_cast<char*>(data), std::streamsize(len_limit));
    if (input_->bad() || (input_->fail() && !input_->eof())) {
      PERFETTO_ELOG("Failed while reading trace");
      ok_ = false;
      return false;
    }
    *len = uint32_t(input_->gcount());
    return true;
  }
  bool ok() const { return ok_; }

 private:
  std::istream* input_;
  bool ok_ = true;
};

}  // namespace

bool TraceToText(std::istream* input, std::ostream* output) {
  constexpr size_t kMaxMsgSize = protozero::ProtoRingBuffer::kMaxMsgSize;
  std::unique_ptr<uint8_t[]> buffer(new uint8_t[kMaxMsgSize]);
  uint32_t buffer_len = 0;

  InputReader input_reader(input);
  OnlineTraceToText online_trace_to_text(output);

  input_reader.Read(buffer.get(), &buffer_len, kMaxMsgSize);
  TraceType type = trace_processor::GuessTraceType(buffer.get(), buffer_len);

  if (type == TraceType::kGzipTraceType) {
    GzipDecompressor decompressor;
    auto consumer = [&](const uint8_t* data, size_t len) {
      online_trace_to_text.Feed(data, len);
    };
    using ResultCode = GzipDecompressor::ResultCode;
    do {
      ResultCode code =
          decompressor.FeedAndExtract(buffer.get(), buffer_len, consumer);
      if (code == ResultCode::kError || !online_trace_to_text.ok())
        return false;
    } while (input_reader.Read(buffer.get(), &buffer_len, kMaxMsgSize));
    return input_reader.ok();
  } else if (type == TraceType::kProtoTraceType) {
    do {
      online_trace_to_text.Feed(buffer.get(), buffer_len);
      if (!online_trace_to_text.ok())
        return false;
    } while (input_reader.Read(buffer.get(), &buffer_len, kMaxMsgSize));
    return input_reader.ok();
  } else {
    PERFETTO_ELOG("Unrecognised file.");
    return false;
  }
}

}  // namespace trace_to_text
}  // namespace perfetto
