1 #include "image_io/jpeg/jpeg_segment_lister.h"
2
3 #include <iomanip>
4 #include <sstream>
5 #include <string>
6
7 #include "image_io/jpeg/jpeg_marker.h"
8 #include "image_io/jpeg/jpeg_scanner.h"
9 #include "image_io/jpeg/jpeg_segment.h"
10
11 namespace photos_editing_formats {
12 namespace image_io {
13
14 /// The width of the type column.
15 constexpr size_t kTypeWidth = 5;
16
17 /// The width of the number columns.
18 constexpr size_t kNumWidth = 12;
19
20 /// The number of bytes to dump from each segment.
21 constexpr size_t kDumpCount = 16;
22
23 /// The width of the ascii dump column, including the surrounding [] brackets.
24 constexpr size_t kAscWidth = kDumpCount + 2;
25
26 /// The width of the hex dump column, including the surrounding [] brackets.
27 constexpr size_t kHexWidth = 2 * kDumpCount + 2;
28
29 using std::string;
30 using std::stringstream;
31
32 namespace {
33
34 /// @param value The value to convert to a string.
35 /// @return The value paraemter as a string of length kNumWidth.
Size2String(size_t value)36 string Size2String(size_t value) {
37 stringstream stream;
38 stream << std::setw(kNumWidth) << std::right << value;
39 return stream.str();
40 }
41
42 /// @param value The value to convert to a hex string.
43 /// @return The value paraemter as a hex string of length kNumWidth.
Size2HexString(size_t value)44 string Size2HexString(size_t value) {
45 stringstream stream;
46 stream << std::hex << std::uppercase << std::setw(kNumWidth) << std::right
47 << value;
48 return stream.str();
49 }
50
51 /// @param str The string to add brackets to.
52 /// @return The str value enclosed by square brackets.
BracketedString(const string & str)53 string BracketedString(const string& str) {
54 stringstream stream;
55 stream << '[' << str << ']';
56 return stream.str();
57 }
58
59 /// @param str The string to center.
60 /// @param width The width to center the string in.
61 /// @return A string with leading/trailing spaces added so that it is centered.
CenteredString(const string & str,size_t width)62 string CenteredString(const string& str, size_t width) {
63 if (str.length() >= width) {
64 return str;
65 }
66 size_t spacing = width - str.length();
67 size_t leading = spacing / 2;
68 size_t trailing = spacing - leading;
69 return string(leading, ' ') + str + string(trailing, ' ');
70 }
71
72 /// @param type The type value of the segment. If this value is empty, then a
73 /// divider line with dashes is created.
74 /// @param begin The begin value of the segment.
75 /// @param count The count (size) of the segment.
76 /// @param hex_string The hex dump string of the segment.
77 /// @param asc_string The ascii dump string of the segment.
78 /// @return A line with the various parameters properly spaced.
SegmentLine(string type,string begin,string count,string hex_string,string asc_string)79 string SegmentLine(string type, string begin, string count, string hex_string,
80 string asc_string) {
81 if (type.empty()) {
82 type = string(kTypeWidth, '-');
83 begin = count = string(kNumWidth, '-');
84 hex_string = string(kHexWidth, '-');
85 asc_string = string(kAscWidth, '-');
86 }
87 stringstream line_stream;
88 line_stream << std::setw(kTypeWidth) << std::left << type << " "
89 << std::setw(kNumWidth) << std::right << begin << " "
90 << std::setw(kNumWidth) << std::right << count << " "
91 << std::setw(kHexWidth) << std::right << hex_string << " "
92 << std::setw(kAscWidth) << std::right << asc_string;
93 return line_stream.str();
94 }
95
96 /// @param type The type value of the summary. If this value is empty, then a
97 /// divider line with dashes is created.
98 /// @param count The number of the segments of the given type.
99 /// @return A line with the parameters properly spaced.
SummaryLine(string type,string count)100 string SummaryLine(string type, string count) {
101 if (type.empty()) {
102 type = string(kTypeWidth, '-');
103 count = string(kNumWidth, '-');
104 }
105 stringstream line_stream;
106 line_stream << std::setw(kTypeWidth) << std::left << type << " "
107 << std::setw(kNumWidth) << std::right << count;
108 return line_stream.str();
109 }
110
111 } // namespace
112
JpegSegmentLister()113 JpegSegmentLister::JpegSegmentLister()
114 : marker_type_counts_(kJpegMarkerArraySize, 0) {}
115
Start(JpegScanner * scanner)116 void JpegSegmentLister::Start(JpegScanner* scanner) {
117 scanner->UpdateInterestingMarkerFlags(JpegMarker::Flags().set());
118 string divider_line = SegmentLine("", "", "", "", "");
119 lines_.push_back(divider_line);
120 lines_.push_back(SegmentLine("Type", "Offset", "Payload Size",
121 CenteredString("Hex Payload", kHexWidth),
122 CenteredString("Ascii Payload", kAscWidth)));
123 lines_.push_back(divider_line);
124 }
125
Process(JpegScanner * scanner,const JpegSegment & segment)126 void JpegSegmentLister::Process(JpegScanner* scanner,
127 const JpegSegment& segment) {
128 JpegMarker marker = segment.GetMarker();
129 string hex_payload, ascii_payload;
130 ++marker_type_counts_[marker.GetType()];
131 segment.GetPayloadHexDumpStrings(kDumpCount, &hex_payload, &ascii_payload);
132 lines_.push_back(SegmentLine(
133 marker.GetName(), Size2HexString(segment.GetBegin()),
134 Size2HexString(segment.GetEnd() - segment.GetBegin() - 2),
135 BracketedString(hex_payload), BracketedString(ascii_payload)));
136 }
137
Finish(JpegScanner * scanner)138 void JpegSegmentLister::Finish(JpegScanner* scanner) {
139 lines_.push_back("");
140 string divider_line = SummaryLine("", "");
141 lines_.push_back(divider_line);
142 lines_.push_back(SummaryLine("Type", "Count"));
143 lines_.push_back(divider_line);
144 int total_segments = 0;
145 for (int type = 0; type < kJpegMarkerArraySize; ++type) {
146 int count = marker_type_counts_[type];
147 if (count) {
148 total_segments += count;
149 lines_.push_back(
150 SummaryLine(JpegMarker(type).GetName(), Size2String(count)));
151 }
152 }
153 lines_.push_back(divider_line);
154 lines_.push_back(SummaryLine("TOTAL", Size2String(total_segments)));
155 }
156
157 } // namespace image_io
158 } // namespace photos_editing_formats
159