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