#include "image_io/base/data_context.h" #include #include #include #include "image_io/base/byte_data.h" namespace photos_editing_formats { namespace image_io { namespace { void AddNames(const std::list& 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 none; return GetErrorText(none, none, error_description, expectation_description); } std::string DataContext::GetErrorText( const std::list& prefix_name_list, const std::list& 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& prefix_name_list, const std::list& 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(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