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