Files
argyllcms/icc/iccdump.c
T
2026-08-20 20:28:40 +01:00

333 lines
8.4 KiB
C

/*
* International Color Consortium Format Library (icclib)
* File dump utility.
*
* Author: Graeme W. Gill
* Date: 1999/11/29
* Version: 2.15
*
* Copyright 1997 - 2012 Graeme W. Gill
*
* This material is licensed with an "MIT" free use license:-
* see the License4.txt file in this directory for licensing details.
*/
/*
* TTBD:
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include "icc.h"
void error(char *fmt, ...), warning(char *fmt, ...);
void usage(void) {
fprintf(stderr,"Dump an ICC file in human readable form, V%s\n",ICCLIB_VERSION_STR);
fprintf(stderr,"Author: Graeme W. Gill\n");
fprintf(stderr,"usage: iccdump [-v level] [-t tagname] [-s] infile\n");
fprintf(stderr," -v level Verbose level 1-3 (default 2)\n");
fprintf(stderr," -t tag Dump this tag only (can be used multiple times)\n");
fprintf(stderr," -s Search for embedded profile\n");
fprintf(stderr," -i Check V4 ID value\n");
fprintf(stderr," -w Warn of ICC format problems to stdout\n");
fprintf(stderr," -W Warn of ICC format problems to stderr\n");
fprintf(stderr," -S Be strict about ICC format\n");
exit(1);
}
FILE *warnout;
/* Warning callback function */
void dump_warning(icc *p, int err, const char *format, va_list vp) {
fprintf(warnout, "Warning (0x%x): ",err);
vfprintf(warnout, format, vp);
fprintf(warnout, "\n");
}
#define MXTGNMS 30
int
main(int argc, char *argv[]) {
int fa,nfa; /* argument we're looking at */
static char in_name[MAXNAMEL+1];
int ntag_names = 0;
char tag_names[MXTGNMS][5];
int verb = 2; /* Default = moderate (some from individual tags) */
int search = 0;
int chid = 0; /* Check V4 ID */
int strict = 0; /* Be strict about ICC format */
int warnings = 0; /* Warn of format problems */
int ecount = 1; /* Embedded count */
int offset = 0; /* Offset to read profile from */
int found;
icmErr err = { 0, { '\000' }};
icmFile *fp, *op;
icc *icco;
int rv = 0;
if (argc < 2)
usage();
/* Process the arguments */
for(fa = 1;fa < argc;fa++) {
nfa = fa; /* skip to nfa if next argument is used */
if (argv[fa][0] == '-') { /* Look for any flags */
char *na = NULL; /* next argument after flag, null if none */
if (argv[fa][2] != '\000')
na = &argv[fa][2]; /* next is directly after flag */
else {
if ((fa+1) < argc) {
if (argv[fa+1][0] != '-') {
nfa = fa + 1;
na = argv[nfa]; /* next is seperate non-flag argument */
}
}
}
if (argv[fa][1] == '?')
usage();
/* Verbosity */
else if (argv[fa][1] == 'v') {
fa = nfa;
if (na == NULL) usage();
verb = atoi(na);
}
/* Tag name */
else if (argv[fa][1] == 't') {
fa = nfa;
if (na == NULL) usage();
if (ntag_names >= MXTGNMS)
usage();
strncpy(tag_names[ntag_names],na,4);
tag_names[ntag_names++][4] = '\000';
}
/* Search */
else if (argv[fa][1] == 's') {
search = 1;
}
/* Check ID */
else if (argv[fa][1] == 'i') {
chid = 1;
}
/* Warnings */
else if (argv[fa][1] == 'w') {
warnings = 1;
warnout = stdout;
}
else if (argv[fa][1] == 'W') {
warnings = 1;
warnout = stderr;
}
/* Strict */
else if (argv[fa][1] == 'S') {
strict = 1;
}
else
usage();
}
else
break;
}
if (fa >= argc || argv[fa][0] == '-') usage();
strncpy(in_name,argv[fa++],MAXNAMEL); in_name[MAXNAMEL] = '\000';
/* Open up the file for reading */
if ((fp = new_icmFileStd_name(&err, in_name,"r")) == NULL)
error ("Can't open file '%s' failed with 0x%x, '%s'",in_name, err.c, err.m);
if ((icco = new_icc(&err)) == NULL)
error ("Creation of ICC object failed with 0x%x, '%s'", err.c, err.m);
if (strict)
icco->unset_cflag(icco, icmCFlagRdFormatWarn
| icmCFlagRdVersionWarn
| icmCFlagRdAllowUnknown
| icmCFlagAllowExtensions);
/* Install warning message handler */
if (warnings)
icco->warning = dump_warning;
/* open output stream */
if ((op = new_icmFileStd_fp(&err, stdout)) == NULL)
error ("Can't open stdout stream, failed with 0x%x, '%s'",err.c, err.m);
do {
found = 0;
/* Dumb search for magic number */
if (search) {
int fc = 0;
char c;
if (fp->seek(fp, offset) != 0)
break;
while(found == 0) {
if (fp->read(fp, &c, 1, 1) != 1) {
break;
}
offset++;
switch (fc) {
case 0:
if (c == 'a')
fc++;
else
fc = 0;
break;
case 1:
if (c == 'c')
fc++;
else
fc = 0;
break;
case 2:
if (c == 's')
fc++;
else
fc = 0;
break;
case 3:
if (c == 'p') {
found = 1;
offset -= 40;
}
else
fc = 0;
break;
}
}
}
if (search == 0 || found != 0) {
ecount++;
if (search)
printf("Embedded profile found at file offset %d (0x%x)\n",offset,offset);
if ((rv = icco->read(icco,fp,offset)) != 0)
error ("%d, %s",rv,icco->e.m);
if (icco->header->cmmId == icmstr2tag("argl"))
icco->allowclutPoints256 = 1;
if (ntag_names > 0) {
int i;
for (i = 0; i < ntag_names; i++) {
icTagSignature sig = icmstr2tag(tag_names[i]);
/* Try and locate that particular tag */
if ((rv = icco->find_tag(icco,sig)) != 0 && rv != 1) {
warning ("icc->find_tag() can't find tag '%s' in file", icmtag2str(sig));
} else {
icmBase *ob;
if (rv == 1)
warning ("icc->find_tag() tag '%s' found but unknown type", tag_names[i]);
if ((ob = icco->read_tag_any(icco, sig)) == NULL) {
warning("Failed to read tag '%s': %d, %s",tag_names[i], icco->e.c,icco->e.m);
} else {
ob->dump(ob, op, verb-1);
}
}
}
} else {
icco->dump(icco, op, verb);
if (chid && icco->header->vers.majv >= 4) {
unsigned char id[16];
rv = icco->check_id(icco, id);
if (rv == 0) {
icmHeader *p = icco->header;
printf("Id check succeeds\n");
op->printf(op," ID is = %02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
p->id[0], p->id[1], p->id[2], p->id[3],
p->id[4], p->id[5], p->id[6], p->id[7],
p->id[8], p->id[9], p->id[10], p->id[11],
p->id[12], p->id[13], p->id[14], p->id[15]);
op->printf(op," ID should be = %02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7],
id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15]);
} else if (rv == 1) {
printf("Id can't be checked because it's not set\n");
op->printf(op," ID should be = %02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7],
id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15]);
} else if (rv == 2) {
icmHeader *p = icco->header;
printf("Id check fails:\n");
op->printf(op," ID is = %02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
p->id[0], p->id[1], p->id[2], p->id[3],
p->id[4], p->id[5], p->id[6], p->id[7],
p->id[8], p->id[9], p->id[10], p->id[11],
p->id[12], p->id[13], p->id[14], p->id[15]);
op->printf(op," ID should be = %02x%02x%02x%02x%02x%02x%02x%02x"
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7],
id[8], id[9], id[10], id[11], id[12], id[13], id[14], id[15]);
} else
warning("Failed to do ID check %d, %s",icco->e.c,icco->e.m);
}
}
offset += 128;
}
} while (found != 0);
icco->del(icco);
op->del(op);
fp->del(fp);
return 0;
}
/* Basic printf type error() and warning() routines */
void
error(char *fmt, ...)
{
va_list args;
fprintf(stderr,"iccdump: Error - ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
exit (-1);
}
void
warning(char *fmt, ...)
{
va_list args;
fprintf(stderr,"iccdump: Warning - ");
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "\n");
}