#include "image_io/base/data_context.h"
|
|
#include <cctype>
|
#include <iomanip>
|
#include <sstream>
|
|
#include "image_io/base/byte_data.h"
|
|
namespace photos_editing_formats {
|
namespace image_io {
|
|
namespace {
|
|
void AddNames(const std::list<std::string>& name_list, std::stringstream* ss) {
|
for (const auto& name : name_list) {
|
*ss << name << ":";
|
}
|
}
|
|
} // namespace
|
|
std::string DataContext::GetInvalidLocationAndRangeErrorText() const {
|
std::stringstream ss;
|
ss << "Invalid location:" << location_ << " range:[" << range_.GetBegin()
|
<< "," << range_.GetEnd() << ") segment_range:["
|
<< segment_.GetDataRange().GetBegin() << ","
|
<< segment_.GetDataRange().GetEnd() << ")";
|
return GetErrorText(ss.str(), "");
|
}
|
|
std::string DataContext::GetErrorText(
|
const std::string& error_description,
|
const std::string& expectation_description) const {
|
std::list<std::string> none;
|
return GetErrorText(none, none, error_description, expectation_description);
|
}
|
|
std::string DataContext::GetErrorText(
|
const std::list<std::string>& prefix_name_list,
|
const std::list<std::string>& postfix_name_list,
|
const std::string& error_description,
|
const std::string& expectation_description) const {
|
const std::string kContinue("- ");
|
std::stringstream ss;
|
|
// Write error description if present.
|
if (!error_description.empty()) {
|
ss << error_description << std::endl;
|
}
|
|
// Write name:name:... if present.
|
std::string names_string =
|
GetNamesString(prefix_name_list, postfix_name_list);
|
if (!names_string.empty()) {
|
ss << kContinue << names_string << std::endl;
|
}
|
|
// Get the line:XX part of the line string.
|
DataLine data_line;
|
std::string line_number_string;
|
if (IsValidLocationAndRange()) {
|
data_line = line_info_map_.GetDataLine(location_);
|
line_number_string = GetLineNumberString(data_line);
|
}
|
|
// Get the line_string related ranges and the line string.
|
DataRange clipped_range, line_range;
|
size_t spaces_before_caret = line_number_string.length();
|
GetClippedAndLineRange(data_line, &clipped_range, &line_range);
|
std::string line_string =
|
GetLineString(clipped_range, line_range, &spaces_before_caret);
|
|
// Write the line string
|
ss << kContinue << line_number_string << line_string << std::endl;
|
|
// Write the caret and expectation description
|
size_t spaces_count = location_ + spaces_before_caret - line_range.GetBegin();
|
std::string spaces(spaces_count, ' ');
|
ss << kContinue << spaces << '^';
|
if (!expectation_description.empty()) {
|
ss << "expected:" << expectation_description;
|
}
|
return ss.str();
|
}
|
|
std::string DataContext::GetNamesString(
|
const std::list<std::string>& prefix_name_list,
|
const std::list<std::string>& postfix_name_list) const {
|
std::stringstream ss;
|
if (!prefix_name_list.empty() || !name_list_.empty() ||
|
!postfix_name_list.empty()) {
|
AddNames(prefix_name_list, &ss);
|
AddNames(name_list_, &ss);
|
AddNames(postfix_name_list, &ss);
|
}
|
return ss.str();
|
}
|
|
std::string DataContext::GetLineNumberString(const DataLine& data_line) const {
|
std::stringstream liness;
|
liness << "line:";
|
if (data_line.number == 0) {
|
liness << "?:";
|
} else {
|
liness << data_line.number << ":";
|
}
|
return liness.str();
|
}
|
|
void DataContext::GetClippedAndLineRange(const DataLine& data_line,
|
DataRange* clipped_range,
|
DataRange* line_range) const {
|
// Lines could be really long, so provide some sane limits: some kLimit chars
|
// on either side of the current location.
|
const size_t kLimit = 25;
|
size_t line_begin, line_end;
|
*clipped_range = data_line.range.IsValid()
|
? range_.GetIntersection(data_line.range)
|
: range_;
|
if (clipped_range->IsValid() && clipped_range->Contains(location_)) {
|
line_begin = (clipped_range->GetBegin() + kLimit < location_)
|
? location_ - kLimit
|
: clipped_range->GetBegin();
|
line_end = std::min(line_begin + 2 * kLimit, clipped_range->GetEnd());
|
} else {
|
line_begin = location_;
|
line_end = std::min(location_ + 2 * kLimit, range_.GetEnd());
|
*clipped_range = DataRange(line_begin, line_end);
|
}
|
*line_range = DataRange(line_begin, line_end);
|
}
|
|
std::string DataContext::GetLineString(const DataRange& clipped_range,
|
const DataRange& line_range,
|
size_t* spaces_before_caret) const {
|
std::stringstream ss;
|
if (!IsValidLocationAndRange()) {
|
ss << "Invalid location or range";
|
return ss.str();
|
}
|
|
const char* cbytes =
|
reinterpret_cast<const char*>(segment_.GetBuffer(line_range.GetBegin()));
|
if (cbytes != nullptr) {
|
if (line_range.GetBegin() != clipped_range.GetBegin()) {
|
ss << "...";
|
*spaces_before_caret += 3;
|
}
|
for (size_t index = 0; index < line_range.GetLength(); ++index) {
|
char cbyte = cbytes[index];
|
if (isprint(cbyte)) {
|
ss << cbyte;
|
} else {
|
ss << "\\x" << ByteData::Byte2Hex(cbyte);
|
if (index + line_range.GetBegin() < location_) {
|
*spaces_before_caret += 4;
|
}
|
}
|
}
|
if (line_range.GetEnd() != clipped_range.GetEnd()) {
|
ss << "...";
|
}
|
}
|
return ss.str();
|
}
|
|
} // namespace image_io
|
} // namespace photos_editing_formats
|