1 #ifndef IMAGE_IO_BASE_DATA_CONTEXT_H_  // NOLINT
2 #define IMAGE_IO_BASE_DATA_CONTEXT_H_  // NOLINT
3 
4 #include <list>
5 #include <string>
6 
7 #include "image_io/base/data_line_map.h"
8 #include "image_io/base/data_range.h"
9 #include "image_io/base/data_segment.h"
10 
11 namespace photos_editing_formats {
12 namespace image_io {
13 
14 /// A class to represent a position in a textual subrange of a DataSegment, and
15 /// a means to create an usable error message that shows the relevant line
16 /// number and line text and the location as a "caret" position. The class also
17 /// provides a list of names that can be used to add context to the errors.
18 class DataContext {
19  public:
20   /// @param location A location in the data segment.
21   /// @param range A subrange of the data segment's range.
22   /// @param data_line_map A map for obtaining the line number and range given
23   /// the location.
DataContext(size_t location,const DataRange & range,const DataSegment & segment,const DataLineMap & data_line_map)24   DataContext(size_t location, const DataRange& range,
25               const DataSegment& segment, const DataLineMap& data_line_map)
26       : location_(location),
27         range_(range),
28         segment_(segment),
29         line_info_map_(data_line_map) {}
30 
31   /// @return The location of the context.
GetLocation()32   size_t GetLocation() const { return location_; }
33 
34   /// @param location A new value to use to set the location of the context.
SetLocation(size_t location)35   void SetLocation(size_t location) { location_ = location; }
36 
37   /// @param delta A delta value that is added to the location of the context.
38   /// @return The new location of the context.
IncrementLocation(size_t delta)39   size_t IncrementLocation(size_t delta) {
40     location_ += delta;
41     return location_;
42   }
43 
44   /// @return The range of the data segment defined by this context.
GetRange()45   const DataRange& GetRange() const { return range_; }
46 
47   /// @param range Sets a new range to use for this context.
SetRange(const DataRange & range)48   void SetRange(const DataRange& range) { range_ = range; }
49 
50   /// @return The data segment of this context.
GetSegment()51   const DataSegment& GetSegment() const { return segment_; }
52 
53   /// @return The line info map of this context.
GetDataLineMap()54   const DataLineMap& GetDataLineMap() const { return line_info_map_; }
55 
56   /// @return Whether the context's location and range are valid for use with
57   /// the data segment's range.
IsValidLocationAndRange()58   bool IsValidLocationAndRange() const {
59     return range_.IsValid() && range_.Contains(location_) &&
60            segment_.GetDataRange().Contains(range_);
61   }
62 
63   /// @return A pointer to the data segment's buffer, cast as a const char* type
64   /// pointer, or nullptr if the location and/or range are invalid.
GetCharBytes()65   const char* GetCharBytes() const {
66     return IsValidLocationAndRange()
67                ? reinterpret_cast<const char*>(segment_.GetBuffer(location_))
68                : nullptr;
69   }
70 
71   /// @return The number of bytes available from the location of the context to
72   /// the end of the context's range, or 0 if the location and/or range are
73   /// invalid.
GetBytesAvailable()74   size_t GetBytesAvailable() const {
75     return IsValidLocationAndRange() ? range_.GetEnd() - location_ : 0;
76   }
77 
78   /// @return The context's name list that is used when creating error messages.
GetNameList()79   std::list<std::string>& GetNameList() { return name_list_; }
80 
81   /// @return The context's name list that is used when creating error messages.
GetNameList()82   const std::list<std::string>& GetNameList() const { return name_list_; }
83 
84   /// @return An error message that describes the location/range data segment
85   /// range that leads to the IsValidLocationRange() function returning false.
86   /// Great to user for internal error messages.
87   std::string GetInvalidLocationAndRangeErrorText() const;
88 
89   /// @return An error message with the given descriptions for the error and the
90   /// expectation. See the other GetErrorText() function documentation for more
91   /// details on the format of the error messsage.
92   std::string GetErrorText(const std::string& error_description,
93                            const std::string& expectation_description) const;
94 
95   /// @return An error message with the given descriptions for the error and the
96   /// expectation. The format of the error message is:
97   ///   error_description
98   ///   - prefix_name_list:name_list:postfix_name_list:
99   ///   - at line:number:line_contents
100   ///   -                ^expected:expectation_description
101   /// If error_description is empty then the first line containing it is not
102   /// written. If expectation_description is empty, then the expected:... part
103   /// of the last line is not written. If the context's name list, and the
104   /// pre/postfix name lists are all empty, then that line is not written.
105   std::string GetErrorText(const std::list<std::string>& prefix_name_list,
106                            const std::list<std::string>& postfix_name_list,
107                            const std::string& error_description,
108                            const std::string& expectation_description) const;
109 
110  private:
111   /// @return The string with the contents of the prefix_name_list, name_list_
112   /// and the postfix namelist concatenated with a ":" separator.
113   std::string GetNamesString(
114       const std::list<std::string>& prefix_name_list,
115       const std::list<std::string>& postfix_name_list) const;
116 
117   /// @return The line number string of the form line:XX, where XX is the data
118   /// line's number or "?" if the nmber is zero.
119   std::string GetLineNumberString(const DataLine& data_line) const;
120 
121   /// Gets the clipped and line ranges using the data line's range value.
122   void GetClippedAndLineRange(const DataLine& data_line,
123                               DataRange* clipped_range,
124                               DataRange* line_range) const;
125 
126   /// Gets the line string using the clipped and line ranges and updates the
127   /// number of spaces before the caret depending on the contents of the line.
128   std::string GetLineString(const DataRange& clipped_range,
129                             const DataRange& line_range,
130                             size_t* spaces_before_caret) const;
131 
132   /// See the constructor for documentation on the data members.
133   size_t location_;
134   DataRange range_;
135   const DataSegment& segment_;
136   const DataLineMap& line_info_map_;
137   std::list<std::string> name_list_;
138 };
139 
140 }  // namespace image_io
141 }  // namespace photos_editing_formats
142 
143 #endif // IMAGE_IO_BASE_DATA_CONTEXT_H_  // NOLINT
144