File: | Tools/CmdLine/IccDumpProfile/iccDumpProfile.cpp |
Warning: | line 252, column 9 Value stored to 'pad' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | File: CmdDumpProfile.cpp |
3 | |
4 | Contains: Console app to parse and display profile contents |
5 | |
6 | Version: V1 |
7 | |
8 | Copyright: (c) see below |
9 | */ |
10 | |
11 | /* |
12 | * The ICC Software License, Version 0.2 |
13 | * |
14 | * |
15 | * Copyright (c) 2003-2012 The International Color Consortium. All rights |
16 | * reserved. |
17 | * |
18 | * Redistribution and use in source and binary forms, with or without |
19 | * modification, are permitted provided that the following conditions |
20 | * are met: |
21 | * |
22 | * 1. Redistributions of source code must retain the above copyright |
23 | * notice, this list of conditions and the following disclaimer. |
24 | * |
25 | * 2. Redistributions in binary form must reproduce the above copyright |
26 | * notice, this list of conditions and the following disclaimer in |
27 | * the documentation and/or other materials provided with the |
28 | * distribution. |
29 | * |
30 | * 3. In the absence of prior written permission, the names "ICC" and "The |
31 | * International Color Consortium" must not be used to imply that the |
32 | * ICC organization endorses or promotes products derived from this |
33 | * software. |
34 | * |
35 | * |
36 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
37 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
38 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
39 | * DISCLAIMED. IN NO EVENT SHALL THE INTERNATIONAL COLOR CONSORTIUM OR |
40 | * ITS CONTRIBUTING MEMBERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
41 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
42 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
43 | * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
44 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
45 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
46 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
47 | * SUCH DAMAGE. |
48 | * ==================================================================== |
49 | * |
50 | * This software consists of voluntary contributions made by many |
51 | * individuals on behalf of the The International Color Consortium. |
52 | * |
53 | * |
54 | * Membership in the ICC is encouraged when this software is used for |
55 | * commercial purposes. |
56 | * |
57 | * |
58 | * For more information on The International Color Consortium, please |
59 | * see <http://www.color.org/>. |
60 | * |
61 | * |
62 | */ |
63 | |
64 | ////////////////////////////////////////////////////////////////////// |
65 | // HISTORY: |
66 | // |
67 | // -Initial implementation by Max Derhak 5-15-2003 |
68 | // |
69 | ////////////////////////////////////////////////////////////////////// |
70 | |
71 | |
72 | #include <stdio.h> |
73 | #include <cstring> |
74 | #include "IccProfile.h" |
75 | #include "IccTag.h" |
76 | #include "IccUtil.h" |
77 | |
78 | void DumpTag(CIccProfile *pIcc, icTagSignature sig) |
79 | { |
80 | CIccTag *pTag = pIcc->FindTag(sig); |
81 | char buf[64]; |
82 | CIccInfo Fmt; |
83 | |
84 | std::string contents; |
85 | |
86 | if (pTag) { |
87 | printf("\nContents of %s tag (%s)\n", Fmt.GetTagSigName(sig), icGetSig(buf, sig)); |
88 | printf("Type: "); |
89 | if (pTag->IsArrayType()) { |
90 | printf("Array of "); |
91 | } |
92 | printf("%s\n", Fmt.GetTagTypeSigName(pTag->GetType())); |
93 | pTag->Describe(contents); |
94 | fwrite(contents.c_str(), contents.length(), 1, stdout__stdoutp); |
95 | } |
96 | else { |
97 | printf("Tag (%s) not found in profile\n", icGetSig(buf, sig)); |
98 | } |
99 | } |
100 | |
101 | int main(int argc, char* argv[]) |
102 | { |
103 | int nArg = 1; |
104 | |
105 | if (argc<=1) { |
106 | print_usage: |
107 | printf("Usage: iccDumpProfile {-v} profile {tagId to dump/\"ALL\"}\n"); |
108 | printf("\nThe -v option causes profile validation to be performed.\n"); |
109 | return -1; |
110 | } |
111 | |
112 | CIccProfile *pIcc; |
113 | std::string sReport; |
114 | icValidateStatus nStatus = icValidateOK; |
115 | bool bDumpValidation = false; |
116 | |
117 | if (!strncmp(argv[1], "-V", 2) || !strncmp(argv[1], "-v", 2)) { |
118 | if (argc<=2) |
119 | goto print_usage; |
120 | |
121 | nArg = 2; |
122 | |
123 | pIcc = ValidateIccProfile(argv[nArg], sReport, nStatus); |
124 | bDumpValidation = true; |
125 | } |
126 | else |
127 | pIcc = OpenIccProfile(argv[nArg]); |
128 | |
129 | if (!pIcc) { |
130 | printf("Unable to open '%s'\n", argv[nArg]); |
131 | } |
132 | else { |
133 | icHeader *pHdr = &pIcc->m_Header; |
134 | CIccInfo Fmt; |
135 | char buf[64]; |
136 | |
137 | printf("Profile: '%s'\n", argv[nArg]); |
138 | if(Fmt.IsProfileIDCalculated(&pHdr->profileID)) |
139 | printf("Profile ID: %s\n", Fmt.GetProfileID(&pHdr->profileID)); |
140 | else |
141 | printf("Profile ID: Profile ID not calculated.\n"); |
142 | printf("Size: %d(0x%x) bytes\n", pHdr->size, pHdr->size); |
143 | |
144 | printf("\nHeader\n"); |
145 | printf( "------\n"); |
146 | printf("Attributes: %s\n", Fmt.GetDeviceAttrName(pHdr->attributes)); |
147 | printf("Cmm: %s\n", Fmt.GetCmmSigName((icCmmSignature)(pHdr->cmmId))); |
148 | printf("Creation Date: %d/%d/%d %02u:%02u:%02u\n", |
149 | pHdr->date.month, pHdr->date.day, pHdr->date.year, |
150 | pHdr->date.hours, pHdr->date.minutes, pHdr->date.seconds); |
151 | printf("Creator: %s\n", icGetSig(buf, pHdr->creator)); |
152 | printf("Data Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->colorSpace)); |
153 | printf("Flags %s\n", Fmt.GetProfileFlagsName(pHdr->flags)); |
154 | printf("PCS Color Space: %s\n", Fmt.GetColorSpaceSigName(pHdr->pcs)); |
155 | printf("Platform: %s\n", Fmt.GetPlatformSigName(pHdr->platform)); |
156 | printf("Rendering Intent: %s\n", Fmt.GetRenderingIntentName((icRenderingIntent)(pHdr->renderingIntent))); |
157 | printf("Profile Class: %s\n", Fmt.GetProfileClassSigName(pHdr->deviceClass)); |
158 | if (pHdr->deviceSubClass) |
159 | printf("Profile SubClass: %s\n", icGetSig(buf, pHdr->deviceSubClass)); |
160 | else |
161 | printf("Profile SubClass: Not Defined\n"); |
162 | printf("Version: %s\n", Fmt.GetVersionName(pHdr->version)); |
163 | if (pHdr->version >= icVersionNumberV50x05000000 && pHdr->deviceSubClass) { |
164 | printf("SubClass Version: %s\n", Fmt.GetSubClassVersionName(pHdr->version)); |
165 | } |
166 | printf("Illuminant: X=%.4lf, Y=%.4lf, Z=%.4lf\n", |
167 | icFtoD(pHdr->illuminant.X), |
168 | icFtoD(pHdr->illuminant.Y), |
169 | icFtoD(pHdr->illuminant.Z)); |
170 | printf("Spectral PCS: %s\n", Fmt.GetSpectralColorSigName(pHdr->spectralPCS)); |
171 | if (pHdr->spectralRange.start || pHdr->spectralRange.end || pHdr->spectralRange.steps) { |
172 | printf("Spectral PCS Range: start=%.1fnm, end=%.1fnm, steps=%d\n", |
173 | icF16toF(pHdr->spectralRange.start), |
174 | icF16toF(pHdr->spectralRange.end), |
175 | pHdr->spectralRange.steps); |
176 | } |
177 | else { |
178 | printf("Spectral PCS Range: Not Defined\n"); |
179 | } |
180 | |
181 | if (pHdr->biSpectralRange.start || pHdr->biSpectralRange.end || pHdr->biSpectralRange.steps) { |
182 | printf("BiSpectral Range: start=%.1fnm, end=%.1fnm, steps=%d\n", |
183 | icF16toF(pHdr->biSpectralRange.start), |
184 | icF16toF(pHdr->biSpectralRange.end), |
185 | pHdr->biSpectralRange.steps); |
186 | } |
187 | else { |
188 | printf("BiSpectral Range: Not Defined\n"); |
189 | } |
190 | if (pHdr->mcs) { |
191 | printf("MCS Color Space: %s\n", Fmt.GetColorSpaceSigName((icColorSpaceSignature)pHdr->mcs)); |
192 | } |
193 | else { |
194 | printf("MCS Color Space: Not Defined\n"); |
195 | } |
196 | |
197 | printf("\nProfile Tags\n"); |
198 | printf( "------------\n"); |
199 | |
200 | printf("%28s ID %8s\t%8s\t%8s\n", "Tag", "Offset", "Size", "Pad"); |
201 | printf("%28s ------ %8s\t%8s\t%8s\n", "----", "------", "----", "---"); |
202 | |
203 | int n, closest, pad; |
204 | TagEntryList::iterator i, j; |
205 | |
206 | // n is number of Tags in Tag Table |
207 | for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++) { |
208 | // Find closest tag after this tag, by scanning all offsets of other tags |
209 | closest = pHdr->size; |
210 | for (j = pIcc->m_Tags->begin(); j != pIcc->m_Tags->end(); j++) { |
211 | if ((i != j) && (j->TagInfo.offset >= i->TagInfo.offset + i->TagInfo.size) && ((int)j->TagInfo.offset <= closest)) { |
212 | closest = j->TagInfo.offset; |
213 | } |
214 | } |
215 | // Number of actual padding bytes between this tag and closest neighbour (or EOF) |
216 | // Should be 0-3 if compliant. Negative number if tags overlap! |
217 | pad = closest - i->TagInfo.offset - i->TagInfo.size; |
218 | |
219 | printf("%28s %s %8d\t%8d\t%8d\n", Fmt.GetTagSigName(i->TagInfo.sig), |
220 | icGetSig(buf, i->TagInfo.sig, false), i->TagInfo.offset, i->TagInfo.size, pad); |
221 | } |
222 | |
223 | printf("\n"); |
224 | |
225 | // Check additional details if doing detailed validation: |
226 | // - First tag data offset is immediately after the Tag Table |
227 | // - Tag data offsets are all 4-byte aligned |
228 | // - Tag data should be tightly abutted with adjacent tags (or the end of the Tag Table) |
229 | // (note that tag data can be reused by multiple tags and tags do NOT have to be order) |
230 | // - Last tag also has to be padded and thus file size is always a multiple of 4. See clause |
231 | // 7.2.1, bullet (c) of ICC.1:2010 and ICC.2:2019 specs. |
232 | // - Tag offset + Tag Size should never go beyond EOF |
233 | // - Multiple tags can reuse data and this is NOT reported as it is perfectly valid and |
234 | // occurs in real-world ICC profiles |
235 | // - Tags with overlapping tag data are considered highly suspect (but officially valid) |
236 | // - 1-3 padding bytes after each tag's data need to be all zero *** NOT DONE - TODO *** |
237 | if (bDumpValidation) { |
238 | char str[256]; |
239 | int rndup, smallest_offset = pHdr->size; |
240 | |
241 | // File size is required to be a multiple of 4 bytes according to clause 7.2.1 bullet (c): |
242 | // "all tagged element data, including the last, shall be padded by no more than three |
243 | // following pad bytes to reach a 4 - byte boundary" |
244 | if (pHdr->size % 4 != 0) { |
245 | sReport += icMsgValidateNonCompliant; |
246 | sReport += "File size is not a multiple of 4 bytes (last tag needs padding?).\r\n"; |
247 | nStatus = icMaxStatus(nStatus, icValidateNonCompliant); |
248 | } |
249 | |
250 | for (i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++) { |
251 | rndup = 4 * ((i->TagInfo.size + 3) / 4); // Round up to a 4-byte aligned size as per ICC spec |
252 | pad = rndup - i->TagInfo.size; // Optimal smallest number of bytes of padding for this tag (0-3) |
Value stored to 'pad' is never read | |
253 | |
254 | // Is the Tag offset + Tag Size beyond EOF? |
255 | if (i->TagInfo.offset + i->TagInfo.size > pHdr->size) { |
256 | sReport += icMsgValidateNonCompliant; |
257 | sprintf(str, "Tag %s (offset %d, size %d) ends beyond EOF.\r\n", |
258 | Fmt.GetTagSigName(i->TagInfo.sig), i->TagInfo.offset, i->TagInfo.size); |
259 | sReport += str; |
260 | nStatus = icMaxStatus(nStatus, icValidateNonCompliant); |
261 | } |
262 | |
263 | // Is it the first tag data in the file? |
264 | if ((int)i->TagInfo.offset < smallest_offset) { |
265 | smallest_offset = (int)i->TagInfo.offset; |
266 | } |
267 | |
268 | // Find closest tag after this tag, by scanning all other tag offsets |
269 | closest = pHdr->size; |
270 | for (j=pIcc->m_Tags->begin(); j!=pIcc->m_Tags->end(); j++) { |
271 | if ((i!=j) && (j->TagInfo.offset > i->TagInfo.offset) && ((int)j->TagInfo.offset <= closest)) { |
272 | closest = j->TagInfo.offset; |
273 | } |
274 | } |
275 | |
276 | // Check if closest tag after this tag is less than offset+size - in which case it overlaps! Ignore last tag. |
277 | if ((closest < (int)i->TagInfo.offset + (int)i->TagInfo.size) && (closest < (int)pHdr->size)) { |
278 | sReport += icMsgValidateWarning; |
279 | sprintf(str, "Tag %s (offset %d, size %d) overlaps with following tag data starting at offset %d.\r\n", |
280 | Fmt.GetTagSigName(i->TagInfo.sig), i->TagInfo.offset, i->TagInfo.size, closest); |
281 | sReport += str; |
282 | nStatus = icMaxStatus(nStatus, icValidateWarning); |
283 | } |
284 | |
285 | // Check for gaps between tag data (accounting for 4-byte alignment) |
286 | if (closest > (int)i->TagInfo.offset + rndup) { |
287 | sReport += icMsgValidateWarning; |
288 | sprintf(str, "Tag %s (size %d) is followed by %d unnecessary additional bytes (from offset %d).\r\n", |
289 | Fmt.GetTagSigName(i->TagInfo.sig), i->TagInfo.size, closest-(i->TagInfo.offset+rndup), (i->TagInfo.offset+rndup)); |
290 | sReport += str; |
291 | nStatus = icMaxStatus(nStatus, icValidateWarning); |
292 | } |
293 | } |
294 | |
295 | // Clause 7.2.1, bullet (b): "the first set of tagged element data shall immediately follow the tag table" |
296 | // 1st tag offset should be = Header (128) + Tag Count (4) + Tag Table (n*12) |
297 | if ((n > 0) && (smallest_offset > 128 + 4 + (n * 12))) { |
298 | sReport += icMsgValidateNonCompliant; |
299 | sprintf(str, "First tag data is at offset %d rather than immediately after tag table (offset %d).\r\n", |
300 | smallest_offset, 128 + 4 + (n * 12)); |
301 | sReport += str; |
302 | nStatus = icMaxStatus(nStatus, icValidateNonCompliant); |
303 | } |
304 | } |
305 | |
306 | if (argc>nArg+1) { |
307 | if (!stricmpstrcasecmp(argv[nArg+1], "ALL")) { |
308 | for (i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++) { |
309 | DumpTag(pIcc, i->TagInfo.sig); |
310 | } |
311 | } |
312 | else { |
313 | DumpTag(pIcc, (icTagSignature)icGetSigVal(argv[nArg+1])); |
314 | } |
315 | } |
316 | } |
317 | |
318 | int nValid = 0; |
319 | |
320 | if (bDumpValidation) { |
321 | printf("\nValidation Report\n"); |
322 | printf( "-----------------\n"); |
323 | switch (nStatus) { |
324 | case icValidateOK: |
325 | printf("Profile is valid\n\n"); |
326 | break; |
327 | case icValidateWarning: |
328 | printf("Profile has warning(s)\n\n"); |
329 | break; |
330 | case icValidateNonCompliant: |
331 | printf("Profile violates ICC specification\n\n"); |
332 | break; |
333 | case icValidateCriticalError: |
334 | printf("Profile has Critical Error(s) that violate ICC specification.\n\n"); |
335 | nValid = -1; |
336 | break; |
337 | default: |
338 | printf("Profile has unknown status.\n\n"); |
339 | nValid = -2; |
340 | break; |
341 | } |
342 | fwrite(sReport.c_str(), sReport.length(), 1, stdout__stdoutp); |
343 | } |
344 | |
345 | delete pIcc; |
346 | |
347 | return nValid; |
348 | } |
349 |