xref: /aosp_15_r20/external/image_io/src/jpeg/jpeg_scanner.cc (revision ca0779eb572efbbfda2e47f806647c3c7eeea8c3)
1*ca0779ebSJerome Gaillard #include "image_io/jpeg/jpeg_scanner.h"
2*ca0779ebSJerome Gaillard 
3*ca0779ebSJerome Gaillard #include <sstream>
4*ca0779ebSJerome Gaillard 
5*ca0779ebSJerome Gaillard #include "image_io/base/message_handler.h"
6*ca0779ebSJerome Gaillard #include "image_io/jpeg/jpeg_segment.h"
7*ca0779ebSJerome Gaillard 
8*ca0779ebSJerome Gaillard namespace photos_editing_formats {
9*ca0779ebSJerome Gaillard namespace image_io {
10*ca0779ebSJerome Gaillard 
11*ca0779ebSJerome Gaillard using std::stringstream;
12*ca0779ebSJerome Gaillard 
13*ca0779ebSJerome Gaillard /// The minimum size for the DataSegments requested from the DataSource. Using
14*ca0779ebSJerome Gaillard /// this value will guarentee that a JpegSegment will occupy at most two
15*ca0779ebSJerome Gaillard /// DataSegments.
16*ca0779ebSJerome Gaillard const size_t kMinBufferDataRequestSize = 0x10000;
17*ca0779ebSJerome Gaillard 
Run(DataSource * data_source,JpegSegmentProcessor * segment_processor)18*ca0779ebSJerome Gaillard void JpegScanner::Run(DataSource* data_source,
19*ca0779ebSJerome Gaillard                       JpegSegmentProcessor* segment_processor) {
20*ca0779ebSJerome Gaillard   if (data_source_) {
21*ca0779ebSJerome Gaillard     // The Run() function is already active.
22*ca0779ebSJerome Gaillard     return;
23*ca0779ebSJerome Gaillard   }
24*ca0779ebSJerome Gaillard   data_source_ = data_source;
25*ca0779ebSJerome Gaillard   segment_processor_ = segment_processor;
26*ca0779ebSJerome Gaillard   current_location_ = 0;
27*ca0779ebSJerome Gaillard   done_ = false;
28*ca0779ebSJerome Gaillard   has_error_ = false;
29*ca0779ebSJerome Gaillard   data_source_->Reset();
30*ca0779ebSJerome Gaillard   current_segment_ = data_source_->GetDataSegment(current_location_,
31*ca0779ebSJerome Gaillard                                                   kMinBufferDataRequestSize);
32*ca0779ebSJerome Gaillard   segment_processor_->Start(this);
33*ca0779ebSJerome Gaillard   FindAndProcessSegments();
34*ca0779ebSJerome Gaillard   segment_processor_->Finish(this);
35*ca0779ebSJerome Gaillard   data_source_ = nullptr;
36*ca0779ebSJerome Gaillard   segment_processor_ = nullptr;
37*ca0779ebSJerome Gaillard   current_segment_.reset();
38*ca0779ebSJerome Gaillard   next_segment_.reset();
39*ca0779ebSJerome Gaillard }
40*ca0779ebSJerome Gaillard 
FindAndProcessSegments()41*ca0779ebSJerome Gaillard void JpegScanner::FindAndProcessSegments() {
42*ca0779ebSJerome Gaillard   while (!IsDone() && !HasError()) {
43*ca0779ebSJerome Gaillard     size_t begin_segment_location =
44*ca0779ebSJerome Gaillard         current_segment_->Find(current_location_, JpegMarker::kStart);
45*ca0779ebSJerome Gaillard     if (begin_segment_location == current_segment_->GetEnd()) {
46*ca0779ebSJerome Gaillard       GetNextSegment();
47*ca0779ebSJerome Gaillard       if (next_segment_) {
48*ca0779ebSJerome Gaillard         current_location_ =
49*ca0779ebSJerome Gaillard             std::max(current_location_, next_segment_->GetBegin());
50*ca0779ebSJerome Gaillard         current_segment_ = next_segment_;
51*ca0779ebSJerome Gaillard         next_segment_.reset();
52*ca0779ebSJerome Gaillard         continue;
53*ca0779ebSJerome Gaillard       }
54*ca0779ebSJerome Gaillard       SetDone();
55*ca0779ebSJerome Gaillard       break;
56*ca0779ebSJerome Gaillard     }
57*ca0779ebSJerome Gaillard     size_t payload_size = 0;
58*ca0779ebSJerome Gaillard     JpegMarker marker(
59*ca0779ebSJerome Gaillard         GetByte(begin_segment_location + JpegMarker::kTypeOffset));
60*ca0779ebSJerome Gaillard     if (marker.IsValid() && !HasError()) {
61*ca0779ebSJerome Gaillard       payload_size = GetPayloadSize(marker, begin_segment_location);
62*ca0779ebSJerome Gaillard       if (marker.IsValid() && interesting_marker_flags_[marker.GetType()]) {
63*ca0779ebSJerome Gaillard         size_t end_segment_location =
64*ca0779ebSJerome Gaillard             begin_segment_location + JpegMarker::kLength + payload_size;
65*ca0779ebSJerome Gaillard         GetByte(end_segment_location - 1);
66*ca0779ebSJerome Gaillard         if (!HasError()) {
67*ca0779ebSJerome Gaillard           JpegSegment segment(begin_segment_location, end_segment_location,
68*ca0779ebSJerome Gaillard                               current_segment_.get(), next_segment_.get());
69*ca0779ebSJerome Gaillard           segment_processor_->Process(this, segment);
70*ca0779ebSJerome Gaillard         }
71*ca0779ebSJerome Gaillard       }
72*ca0779ebSJerome Gaillard     }
73*ca0779ebSJerome Gaillard     current_location_ =
74*ca0779ebSJerome Gaillard         begin_segment_location + JpegMarker::kLength + payload_size;
75*ca0779ebSJerome Gaillard   }
76*ca0779ebSJerome Gaillard }
77*ca0779ebSJerome Gaillard 
GetPayloadSize(const JpegMarker & marker,size_t begin_location)78*ca0779ebSJerome Gaillard size_t JpegScanner::GetPayloadSize(const JpegMarker& marker,
79*ca0779ebSJerome Gaillard                                    size_t begin_location) {
80*ca0779ebSJerome Gaillard   if (marker.HasVariablePayloadSize()) {
81*ca0779ebSJerome Gaillard     return (GetByte(begin_location + JpegMarker::kLength) << 8) |
82*ca0779ebSJerome Gaillard            GetByte(begin_location + JpegMarker::kLength + 1);
83*ca0779ebSJerome Gaillard   } else {
84*ca0779ebSJerome Gaillard     return 0;
85*ca0779ebSJerome Gaillard   }
86*ca0779ebSJerome Gaillard }
87*ca0779ebSJerome Gaillard 
GetValidatedByte(size_t location)88*ca0779ebSJerome Gaillard ValidatedByte JpegScanner::GetValidatedByte(size_t location) {
89*ca0779ebSJerome Gaillard   if (current_segment_->Contains(location)) {
90*ca0779ebSJerome Gaillard     return current_segment_->GetValidatedByte(location);
91*ca0779ebSJerome Gaillard   }
92*ca0779ebSJerome Gaillard   GetNextSegment();
93*ca0779ebSJerome Gaillard   if (next_segment_ && next_segment_->Contains(location)) {
94*ca0779ebSJerome Gaillard     return next_segment_->GetValidatedByte(location);
95*ca0779ebSJerome Gaillard   }
96*ca0779ebSJerome Gaillard   if (message_handler_) {
97*ca0779ebSJerome Gaillard     stringstream sstream;
98*ca0779ebSJerome Gaillard     sstream << location;
99*ca0779ebSJerome Gaillard     message_handler_->ReportMessage(Message::kPrematureEndOfDataError,
100*ca0779ebSJerome Gaillard                                     sstream.str());
101*ca0779ebSJerome Gaillard   }
102*ca0779ebSJerome Gaillard   return InvalidByte();
103*ca0779ebSJerome Gaillard }
104*ca0779ebSJerome Gaillard 
GetByte(size_t location)105*ca0779ebSJerome Gaillard Byte JpegScanner::GetByte(size_t location) {
106*ca0779ebSJerome Gaillard   ValidatedByte validated_byte = GetValidatedByte(location);
107*ca0779ebSJerome Gaillard   if (validated_byte.is_valid) {
108*ca0779ebSJerome Gaillard     return validated_byte.value;
109*ca0779ebSJerome Gaillard   }
110*ca0779ebSJerome Gaillard   has_error_ = true;
111*ca0779ebSJerome Gaillard   return 0;
112*ca0779ebSJerome Gaillard }
113*ca0779ebSJerome Gaillard 
GetNextSegment()114*ca0779ebSJerome Gaillard void JpegScanner::GetNextSegment() {
115*ca0779ebSJerome Gaillard   if (!next_segment_ && current_segment_) {
116*ca0779ebSJerome Gaillard     next_segment_ = data_source_->GetDataSegment(current_segment_->GetEnd(),
117*ca0779ebSJerome Gaillard                                                  kMinBufferDataRequestSize);
118*ca0779ebSJerome Gaillard   }
119*ca0779ebSJerome Gaillard }
120*ca0779ebSJerome Gaillard 
121*ca0779ebSJerome Gaillard }  // namespace image_io
122*ca0779ebSJerome Gaillard }  // namespace photos_editing_formats
123