• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef IMAGE_IO_JPEG_JPEG_SEGMENT_H_  // NOLINT
2 #define IMAGE_IO_JPEG_JPEG_SEGMENT_H_  // NOLINT
3 
4 #include "image_io/base/data_range.h"
5 #include "image_io/base/data_segment.h"
6 #include "image_io/jpeg/jpeg_marker.h"
7 
8 namespace photos_editing_formats {
9 namespace image_io {
10 
11 /// A JpegSegment is an entity in a JPEG file that starts with a JpegMarker and
12 /// is followed by zero or more payload bytes. The JpegSegment has a DataRange
13 /// that indicates the position of the segment in the originating DataSource.
14 /// A JpegScanner obtains DataSegment instances from a DataSource in such a way
15 /// that it can guarantee that a JpegSegment will span at most two DataSegment
16 /// instances. Clients of JpegSegment need not be concerned with the number of
17 /// underlying DataSegments if they use the member functions defined here to
18 /// access the segment's bytes.
19 class JpegSegment {
20  public:
21   /// If a JpegSegment has a variable length data payload, the payload data is
22   /// located at this offset from the start of the payload.
23   static constexpr size_t kVariablePayloadDataOffset = 2;
24 
25   /// Constructs a JpegSegment starting and ending at the indicated points in
26   /// the given DataSegment instances, the second of which may be null.
27   /// @param begin The start of JpegSegment range.
28   /// @param end The end of JpegSegment range.
29   /// @param begin_segment The DataSegment that contains the begin location of
30   ///     the JpegSegment and the end if the end_segment is null.
31   /// @param end_segment The DataSegment that contains the end location of the
32   ///     JpegSegment if it is not null.
JpegSegment(size_t begin,size_t end,const DataSegment * begin_segment,const DataSegment * end_segment)33   JpegSegment(size_t begin, size_t end, const DataSegment* begin_segment,
34               const DataSegment* end_segment)
35       : data_range_(begin, end),
36         begin_segment_(begin_segment),
37         end_segment_(end_segment){}
38   ~JpegSegment() = default;
39 
40   /// @return The DataRange of the data in the segment.
GetDataRange()41   const DataRange& GetDataRange() const { return data_range_; }
42 
43   /// @return The begin location of the segment's data range.
GetBegin()44   size_t GetBegin() const { return data_range_.GetBegin(); }
45 
46   /// @return The end location of the segment's data range.
GetEnd()47   size_t GetEnd() const { return data_range_.GetEnd(); }
48 
49   /// @return The length of the segment's data range.
GetLength()50   size_t GetLength() const { return data_range_.GetLength(); }
51 
52   /// @return True if the segment's range contains the location, else false.
Contains(size_t location)53   bool Contains(size_t location) const {
54     return data_range_.Contains(location);
55   }
56 
57   /// @return The location of the segment's JpegMarker.
GetMarkerLocation()58   size_t GetMarkerLocation() const { return GetBegin(); }
59 
60   /// @return The location of the segment's payload, which includes the payload
61   ///     length if applicable for the type of segment.
GetPayloadLocation()62   size_t GetPayloadLocation() const { return GetBegin() + JpegMarker::kLength; }
63 
64   /// @return The location of the segment's payload's data.
GetPayloadDataLocation()65   size_t GetPayloadDataLocation() const {
66     return GetMarker().HasVariablePayloadSize()
67                ? GetPayloadLocation() + kVariablePayloadDataOffset
68                : GetPayloadLocation();
69   }
70 
71   /// @param The location at which to obtain the byte value.
72   /// @return The validated byte value at the location, or 0/false if the
73   /// segment's range does not contain the location.
GetValidatedByte(size_t location)74   ValidatedByte GetValidatedByte(size_t location) const {
75     return DataSegment::GetValidatedByte(location, begin_segment_,
76                                                    end_segment_);
77   }
78 
79   /// @return The payload size or zero if the segment's marker indicates the
80   ///     segment does not have a payload. The payload size includes the two
81   ///     bytes that encode the length of the payload. I.e., the payload data
82   ///     size is two less than the value returned by this function.
83   size_t GetVariablePayloadSize() const;
84 
85   /// @param location The start location of the compare operation.
86   /// @param str The string to compare the bytes with.
87   /// @return True if the segment's bytes at the given location equals the str.
88   bool BytesAtLocationStartWith(size_t location, const char* str) const;
89 
90   /// @param location The start location of the search operation.
91   /// @param str The string to search for.
92   /// @return True if the segment's contains the string, starting at location.
93   bool BytesAtLocationContain(size_t location, const char* str) const;
94 
95   /// @param start_location The location at which to start the search.
96   /// @param value The byte value to search for.
97   /// @return The location in the segment's bytes of the next occurrence of the
98   ///     given byte value, starting at the indicated location, or the segment's
99   ///     range's GetEnd() location if not found.
100   size_t Find(size_t start_location, Byte value) const;
101 
102   /// @param start_location The location at which to start the search.
103   /// @param str The string to search for.
104   /// @return the location in the segment's bytes of the next occurrence of the
105   ///     given string value,  starting at the indicated location, or the
106   ///     segment's range's GetEnd() location if not found.
107   size_t Find(size_t location, const char* str) const;
108 
109   /// XMP property names have the syntax property_name="property_value".
110   /// @param segment The segment in which to look for the property name/value.
111   /// @param start_location Where to start looking for the property name.
112   /// @param property_name The name of the property to look for.
113   /// @return The string value associated with the xmp property name, or an
114   ///     empty string if the property was not found.
115   std::string ExtractXmpPropertyValue(size_t start_location,
116                                       const char* property_name) const;
117 
118   /// XMP property names have the syntax property_name="property_value".
119   /// @start_location The location in the segment to begin looking for the
120   ///     property_name=" syntax.
121   /// @return The location of the next byte following the quote, or GetEnd() if
122   ///     the property_name=" syntax was not found.
123   size_t FindXmpPropertyValueBegin(size_t start_location,
124                                    const char* property_name) const;
125 
126   /// XMP property names have the syntax property_name="property_value".
127   /// @start_location The location in the segment to begin looking for the final
128   ///     quote of the property value.
129   /// @return The location of quote that terminates the property_value, or
130   ///     GetEnd() if the final quote was not found.
131   size_t FindXmpPropertyValueEnd(size_t start_location) const;
132 
133   /// @param The DataRange to use to extract a string from the segment's bytes.
134   /// @return The string extracted from the segment at locations indicated by
135   ///     the data_range, or an empty string if the data_range is not contained
136   ///     in the segment's range, or any invalid or zero bytes are encountered.
137   std::string ExtractString(const DataRange& data_range) const;
138 
139   /// @return the JpegMarker of this segment.
GetMarker()140   JpegMarker GetMarker() const {
141     size_t marker_type_location = GetMarkerLocation() + 1;
142     // An invalid ValidatedByte has a value of 0, and a JpegMarker with a 0
143     // type value is invalid, so its ok to just grab the ValidatedByte's value.
144     return JpegMarker(GetValidatedByte(marker_type_location).value);
145   }
146 
147   /// Fills two strings with byte_count bytes from the start of the segment's
148   /// payload in a form suitable for creating a "hex dump" of the segment. Note
149   /// that if the jpeg segment has a entropy delimiter type marker, there is
150   /// technically no payload to dump. However in this case, as long as a valid
151   /// byte can be obtained from the jpeg segment's underlying data segments, a
152   /// byte value will be dumped to the strings.
153   /// @param byte_count The number of bytes to dump from the segment's payload.
154   /// @param hex_string A string that will be at most 2 * byte_count in length
155   ///     that will contain the hex values of the bytes.
156   /// @param ascii_string A string that will be at most byte_count in length
157   ///     that will contain the printable character of the bytes, or a '.' for
158   ///     non-printable byte values.
159   void GetPayloadHexDumpStrings(size_t byte_count, std::string* hex_string,
160                                 std::string* ascii_string) const;
161 
162  private:
163   /// The DataRange of the JpegSegment.
164   DataRange data_range_;
165 
166   /// The DataSegment that contains the begin of the range and possibly the
167   /// end. This DataSegment will never be null.
168   const DataSegment* begin_segment_;
169 
170   /// The DataSegment, that if not null, will contain the end location of the
171   /// JPegSegment's DataRange.
172   const DataSegment* end_segment_;
173 };
174 
175 }  // namespace image_io
176 }  // namespace photos_editing_formats
177 
178 #endif // IMAGE_IO_JPEG_JPEG_SEGMENT_H_  // NOLINT
179