2
* Argyll Color Correction System
4
* X-Rite i1 DIsplay 3 related software.
6
* Author: Graeme W. Gill
9
* Copyright 2006 - 2011, Graeme W. Gill
10
* All rights reserved.
12
* This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
13
* see the License2.txt file for licencing details.
16
/* This program allows translating the EDR calibration files that */
17
/* come with the i1d3 instrument into Argyll .ccss calibration files, */
18
/* and then installing them. It also allows installing .ccss files */
26
#define WIN32_LEAN_AND_MEAN
32
#include <sys/param.h>
33
#include <sys/mount.h>
36
#include "copyright.h"
39
#else /* SALONEINSTLIB */
41
#include "sa_config.h"
43
#endif /* SALONEINSTLIB */
51
#define MAX_EDR_FILES 200
55
/* --------------------------------------------------------- */
57
/* A list of files stored in memory. The last entry of the list has name == NULL */
59
char *name; /* Name of file */
60
unsigned char *buf; /* It's contents */
61
unsigned long len; /* The length of the contents */
65
xfile *add_xf(xfile **l);
66
void del_xf(xfile *l);
68
static xfile *load_file(char *sname, int verb);
69
static xfile *inno_extract(xfile *xi, char *tfilename, int verb);
70
static xfile *msi_extract(xfile *xi, char *tname, int verb);
71
static xfile *cab_extract(xfile *xi, char *text, int verb);
73
static ccss *parse_EDR(unsigned char *buf, unsigned long len, char *name, int verb);
74
static ccss *read_EDR_file(char *name, int verb);
77
"i1Profiler" "/Installer/Setup.exe"
78
"ColorMunki Displ", "/Installer/ColorMunkiDisplaySetup.exe"
81
/* Cleanup function for transfer on Apple OS X */
82
void umiso(char *amount_path) {
83
#if defined(UNIX) && defined(__APPLE__)
84
char sbuf[MAXNAMEL+1 + 100];
85
sprintf(sbuf, "umount \"%s\"",amount_path);
87
sprintf(sbuf, "rmdir \"%s\"",amount_path);
89
#endif /* UNIX && __APPLE__ */
93
fprintf(stderr,"Translate X-Rite EDR to Argyll .ccss format, & install, Version %s\n",ARGYLL_VERSION_STR);
94
fprintf(stderr,"Author: Graeme W. Gill, licensed under the GPL Version 2 or later\n");
95
fprintf(stderr,"usage: i1d3edr [-options] [infile(s)]\n");
96
fprintf(stderr," -v Verbose\n");
97
fprintf(stderr," -n Don't install, save files to current directory\n");
98
fprintf(stderr," -S d Specify the install scope u = user (def.), l = local system]\n");
99
fprintf(stderr," infile setup.exe file source .edr files from \n");
100
fprintf(stderr," infile.[edr|ccss] EDR file(s) to translate and install or CCSS files to install\n");
105
main(int argc, char *argv[]) {
106
int fa,nfa; /* argument we're looking at */
107
char *ccss_names[MAX_EDR_FILES];
108
ccss *ccss_objs[MAX_EDR_FILES];
109
int no_ccss = 0; /* Number of files provided */
110
int not_edr = 0; /* NZ if first file is not a .edr or .ccss */
111
xdg_scope scope = xdg_user;
114
int amount = 0; /* We mounted the CDROM */
115
char *amount_path = ""; /* Path we mouted */
118
char *install_dir = NULL;
122
set_exe_path(argv[0]); /* Set global exe_path and error_program */
127
/* Process the arguments */
128
for(fa = 1;fa < argc;fa++) {
129
nfa = fa; /* skip to nfa if next argument is used */
130
if (argv[fa][0] == '-') { /* Look for any flags */
131
char *na = NULL; /* next argument after flag, null if none */
133
if (argv[fa][2] != '\000')
134
na = &argv[fa][2]; /* next is directly after flag */
137
if (argv[fa+1][0] != '-') {
139
na = argv[nfa]; /* next is seperate non-flag argument */
144
if (argv[fa][1] == '?')
148
else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
153
else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
158
else if (argv[fa][1] == 'S') {
160
if (na == NULL) usage();
161
else if (na[0] == 'l' || na[0] == 'L')
163
else if (na[0] == 'u' || na[0] == 'U')
173
if (fa > argc || (fa < argc && argv[fa][0] == '-')) usage();
175
/* If filename(s) are provided */
177
for (no_ccss = 0; fa < argc; no_ccss++, fa++) {
178
if (no_ccss >= MAX_EDR_FILES)
179
error("Too many ccss files (max %d)",MAX_EDR_FILES);
181
if ((ccss_names[no_ccss] = strdup(argv[fa])) == NULL)
182
error("malloc failed on ccss_names");
184
if ((strlen(ccss_names[no_ccss]) > 4
185
&& (strncmp(ccss_names[no_ccss] + strlen(ccss_names[no_ccss]) -4, ".edr", 4) == 0
186
|| strncmp(ccss_names[no_ccss] + strlen(ccss_names[no_ccss]) -4, ".EDR", 4) == 0))
187
|| (strlen(ccss_names[no_ccss]) > 5
188
&& (strncmp(ccss_names[no_ccss] + strlen(ccss_names[no_ccss]) -5, ".ccss", 5) == 0
189
|| strncmp(ccss_names[no_ccss] + strlen(ccss_names[no_ccss]) -5, ".CCSS", 5) == 0))) {
195
if (not_edr && no_ccss > 1)
196
error("Need either an archive name or list of .edr or .ccss files");
198
/* Assume we are looking for install files or Setup.exe on a CD */
202
/* Look for the CD */
208
/* Typical instalation locations */
210
"/X-Rite/Devices/i1d3/Calibrations/*.edr",
214
/* Typical volume names the CDROM may have */
221
/* Corresponding setup filenames for each volume name */
222
char *setupnames[] = {
223
"Installer\\Setup.exe",
224
"Installer\\ColorMunkiDisplaySetup.exe",
228
/* See if the files are already installed for the OEM */
230
char tname[MAXNAMEL+1] = { '\000' };
233
if (paths[i][0] == '\000')
236
/* Where the normal instalation goes */
237
if ((pf = getenv("PROGRAMFILES")) != NULL)
240
strcpy(tname, "C:\\Program Files");
242
strcat(tname, paths[i]);
244
printf("Looking for MSWindows install at '%s' .. ",tname);
247
if (aglob_create(&ag, tname))
248
error("Searching for '%s' malloc error",paths[i]);
252
if ((pp = aglob_next(&ag)) == NULL)
254
if (no_ccss >= MAX_EDR_FILES)
255
error("Too many ccss files (max %d)",MAX_EDR_FILES);
256
ccss_names[no_ccss++] = pp;
260
if (verb && no_ccss == 0) printf("not found\n");
262
/* No EDR files found, so look for CD */
265
char vol_name[MAXNAMEL+1] = { '\000' };
266
char tname[MAXNAMEL+1] = { '\000' };
269
if (verb) { printf("Looking for i1d3 install CDROM .. "); fflush(stdout); }
271
len = GetLogicalDriveStrings(400, buf);
273
error("GetLogicalDriveStrings too large");
274
for (i = 0; ;) { /* For all drives */
275
if (buf[i] == '\000')
277
if (GetDriveType(buf+i) == DRIVE_CDROM) {
278
DWORD maxvoll, fsflags;
279
if (GetVolumeInformation(buf + i, vol_name, MAXNAMEL,
280
NULL, &maxvoll, &fsflags, NULL, 0) != 0) {
281
for (j = 0;;j++) { /* For all volume names */
282
if (vols[j][0] == '\000')
284
if (strcmp(vol_name, vols[j]) == 0) {
285
/* Found the instalation CDROM volume name */
286
strcpy(tname, buf+i);
287
strcat(tname, setupnames[j]);
289
printf("found Vol '%s' file '%s'\n",vols[j], tname);
290
if (no_ccss >= MAX_EDR_FILES)
291
error("Too many ccss files (max %d)",MAX_EDR_FILES);
292
if ((ccss_names[no_ccss++] = strdup(tname)) == NULL)
293
error("malloc failed on ccss_names");
298
if (vols[j][0] != '\000')
302
i += strlen(buf + i) + 1;
304
if (buf[i] == '\000' && verb)
305
printf("No volume & Setup.exe found\n");
311
#if defined(UNIX) && defined(__APPLE__)
315
/* Typical instalation locations */
317
"/Library/Application Support/X-Rite/Devices/i1d3xrdevice/Contents/Resources/Calibrations/*.edr",
321
/* Typical native volume names the CDROM may have */
323
"/Volumes/i1Profiler",
324
"/Volumes/ColorMunki Display",
327
/* Corresponding setup filenames for each volume name */
328
char *setupnames[] = {
329
"Installer/Setup.exe",
330
"Installer/ColorMunkiDisplaySetup.exe",
334
/* See if the files are already installed for the OEM */
338
if (paths[i][0] == '\000')
342
printf("Looking for OS X install at '%s' .. ",paths[i]);
345
if (aglob_create(&ag, paths[i]))
346
error("Searching for '%s' malloc error",paths[i]);
350
if ((pp = aglob_next(&ag)) == NULL)
352
if (no_ccss >= MAX_EDR_FILES)
353
error("Too many ccss files (max %d)",MAX_EDR_FILES);
354
ccss_names[no_ccss++] = pp;
358
if (verb && no_ccss == 0) printf("not found\n");
361
/* No EDR files found, so look for CD */
364
char tname[MAXNAMEL+1] = { '\000' };
366
if (verb) { printf("Looking for i1d3 install CDROM .. \n"); fflush(stdout); }
369
if (vols[j][0] == '\000')
372
/* In case it's already mounted (abort of spyd2en ?) */
373
strcpy(tname, vols[j]);
374
strcat(tname, "_ISO");
375
if ((amount_path = strdup(tname)) == NULL)
376
error("Malloc of amount_path failed");
378
strcat(tname, setupnames[j]);
379
if (verb) { printf("Checking if '%s' is already mounted .. ",tname); fflush(stdout); }
380
if (access(tname, 0) == 0) {
381
if (no_ccss >= MAX_EDR_FILES)
382
error("Too many ccss files (max %d)",MAX_EDR_FILES);
383
if ((ccss_names[no_ccss++] = strdup(tname)) == NULL)
384
error("malloc failed on ccss_names");
385
if (verb) printf("yes\n");
387
amount = 1; /* Remember to unmount */
391
/* Not already mounted. */
392
if (access(vols[j], 0) == 0) {
394
char sbuf[MAXNAMEL+1 + 100];
396
if (verb) { printf("no\nMounting ISO partition .. "); fflush(stdout); }
398
/* but we need the ISO partition */
399
/* Locate the mount point */
400
if (statfs(vols[j], &buf) != 0)
401
error("\nUnable to locate mount point for '%s' of install CDROM",vols[j]);
402
if ((sl = strlen(buf.f_mntfromname)) > 3
403
&& buf.f_mntfromname[sl-2] == 's'
404
&& buf.f_mntfromname[sl-1] >= '1'
405
&& buf.f_mntfromname[sl-1] <= '9')
406
buf.f_mntfromname[sl-2] = '\000';
408
error("\nUnable to determine CDROM mount point from '%s'",buf.f_mntfromname);
410
strcpy(tname, vols[j]);
411
strcat(tname, "_ISO");
412
sprintf(sbuf, "mkdir \"%s\"", tname);
413
if ((rv = system(sbuf)) != 0)
414
error("\nCreating ISO9660 volume of CDROM failed with %d",rv);
415
sprintf(sbuf, "mount_cd9660 %s \"%s\"", buf.f_mntfromname,tname);
416
if ((rv = system(sbuf)) != 0) {
417
sprintf(sbuf, "rmdir \"%s\"", tname);
419
error("\nMounting ISO9660 volume of CDROM failed with %d",rv);
424
strcat(tname, setupnames[j]);
425
if (no_ccss >= MAX_EDR_FILES)
426
error("Too many ccss files (max %d)",MAX_EDR_FILES);
427
if ((ccss_names[no_ccss++] = strdup(tname)) == NULL)
428
error("malloc failed on ccss_names");
430
amount = 1; /* Remember to unmount */
435
if (verb) printf("not found\n");
438
#endif /* UNIX && __APPLE__ */
440
#if defined(UNIX) && !defined(__APPLE__)
442
char tname[MAXNAMEL+1] = { '\000' };
445
/* Since there is no vendor driver instalation for Linux, we */
446
/* must look for the CDROM. */
447
char *vols[] = { /* Typical volumes the CDROM could be mounted under */
449
"/media/ColorMunki Displ",
458
char *setupnames[] = {
459
"Installer/Setup.exe",
460
"Installer/ColorMunkiDisplaySetup.exe",
465
if (verb) { printf("Looking for i1d3 install CDROM .. "); fflush(stdout); }
466
/* See if we can see what we're looking for on one of the volumes */
467
/* It would be nice to be able to read the volume name ! */
469
if (vols[j][0] == '\000')
472
if (setupnames[k][0] == '\000')
475
strcpy(tname, vols[j]);
477
strcat(tname, setupnames[k]);
478
if (access(tname, 0) == 0) {
479
if (verb) printf("found '%s'\n",tname);
480
if (no_ccss >= MAX_EDR_FILES)
481
error("Too many ccss files (max %d)",MAX_EDR_FILES);
482
if ((ccss_names[no_ccss++] = strdup(tname)) == NULL)
483
error("malloc failed on ccss_names");
488
if (setupnames[k][0] != '\000') /* We got it */
492
if (verb) printf("not found\n");
498
if (amount) umiso(amount_path);
499
error("No CD found, no Setup.exe or list of EDR or CCSS files provided");
502
if (not_edr) { /* Must be Setup.exe */
508
/* Load up the Seup.exe file */
509
xf0 = load_file(ccss_names[0], verb);
512
/* Extract .msi from it */
513
xf1 = inno_extract(xf0, "{tmp}\\XRD i1d3.msi", verb);
516
/* Extract the .cab from it */
517
xf2 = msi_extract(xf1, "XRD_i1d3.cab", verb);
521
/* Extract the .cab directly from Setup.exe */
522
xf2 = msi_extract(xf0, "XRD_i1d3.cab", verb);
526
/* Extract the .edr's from it */
527
xf3 = cab_extract(xf2, ".edr", verb);
533
/* Translate all the .edr's */
534
for (i = 0; xf3[i].name != NULL; i++) {
536
printf("Translating '%s'\n",xf3[i].name);
537
if ((ccss_objs[no_ccss] = parse_EDR(xf3[i].buf, xf3[i].len, xf3[i].name, verb))
539
warning("Failed to parse EDR '%s'\n",xf3[i].name);
541
if (no_ccss >= MAX_EDR_FILES)
542
error("Too many ccss files (max %d)",MAX_EDR_FILES);
543
if ((ccss_names[no_ccss++] = strdup(xf3[i].name)) == NULL)
544
error("malloc failed on ccss_names");
549
if(amount) umiso(amount_path);
551
/* Also look for any ccss files in ../ref */
555
char tname[MAXNAMEL+1] = { '\000' };
558
strcpy(tname, exe_path);
561
if ((pp = strrchr(tname, '/')) != NULL)
563
if ((pp = strrchr(tname, '/')) != NULL) {
564
strcpy(pp, "/ref/*.ccss");
566
if (aglob_create(&ag, tname))
567
error("Searching for '%s' malloc error",tname);
570
if ((pp = aglob_next(&ag)) == NULL)
572
if (no_ccss >= MAX_EDR_FILES)
573
error("Too many ccss files (max %d)",MAX_EDR_FILES);
574
ccss_names[no_ccss] = pp;
576
printf("Reading '%s'\n",ccss_names[no_ccss]);
577
if ((ccss_objs[no_ccss] = new_ccss()) == NULL)
578
error("new_ccss failed");
579
if (ccss_objs[i]->read_ccss(ccss_objs[no_ccss], ccss_names[no_ccss])) {
580
warning("Reading CCSS file '%s' failed with '%s' - skipping",ccss_names[no_ccss],ccss_objs[i]->err);
581
free(ccss_names[no_ccss]);
582
ccss_names[no_ccss] = NULL;
591
/* Given .edr and .ccss files */
594
/* Load up each .edr or .ccss */
595
for (i = 0; i < no_ccss; i++) {
597
if ((strlen(ccss_names[i]) > 5
598
&& (strncmp(ccss_names[i] + strlen(ccss_names[i]) -5, ".ccss", 5) == 0
599
|| strncmp(ccss_names[i] + strlen(ccss_names[i]) -5, ".CCSS", 5) == 0))) {
601
printf("Reading '%s'\n",ccss_names[i]);
602
if ((ccss_objs[i] = new_ccss()) == NULL)
603
error("new_ccss failed");
604
if (ccss_objs[i]->read_ccss(ccss_objs[i], ccss_names[i])) {
605
warning("Reading CCSS file '%s' failed with '%s' - skipping",ccss_names[i],ccss_objs[i]->err);
607
ccss_names[i] = NULL;
614
printf("Translating '%s' to ccss\n",ccss_names[i]);
615
if ((ccss_objs[i] = read_EDR_file(ccss_names[i], verb)) == NULL) {
616
warning("Reading EDR file '%s' failed - skipping",ccss_names[i]);
618
ccss_names[i] = NULL;
626
/* We now have all the ccss objects loaded into an array. Save or install them all */
629
install_dir = "color"; /* Install them in color sub-directory */
631
/* Save each ccss file */
632
for (i = 0; i < no_ccss; i++) {
635
char *install_name = NULL;
637
if (ccss_names[i] == NULL) /* Couldn'te load this */
640
/* Get basename of file */
641
if ((edrname = strrchr(ccss_names[i], '/')) == NULL)
642
edrname = ccss_names[i];
646
/* Create install path and name */
649
if (install_dir != NULL)
650
len += strlen(install_dir) + 1;
652
len += strlen(edrname) + 2;
654
if ((install_name = malloc(len)) == NULL)
655
error("Malloc failed on install_name\n");
656
install_name[0] = '\000';
658
if (install_dir != NULL && install_dir[0] != '\000') {
659
strcpy(install_name, install_dir);
660
strcat(install_name, "/");
662
strcat(install_name, edrname);
665
if (strlen(install_name) > 4
666
&& (strncmp(install_name + strlen(install_name) -4, ".edr", 4) == 0
667
|| strncmp(install_name + strlen(install_name) -4, ".EDR", 4) == 0))
668
strcpy(install_name + strlen(install_name) -4, ".ccss");
674
/* Get destination path. This may drop uid/gid if we are su */
675
if ((npaths = xdg_bds(NULL, &paths, xdg_data, xdg_write, scope, install_name)) < 1) {
676
error("Failed to find/create XDG_DATA path '%s'",install_name);
679
printf("Writing '%s'\n",paths[0]);
680
if (ccss_objs[i]->write_ccss(ccss_objs[i], paths[0])) {
681
warning("Writing ccss file '%s' failed - skipping",paths[0]);
683
xdg_free(paths, npaths);
687
printf("Writing '%s'\n",install_name);
688
if (ccss_objs[i]->write_ccss(ccss_objs[i], install_name)) {
689
warning("Writing ccss file '%s' failed - skipping",install_name);
692
ccss_objs[i]->del(ccss_objs[i]);
695
if (install_name != NULL)
702
/* ========================================================= */
704
/* Take a 64 sized return buffer, and convert it to an ORD64 */
705
static ORD64 buf2ord64(unsigned char *buf) {
708
val = ((val << 8) + (0xff & buf[6]));
709
val = ((val << 8) + (0xff & buf[5]));
710
val = ((val << 8) + (0xff & buf[4]));
711
val = ((val << 8) + (0xff & buf[3]));
712
val = ((val << 8) + (0xff & buf[2]));
713
val = ((val << 8) + (0xff & buf[1]));
714
val = ((val << 8) + (0xff & buf[0]));
718
/* Take a word sized return buffer, and convert it to an unsigned int */
719
static unsigned int buf2uint(unsigned char *buf) {
722
val = ((val << 8) + (0xff & buf[2]));
723
val = ((val << 8) + (0xff & buf[1]));
724
val = ((val << 8) + (0xff & buf[0]));
728
/* Take a word sized return buffer, and convert it to an int */
729
static int buf2int(unsigned char *buf) {
732
val = ((val << 8) + (0xff & buf[2]));
733
val = ((val << 8) + (0xff & buf[1]));
734
val = ((val << 8) + (0xff & buf[0]));
738
/* Take a short sized return buffer, and convert it to an int */
739
static int buf2short(unsigned char *buf) {
742
val = ((val << 8) + (0xff & buf[0]));
746
// Print bytes as hex to fp
747
static void dump_bytes(FILE *fp, char *pfx, unsigned char *buf, int len) {
749
for (i = j = 0; i < len; i++) {
751
fprintf(fp,"%s%04x:",pfx,i);
752
fprintf(fp," %02x",buf[i]);
753
if ((i+1) >= len || ((i+1) % 16) == 0) {
754
for (ii = i; ((ii+1) % 16) != 0; ii++)
757
for (; j <= i; j++) {
759
fprintf(fp,"%c",buf[j]);
761
fprintf(fp,".",buf[j]);
769
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
770
/* A list of files stored in memory. The last entry of the list has name == NULL */
772
/* return a list with the given number of available entries */
773
xfile *new_xf(int n) {
776
if ((l = (xfile *)calloc((n + 1), sizeof(xfile))) == NULL) {
777
fprintf(stderr,"Failed to allocate xfile structure\n");
784
/* Add an entry to the list. Return the pointer to that entry */
785
xfile *add_xf(xfile **l) {
789
for (ll = *l, n = 0; ll->name != NULL; ll++, n++)
792
if ((*l = (xfile *)realloc(*l, (n+2) * sizeof(xfile))) == NULL) {
793
fprintf(stderr,"Failed to realloc xfile structure\n");
796
(*l)[n+1].name = NULL; /* End marker */
797
(*l)[n+1].buf = NULL;
805
void del_xf(xfile *l) {
809
for (n = 0; l[n].name != NULL; n++) {
811
if (l[n].buf != NULL)
818
/* ================================================================ */
819
/* Load a disk file into an xfile */
821
static xfile *load_file(char *sname, int verb) {
824
unsigned long ilen, bread;
827
if (verb) printf("Loading file '%s'\n",sname);
829
/* Open up the file for reading */
830
#if !defined(O_CREAT) && !defined(_O_CREAT)
831
# error "Need to #include fcntl.h!"
833
#if defined(O_BINARY) || defined(_O_BINARY)
834
if ((fp = fopen(sname,"rb")) == NULL)
836
if ((fp = fopen(sname,"r")) == NULL)
839
fprintf(stderr,"Can't open file '%s'\n",sname);
843
/* Figure out how big it is */
844
if (fseek(fp, 0, SEEK_END)) {
845
fprintf(stderr,"Seek to EOF failed\n");
848
ilen = (unsigned long)ftell(fp);
850
if (verb > 1) printf("Size of file '%s' is %d bytes\n",sname, ilen);
852
if (fseek(fp, 0, SEEK_SET)) {
853
fprintf(stderr,"Seek to SOF of file '%s' failed\n",sname);
857
if ((ibuf = (unsigned char *)malloc(ilen)) == NULL) {
858
fprintf(stderr,"malloc buffer for file '%s' failed\n",sname);
862
if (verb > 1) printf("(Reading file '%s')\n",sname);
864
if ((bread = fread(ibuf, 1, ilen, fp)) != ilen) {
865
fprintf(stderr,"Failed to read file '%s', read %d out of %d bytes\n",sname,bread,ilen);
872
if ((xf[0].name = strdup(sname)) == NULL) {
873
fprintf(stderr,"mmaloc failed on filename '%s'\n", sname);
883
/* ========================================================= */
886
/* Given a buffer holding and EDR file, parse it and return a ccss */
887
/* Return NULL on error */
888
static ccss *parse_EDR(
891
char *name, /* Name of the file */
892
int verb /* Verbose flag */
899
unsigned char *dbuf = NULL; /* Buffer for spectral samples */
903
int ttmin, ttmax; /* Min & max technology strings (inclusive) */
904
char **ttstrings; /* Corresponding technology strings */
905
int ttype; /* Technology type idex */
907
xspect *samples = NULL, sp;
909
double nmstart, nmend, nmspace;
913
/* We hard code the Technology strings for now. In theory we could */
914
/* read them from the TechnologyStrings.txt file that comes with the .edr's */
918
if ((ttstrings = malloc(sizeof(char *) * (ttmax - ttmin + 2))) == NULL) {
919
if (verb) printf("Malloc failed\n");
922
ttstrings[0] = "Color Matching Function";
923
ttstrings[1] = "Custom";
924
ttstrings[2] = "CRT";
925
ttstrings[3] = "LCD CCFL IPS";
926
ttstrings[4] = "LCD CCFL VPA";
927
ttstrings[5] = "LCD CCFL TFT";
928
ttstrings[6] = "LCD CCFL Wide Gamut IPS";
929
ttstrings[7] = "LCD CCFL Wide Gamut VPA";
930
ttstrings[8] = "LCD CCFL Wide Gamut TFT";
931
ttstrings[9] = "LCD White LED IPS";
932
ttstrings[10] = "LCD White LED VPA";
933
ttstrings[11] = "LCD White LED TFT";
934
ttstrings[12] = "LCD RGB LED IPS";
935
ttstrings[13] = "LCD RGB LED VPA";
936
ttstrings[14] = "LCD RGB LED TFT";
937
ttstrings[15] = "LED OLED";
938
ttstrings[16] = "LED AMOLED";
939
ttstrings[17] = "Plasma";
940
ttstrings[18] = "RG Phosphor";
941
ttstrings[19] = "Projector RGB Filter Wheel";
942
ttstrings[20] = "Projector RGBW Filter Wheel";
943
ttstrings[21] = "Projector RGBCMY Filter Wheel";
944
ttstrings[22] = "Projector";
945
ttstrings[23] = "Unknown";
949
if (verb) printf("Unable to read '%s' header\n",name);
952
nbuf = buf + 600; /* Next time we "read" the file */
955
/* See if it has the right file ID */
956
if (strncmp("EDR DATA1", (char *)buf, 16) != 0) {
957
if (verb) printf("File '%s' isn't an EDR\n",name);
961
/* Creation Date&time of EDR */
962
edrdate = buf2ord64(buf + 0x0018);
963
strcpy(creatdate, ctime_64(&edrdate));
965
/* Creation tool string @ 0x0020 */
967
/* Display description */
968
strncpy(dispdesc, (char *)buf + 0x0060, 255); dispdesc[255] = '\000';
970
/* Technology type index. */
971
ttype = buf2int(buf + 0x0160);
973
/* Number of data sets */
974
nsets = buf2int(buf + 0x0164);
976
if (nsets < 3 || nsets > 100) {
977
if (verb) printf("File '%s' number of data sets %d out of range\n",name,nsets);
981
/* Model number string @ 0x0168 ? */
982
/* Part code string @ 0x01a8 ? */
983
/* Another number string @ 0x01e8 ? */
985
/* Unknown Flag/number = 1 @ 0x022c */
987
/* "has spectral data" flag ? */
988
hasspec = buf2short(buf + 0x022E);
990
if (verb) printf("Has Data flag != 1 in EDR file '%s'\n",name);
994
/* The spectral sample characteristics */
995
nmstart = IEEE754_64todouble(buf2ord64(buf + 0x0230));
996
nmend = IEEE754_64todouble(buf2ord64(buf + 0x0238));
997
nmspace = IEEE754_64todouble(buf2ord64(buf + 0x0240));
999
/* Setup prototype spectral values */
1000
sp.spec_wl_short = nmstart;
1001
sp.spec_wl_long = nmend;
1002
sp.spec_n = (int)(1.0 + (nmend - nmstart)/nmspace + 0.5);
1005
/* Unknown Flag/number = 0 @ 0x0248 */
1006
/* Error if not 0 ??? */
1009
/* Allocate space for the sets */
1010
if ((samples = (xspect *)malloc(sizeof(xspect) * nsets)) == NULL) {
1011
if (verb) printf("Malloc of spectral samples failed\n");
1016
/* Read the sets of data */
1017
for (set = 0; set < nsets; set++) {
1019
/* "Read" in the 128 byte data set header */
1023
if (verb) printf("Unable to read file '%s' set %d data header\n",name,set);
1024
if (samples != NULL) free(samples);
1027
nbuf = buf + 128; /* Next time we "read" the file */
1030
/* See if it has the right ID */
1031
if (strncmp("DISPLAY DATA", (char *)buf, 16) != 0) {
1032
if (verb) printf("File '%s' set %d data header has unknown identifier\n",name,set);
1033
if (samples != NULL) free(samples);
1037
/* double Yxy(z) of sample at +0x0058 in data header ? */
1039
if (hasspec == 0) /* No spectral data, so skip it */
1042
/* Read in the 28 byte data set header */
1046
if (verb) printf("Unable to read file '%s' set %d spectral data header\n",name,set);
1047
if (samples != NULL) free(samples);
1050
nbuf = buf + 28; /* Next time we "read" the file */
1053
/* See if it has the right ID */
1054
if (strncmp("SPECTRAL DATA", (char *)buf, 16) != 0) {
1055
if (verb) printf("File '%s' set %d data header has unknown identifier\n",name,set);
1056
if (samples != NULL) free(samples);
1060
/* Number of doubles in set */
1061
nsamples = buf2int(buf + 0x0010);
1063
if (nsamples != sp.spec_n) {
1064
if (verb) printf("File '%s' set %d number of samles %d doesn't match wavelengths %d\n",name,set,nsamples,sp.spec_n);
1065
if (samples != NULL) free(samples);
1069
/* Read in the spectral values */
1072
if (len < 8 * sp.spec_n) {
1073
if (verb) printf("Unable to read file '%s' set %d spectral data\n",name,set);
1074
if (samples != NULL) free(samples);
1077
nbuf = buf + 8 * sp.spec_n; /* Next time we "read" the file */
1078
nlen = len - 8 * sp.spec_n;
1080
XSPECT_COPY_INFO(&samples[set], &sp);
1082
/* Read the spectral values for this sample, */
1083
/* and convert it from W/nm/m^2 to mW/nm/m^2 */
1084
for (j = 0; j < sp.spec_n; j++) {
1085
samples[set].spec[j] = IEEE754_64todouble(buf2ord64(buf + j * 8));
1086
samples[set].spec[j] *= 1000.0;
1089
/* Plot the spectra */
1094
for (j = 0; j < samples[set].spec_n; j++) {
1095
xx[j] = XSPECT_XWL(&sp, j);
1096
y1[j] = samples[set].spec[j];
1098
printf("EDR sample %d (uncorrected)\n",set+1);
1099
do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, samples[set].spec_n);
1101
#endif /* PLOT_SAMPLES */
1105
/* After the spectral data comes the "correction" data. This seems to be */
1106
/* related to the measurement instrument (typically a Minolta CS1000). */
1107
/* It's not obvious why this isn't already applied to the spectral data, */
1108
/* and doesn't cover the same wavelength range as the samples. */
1110
/* Try and read in the 92 byte correction header */
1114
nbuf = buf + 92; /* Next time we "read" the file */
1117
/* See if it has the right ID */
1118
if (strncmp("CORRECTION DATA", (char *)buf, 16) != 0) {
1119
if (verb) printf("File '%s' correction data header has unknown identifier\n",name);
1120
if (samples != NULL) free(samples);
1124
/* Number of doubles in set */
1125
nsamples = buf2int(buf + 0x0050);
1127
if (nsamples == 351) {
1128
sp.spec_wl_short = 380.0;
1129
sp.spec_wl_long = 730.0;
1130
sp.spec_n = nsamples;
1132
} else if (nsamples == 401) {
1133
sp.spec_wl_short = 380.0;
1134
sp.spec_wl_long = 780.0;
1135
sp.spec_n = nsamples;
1138
if (verb) printf("File '%s' correction data has unknown range %d\n\n",name,nsamples);
1139
if (samples != NULL) free(samples);
1143
/* Read in the spectral values */
1146
if (len < 8 * sp.spec_n) {
1147
if (verb) printf("Unable to read file '%s' correction spectral data\n",name);
1148
if (samples != NULL) free(samples);
1151
nbuf = buf + 8 * sp.spec_n; /* Next time we "read" the file */
1152
nlen = len - 8 * sp.spec_n;
1154
for (j = 0; j < sp.spec_n; j++) {
1155
sp.spec[j] = IEEE754_64todouble(buf2ord64(buf + j * 8));
1159
/* Plot the spectra */
1164
for (j = 0; j < sp.spec_n; j++) {
1165
xx[j] = XSPECT_XWL(&sp, j);
1168
printf("Correction data\n");
1169
do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, sp.spec_n);
1171
#endif /* PLOT_SAMPLES */
1173
/* Apply the correction to all the spectral samples */
1174
for (set = 0; set < nsets; set++) {
1175
for (j = 0; j < samples[set].spec_n; j++)
1176
samples[set].spec[j] *= value_xspect(&sp, XSPECT_XWL(&samples[set], j));
1181
if ((rv = new_ccss()) == NULL) {
1182
if (verb) printf("Unable to read file '%s' correction spectral data\n",name);
1183
if (samples != NULL) free(samples);
1187
if (ttype < ttmin || ttype > ttmax) {
1188
ttype = ttmax + 1; /* Set to Unknown */
1191
/* Set it's values */
1192
rv->set_ccss(rv, "X-Rite", creatdate, NULL, dispdesc, ttstrings[ttype], "CS1000", samples, nsets);
1200
/* Read am EDR file and return a ccss class */
1201
/* Return NULL on error */
1202
static ccss *read_EDR_file(
1203
char *name, /* File to read */
1204
int verb /* Verbose flag */
1207
unsigned char *ibuf;
1208
unsigned long ilen, bread;
1211
/* Open up the file for reading */
1212
#if !defined(O_CREAT) && !defined(_O_CREAT)
1213
# error "Need to #include fcntl.h!"
1215
#if defined(O_BINARY) || defined(_O_BINARY)
1216
if ((fp = fopen(name,"rb")) == NULL)
1218
if ((fp = fopen(name,"r")) == NULL)
1221
if (verb) printf("Unable to open file file '%s'\n",name);
1225
/* Figure out how big it is */
1226
if (fseek(fp, 0, SEEK_END)) {
1227
if (verb) printf("Seek to EOF '%s' failed'\n",name);
1230
ilen = (unsigned long)ftell(fp);
1232
if (fseek(fp, 0, SEEK_SET)) {
1233
if (verb) printf("Seek to SOF '%s' failed'\n",name);
1237
if ((ibuf = (unsigned char *)malloc(ilen)) == NULL) {
1238
if (verb) printf("Malloc of buffer for file '%s' failed\n",name);
1242
if ((bread = fread(ibuf, 1, ilen, fp)) != ilen) {
1243
if (verb) printf("Failed to read file '%s', read %d out of %d bytes\n",name,bread,ilen);
1249
rv = parse_EDR(ibuf, ilen, name, verb);
1256
/* ========================================================= */
1257
/* Extract a file from an inno archive. */
1259
/* (It turns out we don't actually need this inno parsing code, */
1260
/* since the .cab file is uncompressed and contiguous, so */
1261
/* we can locate and save it directly from Setup.exe.) */
1263
/* Function callbacks for LzmaDec */
1264
static void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
1265
static void SzFree(void *p, void *address) { p = p; free(address); }
1266
ISzAlloc alloc = { SzAlloc, SzFree };
1269
/* Version of lzma decode that skips the 4 byte CRC before each 4096 byte block */
1270
static SRes LzmaDecodeX(
1271
Byte *dest, unsigned long *destLen, const Byte *src, unsigned long *srcLen,
1272
ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc) {
1275
SizeT slen = *srcLen;
1276
SizeT dlen = *destLen;
1281
return SZ_ERROR_INPUT_EOF;
1283
LzmaDec_Construct(&state);
1284
res = LzmaDec_Allocate(&state, src + 4, LZMA_PROPS_SIZE, alloc);
1290
LzmaDec_Init(&state);
1292
for (;slen > 0 && dlen > 0;) {
1296
return SZ_ERROR_INPUT_EOF;
1298
return SZ_ERROR_OUTPUT_EOF;
1305
len = 4096; /* Bytes to next CRC */
1307
if (doneheader == 0) { /* Skip the 5 + 8 byte header */
1320
res = LzmaDec_DecodeToBuf(&state, dest, &ddlen, src, &len, finishMode, status);
1322
LzmaDec_Free(&state, alloc);
1334
if (*status == LZMA_STATUS_FINISHED_WITH_MARK
1335
|| *status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) {
1339
LzmaDec_Free(&state, alloc);
1344
/* extract the given file from Setup.exe */
1346
/* Return a list of xfiles, with one entry if successful */
1347
/* print error message and exit othewise. */
1348
static xfile *inno_extract(xfile *xi, char *tfilename, int verb) {
1350
unsigned char *ibuf;
1352
char *headerid = "Inno Setup Setup Data (5.3.10)";
1353
int headerlen = strlen(headerid);
1354
unsigned int ldrbase = 0;
1355
unsigned long haddr, srclen;
1356
unsigned char *d1buf, *d2buf; /* Decompress buffer */
1357
unsigned long d1sz, d2sz;
1358
unsigned char *msibuf;
1359
unsigned long msisz;
1360
unsigned long cblocklen;
1364
int filelen = strlen(tfilename);
1365
unsigned long fileso, filesz;
1372
/* Search for the start of the loader. All the file offsets */
1373
/* are relative to this */
1374
for (i = 0; i < (ilen - 4); i++) {
1375
if (ibuf[i + 0] == 0x4d
1376
&& ibuf[i + 1] == 0x5a
1377
&& ibuf[i + 2] == 0x90
1378
&& ibuf[i + 3] == 0x00) {
1379
if (verb > 1) printf("Found archive base 0x%x\n",i);
1384
if (i >= (ilen - 4)) {
1385
fprintf(stderr,"Failed to locate loader base\n");
1389
/* Search for inno header pattern. */
1390
for (i = 0; i < (ilen - 64 - 4 - 5 - 4); i++) {
1391
if (ibuf[i] == headerid[0]
1392
&& strncmp((char *)ibuf + i, headerid, headerlen) == 0
1393
&& ibuf[i + 64] != 'I'
1394
&& ibuf[i + 65] != 'n'
1395
&& ibuf[i + 66] != 'n'
1396
&& ibuf[i + 67] != 'o') {
1401
if (verb > 1) printf("Found header at 0x%x\n",i);
1403
/* Use the last header found (or cound search all found ?) */
1404
haddr += 64; /* Skip Inno header */
1406
/* Next 9 bytes are the compression header */
1407
haddr += 4; /* Skip Inno header CRC */
1408
cblocklen = buf2uint(ibuf + haddr); /* Compressed block length */
1410
if (verb > 1) printf("Header compression block length = %d\n",cblocklen);
1412
if ((haddr + cblocklen) > ilen) {
1413
fprintf(stderr,"Compression block is longer than setup.exe\n");
1417
if (ibuf[haddr + 4] != 1) {
1418
fprintf(stderr,"Inno header is expected to be compressed\n");
1421
haddr += 5; /* Skip compression header */
1423
/* We'r now at the start of the compressed data */
1425
d1sz = cblocklen * 30;
1426
if ((d1buf = (unsigned char *)malloc(d1sz)) == NULL) {
1427
fprintf(stderr,"Failed to allocate decompression buffer\n");
1431
// if (verb) printf("CRC + lzma at %d\n",haddr);
1433
srclen = ilen - haddr;
1435
/* Decode using CRC + 4096 byte blocks */
1436
rv = LzmaDecodeX(d1buf, &d1sz, ibuf + haddr, &srclen, LZMA_FINISH_END, &dstat, &alloc);
1439
fprintf(stderr,"lzma decode failed with rv %d and status %d\n",rv, dstat);
1442
if (verb > 1) printf("Decoded %d bytes to created %d bytes of Header output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen);
1444
// dump_bytes(stdout, " ", d1buf, d1sz);
1446
/* - - - - - - - - - - - - - - - - -*/
1448
/* Skip to the start of the next compression block header */
1451
if (verb > 1) printf("Expect File Location compressed block to be at 0x%x\n",haddr);
1452
if ((haddr + 20) > ilen) {
1453
fprintf(stderr,"Setup.exe too short for 2nd header block\n");
1457
/* Next 9 bytes are the compression header */
1458
haddr += 4; /* Skip Inno header CRC */
1459
cblocklen = buf2uint(ibuf + haddr); /* Compressed block length */
1461
if (verb > 1) printf("File Location compression block length = %d\n",cblocklen);
1463
if ((haddr + cblocklen) > ilen) {
1464
fprintf(stderr,"2nd compression block is longer than setup.exe\n");
1468
if (ibuf[haddr + 4] != 1) {
1469
fprintf(stderr,"Inno 2nd header is expected to be compressed\n");
1472
haddr += 5; /* Skip compression header */
1474
/* We're now at the start of the compressed data */
1476
d2sz = cblocklen * 10;
1477
if ((d2buf = (unsigned char *)malloc(d2sz)) == NULL) {
1478
fprintf(stderr,"Failed to allocate 2nd block decompression buffer\n");
1482
//if (verb) printf("CRC + lzma at %d\n",haddr);
1483
srclen = ilen - haddr;
1485
/* Decode using CRC + 4096 byte blocks */
1486
rv = LzmaDecodeX(d2buf, &d2sz, ibuf + haddr, &srclen, LZMA_FINISH_END, &dstat, &alloc);
1489
fprintf(stderr,"lzma decode of 2nd block failed with rv %d and status %d\n",rv, dstat);
1492
if (verb > 1) printf("Decoded %d bytes to created %d bytes of File Location output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen);
1494
// dump_bytes(stdout, " ", d2buf, d2sz);
1496
if (verb > 1) printf("Searching for file '%s' in Header\n",tfilename);
1497
for (i = 0; i < (d1sz - 101); i++) {
1498
if (d1buf[i+4] == tfilename[0]
1499
&& strncmp((char *)d1buf + 4 + i, tfilename, filelen) == 0
1500
&& d1buf[i+0] == filelen
1503
&& d1buf[i+3] == 0) {
1504
if (verb > 1) printf("Found it at 0x%x\n",i);
1509
/* Need to skip 8 more strings */
1511
for (j = 0; j < 8; j++) {
1513
len = buf2uint(d1buf + i);
1516
/* Skip another 40 bytes to location entry index */
1519
ix = buf2uint(d1buf + i);
1521
if (verb > 1) printf("Got file location index %d at 0x%x\n",ix,i);
1524
/* Now get the ix file entry information. */
1525
/* They are in 74 byte structures */
1528
if ((i + 74) > d2sz) {
1529
fprintf(stderr,"File location structure is out of range\n");
1533
/* The start offset is at 8 */
1534
fileso = buf2uint(d2buf + i + 8);
1536
/* The original and compresses sizes are at 20 and 28 */
1537
filesz = buf2uint(d2buf + i + 20); /* Actually 64 bit, but we don't need it */
1538
if (filesz != buf2uint(d2buf + i + 28)) {
1539
fprintf(stderr,"Can't handle compressed '%s'\n",tfilename);
1543
if (verb > 1) printf("File '%s' is at offset 0x%x, length %d\n",tfilename,fileso,filesz);
1545
if ((fileso + ldrbase) > ilen
1546
|| (fileso + ldrbase + filesz-1) > ilen) {
1547
printf("File '%s' is outsize file '%s' range \n",tfilename,xi[0].name);
1551
if (ibuf[ldrbase + fileso + 0] != 0xd0
1552
|| ibuf[ldrbase + fileso + 1] != 0xcf
1553
|| ibuf[ldrbase + fileso + 2] != 0x11
1554
|| ibuf[ldrbase + fileso + 3] != 0xe0) {
1555
fprintf(stderr,"File '%s' doesn't seem to be at location\n",tfilename);
1559
/* Copy to new buffer and free everything */
1561
if ((msibuf = (unsigned char *)malloc(msisz)) == NULL) {
1562
fprintf(stderr,"Failed to allocate file '%s' buffer\n",tfilename);
1565
memmove(msibuf, ibuf + ldrbase + fileso, filesz);
1572
/* Just return base filename */
1573
if ((cp = strrchr(tfilename, '/')) == NULL
1574
&& (cp = strrchr(tfilename, '\\')) == NULL)
1579
if ((xf[0].name = strdup(cp)) == NULL) {
1580
fprintf(stderr,"mmaloc failed on filename\n");
1586
if (verb) printf("Returning '%s' length %d from '%s'\n",xf[0].name,xf[0].len, xi[0].name);
1591
/* ====================================================== */
1592
/* Extract the .cab file from another file. */
1594
/* It's stored in the .msi uncompressed and contiguous, so we */
1595
/* just need to identify where it is and its length. */
1596
/* (This will work on any file that has the .cab file uncompressed and contiguous) */
1597
static xfile *msi_extract(xfile *xi, char *tname, int verb) {
1600
char *fid = "i1d3.xrdevice"; /* File in .cab to look for */
1601
unsigned long fle = strlen(fid);
1602
unsigned long cabo, cabsz;
1604
if (verb) printf("Attempting to extract '%s' from '%s'\n",tname,xi[0].name);
1606
/* Search for a filename in the .cab */
1607
for (i = 0; i < (xi[0].len - fle - 2); i++) {
1608
if (xi[0].buf[i + 0] == 0x00
1609
&& xi[0].buf[i + 1] == fid[0]
1610
&& strncmp((char *)xi[0].buf + i + 1, fid, fle) == 0) {
1611
if (verb > 1) printf("Found file name '%s' in '%s' at 0x%x\n",fid,xi[0].name,i);
1616
/* Search backwards for .cab signature */
1617
for (; i >= 0; i--) {
1618
if (xi[0].buf[i + 0] == 0x4d
1619
&& xi[0].buf[i + 1] == 0x53
1620
&& xi[0].buf[i + 2] == 0x43
1621
&& xi[0].buf[i + 3] == 0x46
1622
&& xi[0].buf[i + 4] == 0x00
1623
&& xi[0].buf[i + 5] == 0x00
1624
&& xi[0].buf[i + 6] == 0x00
1625
&& xi[0].buf[i + 7] == 0x00) {
1626
if (verb > 1) printf("Found '%s' at 0x%x\n",tname,i);
1633
/* Lookup the .cab size (really 64 bit, but we don't care) */
1634
xf[0].len = buf2uint(xi[0].buf + i + 8);
1636
if (verb > 1) printf("'%s' is length %d\n",tname,xf[0].len);
1638
if ((xi[0].len - i) < xf[0].len) {
1639
fprintf(stderr,"Not enough room for .cab file in source\n");
1643
if ((xf[0].buf = malloc(xf[0].len)) == NULL) {
1644
fprintf(stderr,"maloc of .cab buffer failed\n");
1647
memmove(xf[0].buf, xi[0].buf + i ,xf[0].len);
1649
if ((xf[0].name = strdup(tname)) == NULL) {
1650
fprintf(stderr,"maloc of .cab name failed\n");
1654
if (verb) printf("Extacted '%s' length %d\n",xf[0].name,xf[0].len);
1660
/* ================================================================ */
1661
/* Extract files of a given type from a .cab file */
1663
/* Interface with inflate.c */
1664
/* We use globals for this */
1666
unsigned char *i_buf = NULL;
1667
unsigned long i_len = 0;
1668
unsigned long i_ix = 0;
1670
unsigned char *o_buf = NULL;
1671
unsigned long o_len = 0;
1672
unsigned long o_ix = 0;
1674
/* Interface to inflate */
1676
/* fetch the next 8 bits */
1677
/* if we get 0xffffffff, we are at EOF */
1678
unsigned int inflate_get_byte() {
1680
return i_buf[i_ix++];
1685
void inflate_unget_byte() {
1690
/* Save the decompressed file to the buffer */
1691
int inflate_write_output(unsigned char *buf, unsigned int len) {
1692
if ((o_ix + len) > o_len) {
1693
fprintf(stderr,"Uncompressed buffer is unexpectedly large (%d > %d)!\n", o_ix + len, o_len);
1696
memmove(o_buf + o_ix, buf, len);
1701
/* Extract all the .edr files from the .cab */
1702
static xfile *cab_extract(xfile *xi, char *text, int verb) {
1705
unsigned char *buf = xi[0].buf;
1706
unsigned long len = xi[0].len;
1708
unsigned long filesize, headeroffset, datastart;
1709
int nofolders, nofiles, flags, comptype;
1710
unsigned int totubytes;
1712
unsigned char *obuf;
1715
if (verb) printf("Attempting to extract '*%s' from '%s'\n",text, xi[0].name);
1717
/* Check it is a .cab file */
1726
|| buf[7] != 0x00) {
1727
fprintf(stderr,"'%s' is not a .cab file\n",xi[0].name);
1731
filesize = buf2uint(buf + 0x08);
1732
headeroffset = buf2uint(buf + 0x10);
1733
nofolders = buf2short(buf + 0x1a);
1734
nofiles = buf2short(buf + 0x1c);
1735
flags = buf2short(buf + 0x1e);
1737
if (filesize != len) {
1738
fprintf(stderr,"'%s' filesize desn't match\n",xi[0].name);
1741
if (nofolders != 1) {
1742
fprintf(stderr,"'%s' has more than one folder\n",xi[0].name);
1746
fprintf(stderr,"'%s' has non-zero flags\n",xi[0].name);
1750
/* Read the first folders info (assumed flags == 0) */
1751
datastart = buf2uint(buf + 0x24);
1752
comptype = buf[0x2a];
1754
fprintf(stderr,"'%s' doesn't use MSZip compression\n",xi[0].name);
1758
if (verb > 1) printf(".cab headeroffset = 0x%x, datastart = 0x%x, nofiles = %d\n",headeroffset,datastart,nofiles);
1760
/* Look at each file */
1761
for (off = headeroffset, k = 0; k < nofiles; k++) {
1762
unsigned long fsize; /* Uncompressed size */
1767
if (off > (len - 80)) {
1768
fprintf(stderr,"'%s' too short for directory\n",xi[0].name);
1772
fsize = buf2uint(buf + off + 0x00);
1773
foff = buf2uint(buf + off + 0x04);
1774
ffix = buf2short(buf + off + 0x08);
1776
strncpy(fname, (char *)buf + off + 0x10, 94);
1779
if (verb > 1) printf("file %d is '%s' at 0x%x length %d\n",k,fname, foff,fsize);
1781
off += 0x10 + strlen(fname) + 1; /* Next entry */
1784
/* Now come the data blocks */
1786
for (off = datastart, j = 0; ; j++) {
1787
unsigned long chsum;
1788
unsigned long cbytes;
1789
unsigned long ubytes;
1791
if (off > (len - 8)) {
1792
if (verb > 1) printf("Got to end of data blocks at 0x%x\n",off);
1796
chsum = buf2uint(buf + off + 0x00);
1797
cbytes = buf2short(buf + off + 0x04);
1798
ubytes = buf2short(buf + off + 0x06);
1800
if (verb > 1) printf("Compression block %d, cbytes %d, ubytes %d\n",j,cbytes,ubytes);
1802
totubytes += ubytes;
1808
if (verb > 1) printf("Total uncompressed bytes = %d\n",totubytes);
1811
if ((obuf = malloc(olen)) == NULL) {
1812
fprintf(stderr,"maloc of uncompressed output buffer failed\n");
1820
for (off = datastart, j = 0; ; j++) {
1821
unsigned long chsum;
1822
unsigned long cbytes;
1823
unsigned long ubytes;
1825
if (off > (len - 8))
1828
chsum = buf2uint(buf + off + 0x00);
1829
cbytes = buf2short(buf + off + 0x04);
1830
ubytes = buf2short(buf + off + 0x06);
1832
i_buf = buf + off + 8;
1836
/* MSZIP has a two byte signature at the start of each block */
1837
if (inflate_get_byte() != 0x43 || inflate_get_byte() != 0x4B) {
1838
printf(".cab block doesn't start with 2 byte MSZIP signature\n");
1843
fprintf(stderr, "inflate of '%s' failed at i_ix 0x%x, o_ix 0x%x\n",xi[0].name,i_ix,o_ix);
1847
/* The history buffer is meant to survive from one block to the next. */
1848
/* Not sure what that means, as it seems to work as is... */
1855
/* Create a buffer for each file */
1856
for (ufiles = 0, off = headeroffset, k = 0; k < nofiles; k++) {
1857
unsigned long fsize; /* Uncompressed size */
1860
char fname[95], *cp;
1863
fsize = buf2uint(buf + off + 0x00);
1864
foff = buf2uint(buf + off + 0x04);
1865
ffix = buf2short(buf + off + 0x08);
1867
strncpy(fname, (char *)buf + off + 0x10, 94);
1869
namelen = strlen(fname);
1871
/* Lop of the junk in the filename */
1872
if ((cp = strrchr(fname, '.')) != NULL)
1875
/* See if it's the type of file we want */
1876
if ((cp = strrchr(fname, '.')) != NULL
1877
&& strcmp(cp, text) == 0) {
1882
if (foff >= olen || (foff + fsize) > olen) {
1883
fprintf(stderr,"file '%s' doesn't fit in decomressed buffer\n");
1886
if ((xx->buf = malloc(fsize)) == NULL) {
1887
fprintf(stderr,"maloc of file '%s' buffer len %d failed\n",fname,fsize);
1891
memmove(xx->buf, obuf + foff, fsize);
1893
if ((xx->name = strdup(fname)) == NULL) {
1894
fprintf(stderr,"maloc of .edr name failed\n");
1899
off += 0x10 + namelen + 1; /* Next entry */
1902
if (verb) printf("Found %d %s files out of %d files in .cab\n",ufiles, text, nofiles);