summaryrefslogtreecommitdiff
path: root/includes/image_io/jpeg/jpeg_segment.h
blob: c4a79fdbfd168297f1e28361b3805364aaa03948 (plain)
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
169
170
171
172
173
174
175
176
177
178
#ifndef IMAGE_IO_JPEG_JPEG_SEGMENT_H_  // NOLINT
#define IMAGE_IO_JPEG_JPEG_SEGMENT_H_  // NOLINT

#include "image_io/base/data_range.h"
#include "image_io/base/data_segment.h"
#include "image_io/jpeg/jpeg_marker.h"

namespace photos_editing_formats {
namespace image_io {

/// A JpegSegment is an entity in a JPEG file that starts with a JpegMarker and
/// is followed by zero or more payload bytes. The JpegSegment has a DataRange
/// that indicates the position of the segment in the originating DataSource.
/// A JpegScanner obtains DataSegment instances from a DataSource in such a way
/// that it can guarantee that a JpegSegment will span at most two DataSegment
/// instances. Clients of JpegSegment need not be concerned with the number of
/// underlying DataSegments if they use the member functions defined here to
/// access the segment's bytes.
class JpegSegment {
 public:
  /// If a JpegSegment has a variable length data payload, the payload data is
  /// located at this offset from the start of the payload.
  static constexpr size_t kVariablePayloadDataOffset = 2;

  /// Constructs a JpegSegment starting and ending at the indicated points in
  /// the given DataSegment instances, the second of which may be null.
  /// @param begin The start of JpegSegment range.
  /// @param end The end of JpegSegment range.
  /// @param begin_segment The DataSegment that contains the begin location of
  ///     the JpegSegment and the end if the end_segment is null.
  /// @param end_segment The DataSegment that contains the end location of the
  ///     JpegSegment if it is not null.
  JpegSegment(size_t begin, size_t end, const DataSegment* begin_segment,
              const DataSegment* end_segment)
      : data_range_(begin, end),
        begin_segment_(begin_segment),
        end_segment_(end_segment){}
  ~JpegSegment() = default;

  /// @return The DataRange of the data in the segment.
  const DataRange& GetDataRange() const { return data_range_; }

  /// @return The begin location of the segment's data range.
  size_t GetBegin() const { return data_range_.GetBegin(); }

  /// @return The end location of the segment's data range.
  size_t GetEnd() const { return data_range_.GetEnd(); }

  /// @return The length of the segment's data range.
  size_t GetLength() const { return data_range_.GetLength(); }

  /// @return True if the segment's range contains the location, else false.
  bool Contains(size_t location) const {
    return data_range_.Contains(location);
  }

  /// @return The location of the segment's JpegMarker.
  size_t GetMarkerLocation() const { return GetBegin(); }

  /// @return The location of the segment's payload, which includes the payload
  ///     length if applicable for the type of segment.
  size_t GetPayloadLocation() const { return GetBegin() + JpegMarker::kLength; }

  /// @return The location of the segment's payload's data.
  size_t GetPayloadDataLocation() const {
    return GetMarker().HasVariablePayloadSize()
               ? GetPayloadLocation() + kVariablePayloadDataOffset
               : GetPayloadLocation();
  }

  /// @param The location at which to obtain the byte value.
  /// @return The validated byte value at the location, or 0/false if the
  /// segment's range does not contain the location.
  ValidatedByte GetValidatedByte(size_t location) const {
    return DataSegment::GetValidatedByte(location, begin_segment_,
                                                   end_segment_);
  }

  /// @return The payload size or zero if the segment's marker indicates the
  ///     segment does not have a payload. The payload size includes the two
  ///     bytes that encode the length of the payload. I.e., the payload data
  ///     size is two less than the value returned by this function.
  size_t GetVariablePayloadSize() const;

  /// @param location The start location of the compare operation.
  /// @param str The string to compare the bytes with.
  /// @return True if the segment's bytes at the given location equals the str.
  bool BytesAtLocationStartWith(size_t location, const char* str) const;

  /// @param location The start location of the search operation.
  /// @param str The string to search for.
  /// @return True if the segment's contains the string, starting at location.
  bool BytesAtLocationContain(size_t location, const char* str) const;

  /// @param start_location The location at which to start the search.
  /// @param value The byte value to search for.
  /// @return The location in the segment's bytes of the next occurrence of the
  ///     given byte value, starting at the indicated location, or the segment's
  ///     range's GetEnd() location if not found.
  size_t Find(size_t start_location, Byte value) const;

  /// @param start_location The location at which to start the search.
  /// @param str The string to search for.
  /// @return the location in the segment's bytes of the next occurrence of the
  ///     given string value,  starting at the indicated location, or the
  ///     segment's range's GetEnd() location if not found.
  size_t Find(size_t location, const char* str) const;

  /// XMP property names have the syntax property_name="property_value".
  /// @param segment The segment in which to look for the property name/value.
  /// @param start_location Where to start looking for the property name.
  /// @param property_name The name of the property to look for.
  /// @return The string value associated with the xmp property name, or an
  ///     empty string if the property was not found.
  std::string ExtractXmpPropertyValue(size_t start_location,
                                      const char* property_name) const;

  /// XMP property names have the syntax property_name="property_value".
  /// @start_location The location in the segment to begin looking for the
  ///     property_name=" syntax.
  /// @return The location of the next byte following the quote, or GetEnd() if
  ///     the property_name=" syntax was not found.
  size_t FindXmpPropertyValueBegin(size_t start_location,
                                   const char* property_name) const;

  /// XMP property names have the syntax property_name="property_value".
  /// @start_location The location in the segment to begin looking for the final
  ///     quote of the property value.
  /// @return The location of quote that terminates the property_value, or
  ///     GetEnd() if the final quote was not found.
  size_t FindXmpPropertyValueEnd(size_t start_location) const;

  /// @param The DataRange to use to extract a string from the segment's bytes.
  /// @return The string extracted from the segment at locations indicated by
  ///     the data_range, or an empty string if the data_range is not contained
  ///     in the segment's range, or any invalid or zero bytes are encountered.
  std::string ExtractString(const DataRange& data_range) const;

  /// @return the JpegMarker of this segment.
  JpegMarker GetMarker() const {
    size_t marker_type_location = GetMarkerLocation() + 1;
    // An invalid ValidatedByte has a value of 0, and a JpegMarker with a 0
    // type value is invalid, so its ok to just grab the ValidatedByte's value.
    return JpegMarker(GetValidatedByte(marker_type_location).value);
  }

  /// Fills two strings with byte_count bytes from the start of the segment's
  /// payload in a form suitable for creating a "hex dump" of the segment. Note
  /// that if the jpeg segment has a entropy delimiter type marker, there is
  /// technically no payload to dump. However in this case, as long as a valid
  /// byte can be obtained from the jpeg segment's underlying data segments, a
  /// byte value will be dumped to the strings.
  /// @param byte_count The number of bytes to dump from the segment's payload.
  /// @param hex_string A string that will be at most 2 * byte_count in length
  ///     that will contain the hex values of the bytes.
  /// @param ascii_string A string that will be at most byte_count in length
  ///     that will contain the printable character of the bytes, or a '.' for
  ///     non-printable byte values.
  void GetPayloadHexDumpStrings(size_t byte_count, std::string* hex_string,
                                std::string* ascii_string) const;

 private:
  /// The DataRange of the JpegSegment.
  DataRange data_range_;

  /// The DataSegment that contains the begin of the range and possibly the
  /// end. This DataSegment will never be null.
  const DataSegment* begin_segment_;

  /// The DataSegment, that if not null, will contain the end location of the
  /// JPegSegment's DataRange.
  const DataSegment* end_segment_;
};

}  // namespace image_io
}  // namespace photos_editing_formats

#endif // IMAGE_IO_JPEG_JPEG_SEGMENT_H_  // NOLINT