#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