114{
115#if defined(MEMORY_LEAK_CHECK) && defined(_DEBUG)
116#if defined(WIN32) || defined(_WIN32)
117#if 0
118
119 _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
120 _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
121 _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
122 _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
123#endif
124 int tmp = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
125 tmp = tmp | _CRTDBG_LEAK_CHECK_DF | _CRTDBG_ALLOC_MEM_DF;
126 _CrtSetDbgFlag(tmp);
127
128#elif __GLIBC__
129 mcheck(NULL);
130#endif
131#endif
132
133 int nArg = 1;
134 long int verbosity = 100;
135
136 if (argc <= 1) {
137print_usage:
138 printf("Usage: iccDumpProfile {-v} {int} profile {tagId to dump/\"ALL\"}\n");
140 printf("\nThe -v option causes profile validation to be performed."
141 "\nThe optional integer parameter specifies verboseness of output (1-100, default=100).\n");
142 printf(
"iccDumpProfile built with IccProfLib version " ICCPROFLIBVER "\n\n");
143
144 return -1;
145 }
146
147 CIccProfile *pIcc;
148 std::string sReport;
150 bool bDumpValidation = false;
151
152 if (!strncmp(argv[1], "-V", 2) || !strncmp(argv[1], "-v", 2)) {
153 nArg++;
154 if (argc <= nArg)
155 goto print_usage;
156
157
158 char *endptr = nullptr;
159 verbosity = strtol(argv[nArg], &endptr, 10);
160 if ((verbosity != 0L) && (errno != ERANGE) && ((endptr == nullptr) || (*endptr == '\0'))) {
161
162 if (verbosity < 0)
163 verbosity = 1;
164 else if (verbosity > 100)
165 verbosity = 100;
166 nArg++;
167 if (argc <= nArg)
168 goto print_usage;
169 }
170 else if (argv[nArg] == endptr) {
171 verbosity = 100;
172 }
173
175 bDumpValidation = true;
176 }
177 else {
178
179 char* endptr = nullptr;
180 verbosity = strtol(argv[nArg], &endptr, 10);
181 if ((verbosity != 0L) && (errno != ERANGE) && ((endptr == nullptr) || (*endptr == '\0'))) {
182
183 if (verbosity < 0)
184 verbosity = 1;
185 else if (verbosity > 100)
186 verbosity = 100;
187 nArg++;
188 if (argc <= nArg)
189 goto print_usage;
190 }
191
193 }
194
197
198
199 printf(
"Built with IccProfLib version " ICCPROFLIBVER "\n\n");
200 if (!pIcc) {
201 printf("Unable to parse '%s' as ICC profile!\n", argv[nArg]);
203 }
204 else {
205 pHdr = &pIcc->m_Header;
206 char buf[64];
207
208 printf("Profile: '%s'\n", argv[nArg]);
211 else
212 printf("Profile ID: Profile ID not calculated.\n");
213 printf(
"Size: %d (0x%x) bytes\n", pHdr->
size, pHdr->
size);
214
215 printf("\nHeader\n");
216 printf( "------\n");
219 printf("Creation Date: %d/%d/%d (M/D/Y) %02u:%02u:%02u\n",
232 else
233 printf("Profile SubClass: Not Defined\n");
237 }
238 printf("Illuminant: X=%.4lf, Y=%.4lf, Z=%.4lf\n",
244 printf("Spectral PCS Range: start=%.1fnm, end=%.1fnm, steps=%d\n",
248 }
249 else {
250 printf("Spectral PCS Range: Not Defined\n");
251 }
252
254 printf("BiSpectral Range: start=%.1fnm, end=%.1fnm, steps=%d\n",
258 }
259 else {
260 printf("BiSpectral Range: Not Defined\n");
261 }
262
265 }
266 else {
267 printf("MCS Color Space: Not Defined\n");
268 }
269
270 printf("\nProfile Tags\n");
271 printf( "------------\n");
272
273 printf("%28s ID %8s\t%8s\t%8s\n", "Tag", "Offset", "Size", "Pad");
274 printf("%28s ------ %8s\t%8s\t%8s\n", "----", "------", "----", "---");
275
276 int n, closest, pad;
277 TagEntryList::iterator i, j;
278
279
280 for (n=0, i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++, n++) {
281
282 closest = pHdr->
size;
283 for (j = pIcc->m_Tags->begin(); j != pIcc->m_Tags->end(); j++) {
284 if ((i != j) && (j->TagInfo.offset >= i->TagInfo.offset + i->TagInfo.size) && ((int)j->TagInfo.offset <= closest)) {
285 closest = j->TagInfo.offset;
286 }
287 }
288
289
290 pad = closest - i->TagInfo.offset - i->TagInfo.size;
291
292 printf(
"%28s %s %8d\t%8d\t%8d\n", Fmt.
GetTagSigName(i->TagInfo.sig),
293 icGetSig(buf, i->TagInfo.sig,
false), i->TagInfo.offset, i->TagInfo.size, pad);
294 }
295
296 printf("\n");
297
298
299
300 int m;
301 for (n=0, i = pIcc->m_Tags->begin(); i != pIcc->m_Tags->end(); i++, n++)
302 for (m=0, j = pIcc->m_Tags->begin(); j != pIcc->m_Tags->end(); j++, m++)
303 if ((i != j) && (i->TagInfo.sig == j->TagInfo.sig)) {
304 printf(
"%28s is duplicated at positions %d and %d!\n", Fmt.
GetTagSigName(i->TagInfo.sig), n, m);
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321 if (bDumpValidation) {
322 char str[256];
323 int rndup, smallest_offset = pHdr->
size;
324
325
326
327
330 sReport += "File size is not a multiple of 4 bytes (last tag needs padding?).\n";
332 }
333
334 for (i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++) {
335 rndup = 4 * ((i->TagInfo.size + 3) / 4);
336 pad = rndup - i->TagInfo.size;
337
338
339 if (i->TagInfo.offset + i->TagInfo.size > pHdr->
size) {
341 sprintf(str, "Tag %s (offset %d, size %d) ends beyond EOF.\n",
342 Fmt.
GetTagSigName(i->TagInfo.sig), i->TagInfo.offset, i->TagInfo.size);
343 sReport += str;
345 }
346
347
348 if ((int)i->TagInfo.offset < smallest_offset) {
349 smallest_offset = (int)i->TagInfo.offset;
350 }
351
352
353 closest = pHdr->
size;
354 for (j=pIcc->m_Tags->begin(); j!=pIcc->m_Tags->end(); j++) {
355 if ((i!=j) && (j->TagInfo.offset > i->TagInfo.offset) && ((int)j->TagInfo.offset <= closest)) {
356 closest = j->TagInfo.offset;
357 }
358 }
359
360
361 if ((closest < (
int)i->TagInfo.offset + (int)i->TagInfo.size) && (closest < (int)pHdr->
size)) {
363 sprintf(str, "Tag %s (offset %d, size %d) overlaps with following tag data starting at offset %d.\n",
364 Fmt.
GetTagSigName(i->TagInfo.sig), i->TagInfo.offset, i->TagInfo.size, closest);
365 sReport += str;
367 }
368
369
370 if (closest > (int)i->TagInfo.offset + rndup) {
372 sprintf(str, "Tag %s (size %d) is followed by %d unnecessary additional bytes (from offset %d).\n",
373 Fmt.
GetTagSigName(i->TagInfo.sig), i->TagInfo.size, closest-(i->TagInfo.offset+rndup), (i->TagInfo.offset+rndup));
374 sReport += str;
376 }
377 }
378
379
380
381 if ((n > 0) && (smallest_offset > 128 + 4 + (n * 12))) {
383 sprintf(str, "First tag data is at offset %d rather than immediately after tag table (offset %d).\n",
384 smallest_offset, 128 + 4 + (n * 12));
385 sReport += str;
387 }
388 }
389
390 if (argc>nArg+1) {
391 if (!
stricmp(argv[nArg+1],
"ALL")) {
392 for (i=pIcc->m_Tags->begin(); i!=pIcc->m_Tags->end(); i++) {
393 DumpTag(pIcc, i->TagInfo.sig, verbosity);
394 }
395 }
396 else {
398 }
399 }
400 }
401
402 int nValid = 0;
403
404 if (bDumpValidation) {
405 printf("\nValidation Report\n");
406 printf( "-----------------\n");
407 switch (nStatus) {
409 printf("Profile is valid");
410 if (pHdr)
412 break;
414 printf("Profile has warning(s)");
415 if (pHdr)
417 break;
419 printf("Profile violates ICC specification");
420 if (pHdr)
422 break;
424 printf("Profile has Critical Error(s) that violate ICC specification");
425 if (pHdr)
427 nValid = -1;
428 break;
429 default:
430 printf("Profile has unknown status!");
431 nValid = -2;
432 break;
433 }
434 }
435 printf("\n\n");
436
437 sReport += "\n";
438 fwrite(sReport.c_str(), sReport.length(), 1, stdout);
439
440 delete pIcc;
441
442#if defined(_DEBUG) || defined(DEBUG)
443 printf("EXIT %d\n", nValid);
444#endif
445 return nValid;
446}
@ icValidateCriticalError
CIccProfile * ValidateIccProfile(CIccIO *pIO, std::string &sReport, icValidateStatus &nStatus)
Name: ValidateIccProfile.
CIccProfile * OpenIccProfile(const icChar *szFilename, bool bUseSubProfile)
Name: OpenIccProfile.
icValidateStatus icMaxStatus(icValidateStatus s1, icValidateStatus s2)
Name: icMaxStatus.
const char * icMsgValidateWarning
icFloatNumber icFtoD(icS15Fixed16Number num)
const char * icMsgValidateNonCompliant
icUInt32Number icGetSigVal(const icChar *pBuf)
icFloatNumber icF16toF(icFloat16Number num)
bool IsProfileIDCalculated(icProfileID *profileID)
const icChar * GetVersionName(icUInt32Number val)
const icChar * GetSpectralColorSigName(icSpectralColorSignature sig)
const icChar * GetCmmSigName(icCmmSignature sig)
const icChar * GetProfileClassSigName(icProfileClassSignature sig)
const icChar * GetProfileFlagsName(icUInt32Number val, bool bCheckMCS=false)
const icChar * GetPlatformSigName(icPlatformSignature sig)
const icChar * GetProfileID(icProfileID *profileID)
const icChar * GetColorSpaceSigName(icColorSpaceSignature sig)
const icChar * GetDeviceAttrName(icUInt64Number val)
const icChar * GetSubClassVersionName(icUInt32Number val)
const icChar * GetRenderingIntentName(icRenderingIntent val, bool bIsV5=false)
void DumpTag(CIccProfile *pIcc, icTagSignature sig, int nVerboseness)