huangcm
2024-12-18 9d29be7f7249789d6ffd0440067187a9f040c2cd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#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