~ubuntu-branches/ubuntu/saucy/argyll/saucy

« back to all changes in this revision

Viewing changes to spectro/i1d3ccss.c

  • Committer: Package Import Robot
  • Author(s): Christian Marillat
  • Date: 2012-04-25 07:46:07 UTC
  • mfrom: (1.2.2) (13.1.15 sid)
  • Revision ID: package-import@ubuntu.com-20120425074607-yjqadetw8kum9skc
Tags: 1.4.0-4
Should Build-Depends on libusb-dev (Closes: #670329).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
 * Argyll Color Correction System
 
3
 *
 
4
 * X-Rite i1 DIsplay 3 related software.
 
5
 *
 
6
 * Author: Graeme W. Gill
 
7
 * Date:   18/8/2011
 
8
 *
 
9
 * Copyright 2006 - 2011, Graeme W. Gill
 
10
 * All rights reserved.
 
11
 *
 
12
 * This material is licenced under the GNU GENERAL PUBLIC LICENSE Version 2 or later :-
 
13
 * see the License2.txt file for licencing details.
 
14
 */
 
15
 
 
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 */
 
19
 
 
20
#include <stdio.h>
 
21
#include <stdlib.h>
 
22
#include <stdarg.h>
 
23
#include <fcntl.h>
 
24
#include <string.h>
 
25
#if defined (NT)
 
26
#define WIN32_LEAN_AND_MEAN
 
27
#include <io.h>
 
28
#include <windows.h>
 
29
#endif
 
30
#ifdef UNIX
 
31
#include <unistd.h>
 
32
#include <sys/param.h>
 
33
#include <sys/mount.h>
 
34
#endif /* UNIX */
 
35
#ifndef SALONEINSTLIB
 
36
#include "copyright.h"
 
37
#include "aconfig.h"
 
38
#include "numlib.h"
 
39
#else /* SALONEINSTLIB */
 
40
#include <fcntl.h>
 
41
#include "sa_config.h"
 
42
#include "numsup.h"
 
43
#endif /* SALONEINSTLIB */
 
44
#include "xdg_bds.h"
 
45
#include "xspect.h"
 
46
#include "conv.h"
 
47
#include "aglob.h"
 
48
#include "ccss.h"
 
49
#include "LzmaDec.h"
 
50
 
 
51
#define MAX_EDR_FILES 200
 
52
 
 
53
#undef PLOT_SAMPLES
 
54
 
 
55
/* --------------------------------------------------------- */
 
56
 
 
57
/* A list of files stored in memory. The last entry of the list has name == NULL */
 
58
typedef struct {
 
59
        char *name;                             /* Name of file */
 
60
        unsigned char *buf;             /* It's contents */
 
61
        unsigned long len;              /* The length of the contents */
 
62
} xfile;
 
63
 
 
64
xfile *new_xf(int n);
 
65
xfile *add_xf(xfile **l);
 
66
void del_xf(xfile *l);
 
67
 
 
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);
 
72
 
 
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);
 
75
 
 
76
/*
 
77
        "i1Profiler" "/Installer/Setup.exe"
 
78
        "ColorMunki Displ", "/Installer/ColorMunkiDisplaySetup.exe"
 
79
 */
 
80
 
 
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);
 
86
        system(sbuf);
 
87
        sprintf(sbuf, "rmdir \"%s\"",amount_path);
 
88
        system(sbuf);
 
89
#endif /* UNIX && __APPLE__ */
 
90
}
 
91
 
 
92
void usage(void) {
 
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");
 
101
        exit(1);
 
102
}
 
103
 
 
104
int
 
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;
 
112
        int verb = 0;
 
113
        int install = 1;
 
114
        int amount = 0;                 /* We mounted the CDROM */
 
115
        char *amount_path = ""; /* Path we mouted */
 
116
        unsigned char *fbuf;
 
117
        unsigned int fsize;
 
118
        char *install_dir = NULL;
 
119
        int i;
 
120
        int rv = 0;
 
121
        
 
122
        set_exe_path(argv[0]);          /* Set global exe_path and error_program */
 
123
 
 
124
        if (argc < 1)
 
125
                usage();
 
126
 
 
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 */
 
132
 
 
133
                        if (argv[fa][2] != '\000')
 
134
                                na = &argv[fa][2];              /* next is directly after flag */
 
135
                        else {
 
136
                                if ((fa+1) < argc) {
 
137
                                        if (argv[fa+1][0] != '-') {
 
138
                                                nfa = fa + 1;
 
139
                                                na = argv[nfa];         /* next is seperate non-flag argument */
 
140
                                        }
 
141
                                }
 
142
                        }
 
143
 
 
144
                        if (argv[fa][1] == '?')
 
145
                                usage();
 
146
 
 
147
                        /* Verbosity */
 
148
                        else if (argv[fa][1] == 'v' || argv[fa][1] == 'V') {
 
149
                                verb = 1;
 
150
                        }
 
151
 
 
152
                        /* No install */
 
153
                        else if (argv[fa][1] == 'n' || argv[fa][1] == 'N') {
 
154
                                install = 0;
 
155
                        }
 
156
 
 
157
                        /* Install scope */
 
158
                        else if (argv[fa][1] == 'S') {
 
159
                                fa = nfa;
 
160
                                if (na == NULL) usage();
 
161
                                        else if (na[0] == 'l' || na[0] == 'L')
 
162
                                                scope = xdg_local;
 
163
                                        else if (na[0] == 'u' || na[0] == 'U')
 
164
                                                scope = xdg_user;
 
165
                        }
 
166
                        else 
 
167
                                usage();
 
168
                }
 
169
                else
 
170
                        break;
 
171
        }
 
172
 
 
173
        if (fa > argc || (fa < argc && argv[fa][0] == '-')) usage();
 
174
 
 
175
        /* If filename(s) are provided */
 
176
        if (fa < argc) {
 
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);
 
180
 
 
181
                        if ((ccss_names[no_ccss] = strdup(argv[fa])) == NULL)
 
182
                                error("malloc failed on ccss_names");
 
183
 
 
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))) {
 
190
                                /* */
 
191
                        } else {
 
192
                                not_edr = 1;
 
193
                        }
 
194
                }
 
195
                if (not_edr && no_ccss > 1)
 
196
                        error("Need either an archive name or list of .edr or .ccss files");
 
197
 
 
198
        /* Assume we are looking for install files or Setup.exe on a CD */
 
199
        } else {
 
200
                
 
201
 
 
202
                /* Look for the CD */
 
203
#ifdef NT
 
204
                {
 
205
                        int i;
 
206
                        char *pf = NULL;
 
207
 
 
208
                        /* Typical instalation locations */
 
209
                        char *paths[] = {
 
210
                                "/X-Rite/Devices/i1d3/Calibrations/*.edr",
 
211
                                ""
 
212
                        };
 
213
 
 
214
                        /* Typical volume names the CDROM may have */
 
215
                        char *vols[] = {
 
216
                                "i1Profiler",
 
217
                                "ColorMunki Displ",
 
218
                                ""
 
219
                        };
 
220
 
 
221
                        /* Corresponding setup filenames for each volume name */
 
222
                        char *setupnames[] = {
 
223
                                "Installer\\Setup.exe",
 
224
                                "Installer\\ColorMunkiDisplaySetup.exe",
 
225
                                ""
 
226
                        };
 
227
 
 
228
                        /* See if the files are already installed for the OEM */
 
229
                        for (i = 0;;i++) {
 
230
                                char tname[MAXNAMEL+1] = { '\000' };
 
231
                                aglob ag;
 
232
 
 
233
                                if (paths[i][0] == '\000')
 
234
                                        break;
 
235
 
 
236
                                /* Where the normal instalation goes */
 
237
                                if ((pf = getenv("PROGRAMFILES")) != NULL)
 
238
                                        strcpy(tname, pf);
 
239
                                else
 
240
                                        strcpy(tname, "C:\\Program Files");
 
241
 
 
242
                                strcat(tname, paths[i]);
 
243
                                if (verb) {
 
244
                                        printf("Looking for MSWindows install at '%s' .. ",tname);
 
245
                                        fflush(stdout);
 
246
                                }
 
247
                                if (aglob_create(&ag, tname))
 
248
                                        error("Searching for '%s' malloc error",paths[i]);
 
249
 
 
250
                                for (;;) {
 
251
                                        char *pp;
 
252
                                        if ((pp = aglob_next(&ag)) == NULL)
 
253
                                                break;
 
254
                                        if (no_ccss >= MAX_EDR_FILES)
 
255
                                                error("Too many ccss files (max %d)",MAX_EDR_FILES);
 
256
                                        ccss_names[no_ccss++] = pp;
 
257
                                }
 
258
                                aglob_cleanup(&ag);
 
259
 
 
260
                                if (verb && no_ccss == 0) printf("not found\n");
 
261
                        }
 
262
                        /* No EDR files found, so look for CD */
 
263
                        if (no_ccss == 0) {
 
264
                                char buf[400];
 
265
                                char vol_name[MAXNAMEL+1] = { '\000' };
 
266
                                char tname[MAXNAMEL+1] = { '\000' };
 
267
                                int len, j;
 
268
 
 
269
                                if (verb) { printf("Looking for i1d3 install CDROM .. "); fflush(stdout); }
 
270
 
 
271
                                len = GetLogicalDriveStrings(400, buf);
 
272
                                if (len > 400)
 
273
                                        error("GetLogicalDriveStrings too large");
 
274
                                for (i = 0; ;) {                /* For all drives */
 
275
                                        if (buf[i] == '\000')
 
276
                                                break;
 
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')
 
283
                                                                        break;
 
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]);
 
288
                                                                        if (verb)
 
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");
 
294
                                                                        not_edr = 1;
 
295
                                                                        break;
 
296
                                                                }
 
297
                                                        }
 
298
                                                        if (vols[j][0] != '\000')
 
299
                                                                break;
 
300
                                                }
 
301
                                        }
 
302
                                        i += strlen(buf + i) + 1;
 
303
                                }
 
304
                                if (buf[i] == '\000' && verb)
 
305
                                        printf("No volume & Setup.exe found\n");
 
306
 
 
307
                        }
 
308
                }
 
309
#endif /* NT */
 
310
 
 
311
#if defined(UNIX) && defined(__APPLE__)
 
312
                {
 
313
                        int i;
 
314
 
 
315
                        /* Typical instalation locations */
 
316
                        char *paths[] = {
 
317
                                "/Library/Application Support/X-Rite/Devices/i1d3xrdevice/Contents/Resources/Calibrations/*.edr",
 
318
                                ""
 
319
                        };
 
320
 
 
321
                        /* Typical native volume names the CDROM may have */
 
322
                        char *vols[] = {
 
323
                                "/Volumes/i1Profiler",
 
324
                                "/Volumes/ColorMunki Display",
 
325
                                ""
 
326
                        };
 
327
                        /* Corresponding setup filenames for each volume name */
 
328
                        char *setupnames[] = {
 
329
                                "Installer/Setup.exe",
 
330
                                "Installer/ColorMunkiDisplaySetup.exe",
 
331
                                ""
 
332
                        };
 
333
 
 
334
                        /* See if the files are already installed for the OEM */
 
335
                        for (i = 0;;i++) {
 
336
                                aglob ag;
 
337
 
 
338
                                if (paths[i][0] == '\000')
 
339
                                        break;
 
340
 
 
341
                                if (verb) {
 
342
                                        printf("Looking for OS X install at '%s' .. ",paths[i]);
 
343
                                        fflush(stdout);
 
344
                                }
 
345
                                if (aglob_create(&ag, paths[i]))
 
346
                                        error("Searching for '%s' malloc error",paths[i]);
 
347
 
 
348
                                for (;;) {
 
349
                                        char *pp;
 
350
                                        if ((pp = aglob_next(&ag)) == NULL)
 
351
                                                break;
 
352
                                        if (no_ccss >= MAX_EDR_FILES)
 
353
                                                error("Too many ccss files (max %d)",MAX_EDR_FILES);
 
354
                                        ccss_names[no_ccss++] = pp;
 
355
                                }
 
356
                                aglob_cleanup(&ag);
 
357
 
 
358
                                if (verb && no_ccss == 0) printf("not found\n");
 
359
                        }
 
360
 
 
361
                        /* No EDR files found, so look for CD */
 
362
                        if (no_ccss == 0) {
 
363
                                int j;
 
364
                                char tname[MAXNAMEL+1] = { '\000' };
 
365
 
 
366
                                if (verb) { printf("Looking for i1d3 install CDROM .. \n"); fflush(stdout); }
 
367
 
 
368
                                for (j = 0; ; j++) {
 
369
                                        if (vols[j][0] == '\000')
 
370
                                                break;
 
371
 
 
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");
 
377
                                        strcat(tname, "/");
 
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");
 
386
                                                not_edr = 1;
 
387
                                                amount = 1;             /* Remember to unmount */
 
388
                                                break;
 
389
                                        }
 
390
 
 
391
                                        /* Not already mounted. */
 
392
                                        if (access(vols[j], 0) == 0) {
 
393
                                                struct statfs buf;
 
394
                                                char sbuf[MAXNAMEL+1 + 100];
 
395
                                                int sl, rv;
 
396
                                                if (verb) { printf("no\nMounting ISO partition .. "); fflush(stdout); }
 
397
        
 
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';
 
407
                                                else
 
408
                                                        error("\nUnable to determine CDROM mount point from '%s'",buf.f_mntfromname);
 
409
        
 
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);
 
418
                                                        system(sbuf);
 
419
                                                        error("\nMounting ISO9660 volume of CDROM failed with %d",rv); 
 
420
                                                }
 
421
                                                if (verb)
 
422
                                                        printf("done\n");
 
423
                                                strcat(tname, "/");
 
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");
 
429
                                                not_edr = 1;
 
430
                                                amount = 1;             /* Remember to unmount */
 
431
                                                break;
 
432
                                        }
 
433
                                }
 
434
                                if (no_ccss == 0)
 
435
                                        if (verb) printf("not found\n");
 
436
                        }
 
437
                }
 
438
#endif /* UNIX && __APPLE__ */
 
439
 
 
440
#if defined(UNIX) && !defined(__APPLE__)
 
441
                {
 
442
                        char tname[MAXNAMEL+1] = { '\000' };
 
443
                        int j, k;
 
444
 
 
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 */
 
448
                                "/media/i1Profiler",
 
449
                                "/media/ColorMunki Displ",
 
450
                                "/mnt/cdrom",
 
451
                                "/mnt/cdrecorder",
 
452
                                "/media/cdrom",
 
453
                                "/media/cdrecorder",
 
454
                                "/cdrom",
 
455
                                "/cdrecorder",
 
456
                                ""
 
457
                        };
 
458
                        char *setupnames[] = {
 
459
                                "Installer/Setup.exe",
 
460
                                "Installer/ColorMunkiDisplaySetup.exe",
 
461
                                ""
 
462
                        };
 
463
 
 
464
                        if (verb)
 
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 ! */
 
468
                        for (j = 0;;j++) {
 
469
                                if (vols[j][0] == '\000')
 
470
                                        break;
 
471
                                for (k = 0;;k++) {
 
472
                                        if (setupnames[k][0] == '\000')
 
473
                                                break;
 
474
                                
 
475
                                        strcpy(tname, vols[j]);
 
476
                                        strcat(tname, "/");
 
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");
 
484
                                                not_edr = 1;
 
485
                                                break;          
 
486
                                        }
 
487
                                }
 
488
                                if (setupnames[k][0] != '\000') /* We got it */
 
489
                                        break;
 
490
                        }
 
491
                        if (no_ccss == 0)
 
492
                                if (verb) printf("not found\n");
 
493
                }
 
494
#endif  /* UNIX */
 
495
        }
 
496
 
 
497
        if (no_ccss == 0) {
 
498
                if (amount) umiso(amount_path);
 
499
                error("No CD found, no Setup.exe or list of EDR or CCSS files provided");
 
500
        }
 
501
 
 
502
        if (not_edr) {  /* Must be Setup.exe */
 
503
                xfile *xf0 = NULL;
 
504
                xfile *xf1 = NULL;
 
505
                xfile *xf2 = NULL;
 
506
                xfile *xf3 = NULL;
 
507
 
 
508
                /* Load up the Seup.exe file */
 
509
                xf0 = load_file(ccss_names[0], verb);
 
510
 
 
511
#ifdef NEVER
 
512
                /* Extract .msi from it */
 
513
                xf1 = inno_extract(xf0, "{tmp}\\XRD i1d3.msi", verb);
 
514
                del_xf(xf0);
 
515
 
 
516
                /* Extract the .cab from it */
 
517
                xf2 = msi_extract(xf1, "XRD_i1d3.cab", verb);
 
518
                del_xf(xf1);
 
519
#else
 
520
 
 
521
                /* Extract the .cab directly from Setup.exe */
 
522
                xf2 = msi_extract(xf0, "XRD_i1d3.cab", verb);
 
523
                del_xf(xf0);
 
524
#endif
 
525
 
 
526
                /* Extract the .edr's from it */
 
527
                xf3 = cab_extract(xf2, ".edr", verb);
 
528
                del_xf(xf2);
 
529
 
 
530
                free(ccss_names[0]);
 
531
                no_ccss = 0;
 
532
 
 
533
                /* Translate all the .edr's */
 
534
                for (i = 0; xf3[i].name != NULL; i++) {
 
535
                        if (verb)
 
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))
 
538
                                                                                                 == NULL) {
 
539
                                warning("Failed to parse EDR '%s'\n",xf3[i].name);
 
540
                        } else  {
 
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");
 
545
                        }
 
546
                }
 
547
                del_xf(xf3);
 
548
 
 
549
                if(amount) umiso(amount_path);
 
550
 
 
551
                /* Also look for any ccss files in ../ref */
 
552
                {
 
553
                        int len;
 
554
                        char *pp;
 
555
                        char tname[MAXNAMEL+1] = { '\000' };
 
556
                        aglob ag;
 
557
 
 
558
                        strcpy(tname, exe_path);
 
559
 
 
560
                        len = strlen(tname);
 
561
                        if ((pp = strrchr(tname, '/')) != NULL)
 
562
                                *pp = '\000';
 
563
                        if ((pp = strrchr(tname, '/')) != NULL) {
 
564
                                strcpy(pp, "/ref/*.ccss");
 
565
        
 
566
                                if (aglob_create(&ag, tname))
 
567
                                        error("Searching for '%s' malloc error",tname);
 
568
        
 
569
                                for (;;) {
 
570
                                        if ((pp = aglob_next(&ag)) == NULL)
 
571
                                                break;
 
572
                                        if (no_ccss >= MAX_EDR_FILES)
 
573
                                                error("Too many ccss files (max %d)",MAX_EDR_FILES);
 
574
                                        ccss_names[no_ccss] = pp;
 
575
                                        if (verb)
 
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;
 
583
                                                continue;
 
584
                                        }
 
585
                                        no_ccss++;
 
586
                                }
 
587
                                aglob_cleanup(&ag);
 
588
                        }
 
589
                }
 
590
 
 
591
        /* Given .edr and .ccss files */
 
592
        } else {
 
593
 
 
594
                /* Load up each .edr or .ccss */
 
595
                for (i = 0; i < no_ccss; i++) {
 
596
                        /* If .ccss */
 
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))) {
 
600
                                if (verb)
 
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);
 
606
                                        free(ccss_names[i]);
 
607
                                        ccss_names[i] = NULL;
 
608
                                        continue;
 
609
                                }
 
610
 
 
611
                        /* If .edr */
 
612
                        } else {
 
613
                                if (verb)
 
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]);
 
617
                                        free(ccss_names[i]);
 
618
                                        ccss_names[i] = NULL;
 
619
                                        continue;
 
620
                                }
 
621
                        }
 
622
 
 
623
                }
 
624
        }
 
625
 
 
626
        /* We now have all the ccss objects loaded into an array. Save or install them all */
 
627
        
 
628
        if (install)
 
629
                install_dir = "color";          /* Install them in color sub-directory */
 
630
 
 
631
        /* Save each ccss file */
 
632
        for (i = 0; i < no_ccss; i++) {
 
633
                char *edrname;
 
634
                int len;
 
635
                char *install_name = NULL;
 
636
 
 
637
                if (ccss_names[i] == NULL)              /* Couldn'te load this */
 
638
                        continue;
 
639
 
 
640
                /* Get basename of file */
 
641
                if ((edrname = strrchr(ccss_names[i], '/')) == NULL)
 
642
                        edrname = ccss_names[i];
 
643
                else
 
644
                        edrname++;
 
645
 
 
646
                /* Create install path and name */
 
647
 
 
648
                len = 0;
 
649
                if (install_dir != NULL)
 
650
                        len += strlen(install_dir) + 1;
 
651
 
 
652
                len += strlen(edrname) + 2;
 
653
 
 
654
                if ((install_name = malloc(len)) == NULL)
 
655
                        error("Malloc failed on install_name\n");
 
656
                install_name[0] = '\000';
 
657
 
 
658
                if (install_dir != NULL && install_dir[0] != '\000') {
 
659
                        strcpy(install_name, install_dir);
 
660
                        strcat(install_name, "/");
 
661
                }
 
662
                strcat(install_name, edrname);
 
663
 
 
664
                /* Fix extension */
 
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");
 
669
 
 
670
                if (install) {
 
671
                        char **paths = NULL;
 
672
                        int npaths = 0;
 
673
 
 
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);
 
677
                        }
 
678
                        if (verb)
 
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]);
 
682
                        }
 
683
                        xdg_free(paths, npaths);
 
684
 
 
685
                } else {
 
686
                        if (verb)
 
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);
 
690
                        }
 
691
                }
 
692
                ccss_objs[i]->del(ccss_objs[i]);
 
693
                free(ccss_names[i]);
 
694
 
 
695
                if (install_name != NULL)
 
696
                        free(install_name);
 
697
        }
 
698
 
 
699
        return 0;
 
700
}
 
701
 
 
702
/* ========================================================= */
 
703
 
 
704
/* Take a 64 sized return buffer, and convert it to an ORD64 */
 
705
static ORD64 buf2ord64(unsigned char *buf) {
 
706
        ORD64 val;
 
707
        val = buf[7];
 
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]));
 
715
        return val;
 
716
}
 
717
 
 
718
/* Take a word sized return buffer, and convert it to an unsigned int */
 
719
static unsigned int buf2uint(unsigned char *buf) {
 
720
        unsigned int val;
 
721
        val = buf[3];
 
722
        val = ((val << 8) + (0xff & buf[2]));
 
723
        val = ((val << 8) + (0xff & buf[1]));
 
724
        val = ((val << 8) + (0xff & buf[0]));
 
725
        return val;
 
726
}
 
727
 
 
728
/* Take a word sized return buffer, and convert it to an int */
 
729
static int buf2int(unsigned char *buf) {
 
730
        int val;
 
731
        val = buf[3];
 
732
        val = ((val << 8) + (0xff & buf[2]));
 
733
        val = ((val << 8) + (0xff & buf[1]));
 
734
        val = ((val << 8) + (0xff & buf[0]));
 
735
        return val;
 
736
}
 
737
 
 
738
/* Take a short sized return buffer, and convert it to an int */
 
739
static int buf2short(unsigned char *buf) {
 
740
        int val;
 
741
        val = buf[1];
 
742
        val = ((val << 8) + (0xff & buf[0]));
 
743
        return val;
 
744
}
 
745
 
 
746
// Print bytes as hex to fp
 
747
static void dump_bytes(FILE *fp, char *pfx, unsigned char *buf, int len) {
 
748
        int i, j, ii;
 
749
        for (i = j = 0; i < len; i++) {
 
750
                if ((i % 16) == 0)
 
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++)
 
755
                                fprintf(fp,"   ");
 
756
                        fprintf(fp,"  ");
 
757
                        for (; j <= i; j++) {
 
758
                                if (isprint(buf[j]))
 
759
                                        fprintf(fp,"%c",buf[j]);
 
760
                                else
 
761
                                        fprintf(fp,".",buf[j]);
 
762
                        }
 
763
                        fprintf(fp,"\n");
 
764
                }
 
765
        }
 
766
}
 
767
 
 
768
 
 
769
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 
770
/* A list of files stored in memory. The last entry of the list has name == NULL */
 
771
 
 
772
/* return a list with the given number of available entries */
 
773
xfile *new_xf(int n) {
 
774
        xfile *l;
 
775
 
 
776
        if ((l = (xfile *)calloc((n + 1), sizeof(xfile))) == NULL) {
 
777
                fprintf(stderr,"Failed to allocate xfile structure\n");
 
778
                exit(-1);
 
779
        }
 
780
 
 
781
        return l;
 
782
}
 
783
 
 
784
/* Add an entry to the list. Return the pointer to that entry */
 
785
xfile *add_xf(xfile **l) {
 
786
        int n;
 
787
        xfile *ll;
 
788
 
 
789
        for (ll = *l, n = 0; ll->name != NULL; ll++, n++)
 
790
                ;
 
791
 
 
792
        if ((*l = (xfile *)realloc(*l, (n+2) * sizeof(xfile))) == NULL) {
 
793
                fprintf(stderr,"Failed to realloc xfile structure\n");
 
794
                exit(-1);
 
795
        }
 
796
        (*l)[n+1].name = NULL;          /* End marker */
 
797
        (*l)[n+1].buf = NULL;
 
798
        (*l)[n+1].len = 0;
 
799
 
 
800
        return &(*l)[n];
 
801
}
 
802
 
 
803
 
 
804
/* Free up a list */
 
805
void del_xf(xfile *l) {
 
806
        int n;
 
807
 
 
808
        if (l != NULL) {
 
809
                for (n = 0; l[n].name != NULL; n++) {
 
810
                        free(l[n].name);
 
811
                        if (l[n].buf != NULL)
 
812
                                free(l[n].buf);
 
813
                }
 
814
                free(l);
 
815
        }
 
816
}
 
817
 
 
818
/* ================================================================ */
 
819
/* Load a disk file into an xfile */
 
820
 
 
821
static xfile *load_file(char *sname, int verb) {
 
822
        FILE *fp;
 
823
        unsigned char *ibuf;
 
824
        unsigned long ilen, bread;
 
825
        xfile *xf;
 
826
 
 
827
        if (verb) printf("Loading file '%s'\n",sname);
 
828
 
 
829
        /* Open up the file for reading */
 
830
#if !defined(O_CREAT) && !defined(_O_CREAT)
 
831
# error "Need to #include fcntl.h!"
 
832
#endif
 
833
#if defined(O_BINARY) || defined(_O_BINARY)
 
834
        if ((fp = fopen(sname,"rb")) == NULL)
 
835
#else
 
836
        if ((fp = fopen(sname,"r")) == NULL)
 
837
#endif
 
838
        {
 
839
                fprintf(stderr,"Can't open file '%s'\n",sname);
 
840
                exit(-1);
 
841
        }
 
842
 
 
843
        /* Figure out how big it is */
 
844
        if (fseek(fp, 0, SEEK_END)) {
 
845
                fprintf(stderr,"Seek to EOF failed\n");
 
846
                exit(-1);
 
847
        }
 
848
        ilen = (unsigned long)ftell(fp);
 
849
 
 
850
        if (verb > 1) printf("Size of file '%s' is %d bytes\n",sname, ilen);
 
851
 
 
852
        if (fseek(fp, 0, SEEK_SET)) {
 
853
                fprintf(stderr,"Seek to SOF of file '%s' failed\n",sname);
 
854
                exit(-1);
 
855
        }
 
856
 
 
857
        if ((ibuf = (unsigned char *)malloc(ilen)) == NULL) {
 
858
                fprintf(stderr,"malloc buffer for file '%s' failed\n",sname);
 
859
                exit(-1);
 
860
        }
 
861
 
 
862
        if (verb > 1) printf("(Reading file '%s')\n",sname);
 
863
 
 
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);
 
866
                exit(-1);
 
867
        }
 
868
        fclose(fp);
 
869
 
 
870
        xf = new_xf(1);
 
871
 
 
872
        if ((xf[0].name = strdup(sname)) == NULL) {
 
873
                fprintf(stderr,"mmaloc failed on filename '%s'\n", sname);
 
874
                exit(-1);
 
875
        }
 
876
 
 
877
        xf[0].buf = ibuf;
 
878
        xf[0].len = ilen;
 
879
 
 
880
        return xf;
 
881
}
 
882
 
 
883
/* ========================================================= */
 
884
/* EDR to CCSS */
 
885
 
 
886
/* Given a buffer holding and EDR file, parse it and return a ccss */
 
887
/* Return NULL on error */
 
888
static ccss *parse_EDR(
 
889
        unsigned char *buf,
 
890
        unsigned long len,
 
891
        char *name,                             /* Name of the file */
 
892
        int verb                                /* Verbose flag */
 
893
) {
 
894
        int i, j;
 
895
        FILE *fp;
 
896
        unsigned char *nbuf;
 
897
        unsigned long nlen;
 
898
        unsigned int off;
 
899
        unsigned char *dbuf = NULL;     /* Buffer for spectral samples */
 
900
        INR64 edrdate;
 
901
        char creatdate[30];
 
902
        char dispdesc[256];
 
903
        int ttmin, ttmax;       /* Min & max technology strings (inclusive) */
 
904
        char **ttstrings;       /* Corresponding technology strings */
 
905
        int ttype;                      /* Technology type idex */
 
906
        int nsets, set;
 
907
        xspect *samples = NULL, sp;
 
908
        int hasspec;
 
909
        double nmstart, nmend, nmspace;
 
910
        int nsamples;
 
911
        ccss *rv;
 
912
 
 
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 */
 
915
        {
 
916
                ttmin = 0;
 
917
                ttmax = 22;
 
918
                if ((ttstrings = malloc(sizeof(char *) * (ttmax - ttmin + 2))) == NULL) {
 
919
                        if (verb) printf("Malloc failed\n");
 
920
                        return NULL;
 
921
                }
 
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";
 
946
        }
 
947
 
 
948
        if (len < 600) {
 
949
                if (verb) printf("Unable to read '%s' header\n",name);
 
950
                return NULL;
 
951
        }
 
952
        nbuf = buf + 600;               /* Next time we "read" the file */
 
953
        nlen = len - 600;
 
954
 
 
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);
 
958
                return NULL;
 
959
        }
 
960
 
 
961
        /* Creation Date&time of EDR */
 
962
        edrdate = buf2ord64(buf + 0x0018);
 
963
        strcpy(creatdate, ctime_64(&edrdate));
 
964
        
 
965
        /* Creation tool string @ 0x0020 */
 
966
 
 
967
        /* Display description */
 
968
        strncpy(dispdesc, (char *)buf + 0x0060, 255); dispdesc[255] = '\000';
 
969
 
 
970
        /* Technology type index. */
 
971
        ttype = buf2int(buf + 0x0160);
 
972
 
 
973
        /* Number of data sets */
 
974
        nsets = buf2int(buf + 0x0164);
 
975
 
 
976
        if (nsets < 3 || nsets > 100) {
 
977
                if (verb) printf("File '%s' number of data sets %d out of range\n",name,nsets);
 
978
                return NULL;
 
979
        }
 
980
 
 
981
        /* Model number string @ 0x0168 ? */
 
982
        /* Part code string @ 0x01a8 ? */
 
983
        /* Another number string @ 0x01e8 ? */
 
984
 
 
985
        /* Unknown Flag/number = 1 @ 0x022c */
 
986
 
 
987
        /* "has spectral data" flag ? */
 
988
        hasspec = buf2short(buf + 0x022E);
 
989
        if (hasspec != 1) {
 
990
                if (verb) printf("Has Data flag != 1 in EDR file '%s'\n",name);
 
991
                return NULL;
 
992
        }
 
993
        
 
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));
 
998
        
 
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);
 
1003
        sp.norm = 1.0;
 
1004
 
 
1005
        /* Unknown Flag/number = 0 @ 0x0248 */
 
1006
        /* Error if not 0 ??? */
 
1007
        
 
1008
        if (hasspec) {
 
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");
 
1012
                        return NULL;
 
1013
                }
 
1014
        }
 
1015
 
 
1016
        /* Read the sets of data */
 
1017
        for (set = 0; set < nsets; set++) {
 
1018
 
 
1019
                /* "Read" in the 128 byte data set header */
 
1020
                buf = nbuf;
 
1021
                len = nlen;
 
1022
                if (len < 128) {
 
1023
                        if (verb) printf("Unable to read file '%s' set %d data header\n",name,set);
 
1024
                        if (samples != NULL) free(samples);
 
1025
                        return NULL;
 
1026
                }
 
1027
                nbuf = buf + 128;               /* Next time we "read" the file */
 
1028
                nlen = len - 128;
 
1029
 
 
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);
 
1034
                        return NULL;
 
1035
                }
 
1036
 
 
1037
                /* double Yxy(z) of sample at +0x0058 in data header ? */
 
1038
 
 
1039
                if (hasspec == 0)       /* No spectral data, so skip it */
 
1040
                        continue;
 
1041
 
 
1042
                /* Read in the 28 byte data set header */
 
1043
                buf = nbuf;
 
1044
                len = nlen;
 
1045
                if (len < 28) {
 
1046
                        if (verb) printf("Unable to read file '%s' set %d spectral data  header\n",name,set);
 
1047
                        if (samples != NULL) free(samples);
 
1048
                        return NULL;
 
1049
                }
 
1050
                nbuf = buf + 28;                /* Next time we "read" the file */
 
1051
                nlen = len - 28;
 
1052
 
 
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);
 
1057
                        return NULL;
 
1058
                }
 
1059
 
 
1060
                /* Number of doubles in set */
 
1061
                nsamples = buf2int(buf + 0x0010);
 
1062
 
 
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);
 
1066
                        return NULL;
 
1067
                }
 
1068
 
 
1069
                /* Read in the spectral values */
 
1070
                buf = nbuf;
 
1071
                len = nlen;
 
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);
 
1075
                        return NULL;
 
1076
                }
 
1077
                nbuf = buf + 8 * sp.spec_n;             /* Next time we "read" the file */
 
1078
                nlen = len - 8 * sp.spec_n;
 
1079
 
 
1080
                XSPECT_COPY_INFO(&samples[set], &sp);
 
1081
 
 
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;
 
1087
                }
 
1088
#ifdef PLOT_SAMPLES
 
1089
                /* Plot the spectra */
 
1090
                {
 
1091
                        double xx[500];
 
1092
                        double y1[500];
 
1093
        
 
1094
                        for (j = 0; j < samples[set].spec_n; j++) {
 
1095
                                xx[j] = XSPECT_XWL(&sp, j);
 
1096
                                y1[j] = samples[set].spec[j];
 
1097
                        }
 
1098
                        printf("EDR sample %d (uncorrected)\n",set+1);
 
1099
                        do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, samples[set].spec_n);
 
1100
                }
 
1101
#endif /* PLOT_SAMPLES */
 
1102
 
 
1103
        }
 
1104
 
 
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. */
 
1109
 
 
1110
        /* Try and read in the 92 byte correction header */
 
1111
        buf = nbuf;
 
1112
        len = nlen;
 
1113
        if (len >= 92) {
 
1114
                nbuf = buf + 92;                /* Next time we "read" the file */
 
1115
                nlen = len - 92;
 
1116
 
 
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);
 
1121
                        return NULL;
 
1122
                }
 
1123
 
 
1124
                /* Number of doubles in set */
 
1125
                nsamples = buf2int(buf + 0x0050);
 
1126
 
 
1127
                if (nsamples == 351) {
 
1128
                        sp.spec_wl_short = 380.0;
 
1129
                        sp.spec_wl_long = 730.0;
 
1130
                        sp.spec_n = nsamples;
 
1131
                        sp.norm = 1.0;
 
1132
                } else if (nsamples == 401) {
 
1133
                        sp.spec_wl_short = 380.0;
 
1134
                        sp.spec_wl_long = 780.0;
 
1135
                        sp.spec_n = nsamples;
 
1136
                        sp.norm = 1.0;
 
1137
                } else {
 
1138
                        if (verb) printf("File '%s' correction data has unknown range %d\n\n",name,nsamples);
 
1139
                        if (samples != NULL) free(samples);
 
1140
                        return NULL;
 
1141
                }
 
1142
 
 
1143
                /* Read in the spectral values */
 
1144
                buf = nbuf;
 
1145
                len = nlen;
 
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);
 
1149
                        return NULL;
 
1150
                }
 
1151
                nbuf = buf + 8 * sp.spec_n;             /* Next time we "read" the file */
 
1152
                nlen = len - 8 * sp.spec_n;
 
1153
 
 
1154
                for (j = 0; j < sp.spec_n; j++) {
 
1155
                        sp.spec[j] = IEEE754_64todouble(buf2ord64(buf + j * 8));
 
1156
                }
 
1157
 
 
1158
#ifdef PLOT_SAMPLES
 
1159
                /* Plot the spectra */
 
1160
                {
 
1161
                        double xx[500];
 
1162
                        double y1[500];
 
1163
        
 
1164
                        for (j = 0; j < sp.spec_n; j++) {
 
1165
                                xx[j] = XSPECT_XWL(&sp, j);
 
1166
                                y1[j] = sp.spec[j];
 
1167
                        }
 
1168
                        printf("Correction data\n");
 
1169
                        do_plot6(xx, y1, NULL, NULL, NULL, NULL, NULL, sp.spec_n);
 
1170
                }
 
1171
#endif /* PLOT_SAMPLES */
 
1172
 
 
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));
 
1177
                }
 
1178
        }
 
1179
 
 
1180
        /* Creat a ccss */
 
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);
 
1184
                return NULL;
 
1185
        }
 
1186
 
 
1187
        if (ttype < ttmin || ttype > ttmax) {
 
1188
                ttype = ttmax + 1;                      /* Set to Unknown */
 
1189
        }
 
1190
 
 
1191
        /* Set it's values */
 
1192
        rv->set_ccss(rv, "X-Rite", creatdate, NULL, dispdesc, ttstrings[ttype], "CS1000", samples, nsets);      
 
1193
 
 
1194
        free(ttstrings);
 
1195
        free(samples);
 
1196
 
 
1197
        return rv;
 
1198
}
 
1199
 
 
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 */
 
1205
) {
 
1206
        FILE *fp;
 
1207
        unsigned char *ibuf;
 
1208
        unsigned long ilen, bread;
 
1209
        ccss *rv;
 
1210
 
 
1211
        /* Open up the file for reading */
 
1212
#if !defined(O_CREAT) && !defined(_O_CREAT)
 
1213
# error "Need to #include fcntl.h!"
 
1214
#endif
 
1215
#if defined(O_BINARY) || defined(_O_BINARY)
 
1216
        if ((fp = fopen(name,"rb")) == NULL)
 
1217
#else
 
1218
        if ((fp = fopen(name,"r")) == NULL)
 
1219
#endif
 
1220
        {
 
1221
                if (verb) printf("Unable to open file file '%s'\n",name);
 
1222
                return NULL;
 
1223
        }
 
1224
 
 
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);
 
1228
                return NULL;
 
1229
        }
 
1230
        ilen = (unsigned long)ftell(fp);
 
1231
 
 
1232
        if (fseek(fp, 0, SEEK_SET)) {
 
1233
                if (verb) printf("Seek to SOF '%s' failed'\n",name);
 
1234
                return NULL;
 
1235
        }
 
1236
 
 
1237
        if ((ibuf = (unsigned char *)malloc(ilen)) == NULL) {
 
1238
                if (verb) printf("Malloc of buffer for file '%s' failed\n",name);
 
1239
                return NULL;
 
1240
        }
 
1241
 
 
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);
 
1244
                free(ibuf);
 
1245
                return NULL;
 
1246
        }
 
1247
        fclose(fp);
 
1248
 
 
1249
        rv = parse_EDR(ibuf, ilen, name, verb);
 
1250
 
 
1251
        free(ibuf);
 
1252
 
 
1253
        return rv;
 
1254
}
 
1255
 
 
1256
/* ========================================================= */
 
1257
/* Extract a file from an inno archive. */
 
1258
 
 
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.) */
 
1262
 
 
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 };
 
1267
 
 
1268
 
 
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) {
 
1273
        SRes res;
 
1274
        CLzmaDec state;
 
1275
        SizeT slen = *srcLen;
 
1276
        SizeT dlen = *destLen;
 
1277
        SizeT len;
 
1278
        int doneheader = 0;
 
1279
 
 
1280
        if (slen < (4 + 5))
 
1281
                return SZ_ERROR_INPUT_EOF;
 
1282
 
 
1283
        LzmaDec_Construct(&state);
 
1284
        res = LzmaDec_Allocate(&state, src + 4, LZMA_PROPS_SIZE, alloc);
 
1285
        if (res != SZ_OK)
 
1286
                return res;
 
1287
 
 
1288
        *srcLen = 0;
 
1289
        *destLen = 0;
 
1290
        LzmaDec_Init(&state);
 
1291
        
 
1292
        for (;slen > 0 && dlen > 0;) {
 
1293
                SizeT ddlen;
 
1294
 
 
1295
                if (slen < 4)
 
1296
                        return SZ_ERROR_INPUT_EOF;
 
1297
                if (dlen == 0)
 
1298
                        return SZ_ERROR_OUTPUT_EOF;
 
1299
 
 
1300
                /* Skip the CRC */
 
1301
                src += 4;
 
1302
                slen -= 4;
 
1303
                *srcLen += 4;
 
1304
 
 
1305
                len = 4096;                             /* Bytes to next CRC */
 
1306
 
 
1307
                if (doneheader == 0) {          /* Skip the 5 + 8 byte header */
 
1308
                        int inc = 5;
 
1309
                        len -= inc;
 
1310
                        src += inc;
 
1311
                        slen -= inc;
 
1312
                        *srcLen += inc;
 
1313
                        doneheader = 1;
 
1314
                }
 
1315
 
 
1316
                if (len > slen)
 
1317
                        len = slen;
 
1318
                ddlen = dlen;
 
1319
 
 
1320
                res = LzmaDec_DecodeToBuf(&state, dest, &ddlen, src, &len, finishMode, status);
 
1321
                if (res != SZ_OK) {
 
1322
                        LzmaDec_Free(&state, alloc);
 
1323
                        return res;
 
1324
                }
 
1325
 
 
1326
                src += len;
 
1327
                slen -= len;
 
1328
                *srcLen += len;
 
1329
 
 
1330
                dest += ddlen;
 
1331
                dlen -= ddlen;
 
1332
                *destLen += ddlen;
 
1333
 
 
1334
                if (*status == LZMA_STATUS_FINISHED_WITH_MARK
 
1335
                 || *status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK) {
 
1336
                        break;
 
1337
                }
 
1338
        }
 
1339
        LzmaDec_Free(&state, alloc);
 
1340
 
 
1341
        return res;
 
1342
}
 
1343
 
 
1344
/* extract the given file from Setup.exe */
 
1345
 
 
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) {
 
1349
        int i, j, k;
 
1350
        unsigned char *ibuf;
 
1351
        unsigned long ilen;
 
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;
 
1361
        SRes rv;
 
1362
        ELzmaStatus dstat;
 
1363
        unsigned long ix;
 
1364
        int filelen = strlen(tfilename);
 
1365
        unsigned long fileso, filesz;
 
1366
        char *cp;
 
1367
        xfile *xf = NULL;
 
1368
 
 
1369
        ibuf = xi[0].buf;
 
1370
        ilen = xi[0].len;
 
1371
 
 
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);
 
1380
                        ldrbase = i;
 
1381
                        break;
 
1382
                }
 
1383
        }
 
1384
        if (i >= (ilen - 4)) {
 
1385
                fprintf(stderr,"Failed to locate loader base\n");
 
1386
                exit(-1);
 
1387
        }
 
1388
 
 
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') {
 
1397
                        haddr = i;
 
1398
                }
 
1399
        }
 
1400
 
 
1401
        if (verb > 1) printf("Found header at 0x%x\n",i);
 
1402
 
 
1403
        /* Use the last header found (or cound search all found ?) */
 
1404
        haddr += 64;    /* Skip Inno header */
 
1405
 
 
1406
        /* Next 9 bytes are the compression header */
 
1407
        haddr += 4;             /* Skip Inno header CRC */
 
1408
        cblocklen = buf2uint(ibuf + haddr);             /* Compressed block length */
 
1409
 
 
1410
        if (verb > 1) printf("Header compression block length = %d\n",cblocklen); 
 
1411
 
 
1412
        if ((haddr + cblocklen) > ilen) {
 
1413
                fprintf(stderr,"Compression block is longer than setup.exe\n");
 
1414
                exit(-1);
 
1415
        }
 
1416
 
 
1417
        if (ibuf[haddr + 4] != 1) {
 
1418
                fprintf(stderr,"Inno header is expected to be compressed\n");
 
1419
                exit(-1);
 
1420
        }
 
1421
        haddr += 5;     /* Skip compression header */
 
1422
 
 
1423
        /* We'r now at the start of the compressed data */
 
1424
 
 
1425
        d1sz = cblocklen * 30;
 
1426
        if ((d1buf = (unsigned char *)malloc(d1sz)) == NULL) {
 
1427
                fprintf(stderr,"Failed to allocate decompression buffer\n");
 
1428
                exit(-1);
 
1429
        }
 
1430
 
 
1431
        // if (verb) printf("CRC + lzma at %d\n",haddr);
 
1432
 
 
1433
        srclen = ilen - haddr;
 
1434
        
 
1435
        /* Decode using CRC + 4096 byte blocks */
 
1436
        rv = LzmaDecodeX(d1buf, &d1sz, ibuf + haddr, &srclen, LZMA_FINISH_END, &dstat, &alloc);
 
1437
 
 
1438
        if (rv != SZ_OK) {
 
1439
                fprintf(stderr,"lzma decode failed with rv %d and status %d\n",rv, dstat);
 
1440
                exit(-1);
 
1441
        }
 
1442
        if (verb > 1) printf("Decoded %d bytes to created %d bytes of Header output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen);
 
1443
 
 
1444
//      dump_bytes(stdout, "  ", d1buf, d1sz);
 
1445
 
 
1446
        /* - - - - - - - - - - - - - - - - -*/
 
1447
 
 
1448
        /* Skip to the start of the next compression block header */
 
1449
        haddr += cblocklen;
 
1450
 
 
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");
 
1454
                exit(-1);
 
1455
        }
 
1456
 
 
1457
        /* Next 9 bytes are the compression header */
 
1458
        haddr += 4;             /* Skip Inno header CRC */
 
1459
        cblocklen = buf2uint(ibuf + haddr);             /* Compressed block length */
 
1460
 
 
1461
        if (verb > 1) printf("File Location compression block length = %d\n",cblocklen); 
 
1462
 
 
1463
        if ((haddr + cblocklen) > ilen) {
 
1464
                fprintf(stderr,"2nd compression block is longer than setup.exe\n");
 
1465
                exit(-1);
 
1466
        }
 
1467
 
 
1468
        if (ibuf[haddr + 4] != 1) {
 
1469
                fprintf(stderr,"Inno 2nd header is expected to be compressed\n");
 
1470
                exit(-1);
 
1471
        }
 
1472
        haddr += 5;     /* Skip compression header */
 
1473
 
 
1474
        /* We're now at the start of the compressed data */
 
1475
 
 
1476
        d2sz = cblocklen * 10;
 
1477
        if ((d2buf = (unsigned char *)malloc(d2sz)) == NULL) {
 
1478
                fprintf(stderr,"Failed to allocate 2nd block decompression buffer\n");
 
1479
                exit(-1);
 
1480
        }
 
1481
 
 
1482
        //if (verb) printf("CRC + lzma at %d\n",haddr);
 
1483
        srclen = ilen - haddr;
 
1484
        
 
1485
        /* Decode using CRC + 4096 byte blocks */
 
1486
        rv = LzmaDecodeX(d2buf, &d2sz, ibuf + haddr, &srclen, LZMA_FINISH_END, &dstat, &alloc);
 
1487
 
 
1488
        if (rv != SZ_OK) {
 
1489
                fprintf(stderr,"lzma decode of 2nd block failed with rv %d and status %d\n",rv, dstat);
 
1490
                exit(-1);
 
1491
        }
 
1492
        if (verb > 1) printf("Decoded %d bytes to created %d bytes of File Location output (ratio %.1f)\n",srclen,d1sz,(double)d1sz/srclen);
 
1493
 
 
1494
//      dump_bytes(stdout, "  ", d2buf, d2sz);
 
1495
 
 
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
 
1501
                 && d1buf[i+1] == 0
 
1502
                 && d1buf[i+2] == 0
 
1503
                 && d1buf[i+3] == 0) {
 
1504
                        if (verb > 1) printf("Found it at 0x%x\n",i);
 
1505
                        break;
 
1506
                }
 
1507
        }
 
1508
 
 
1509
        /* Need to skip 8 more strings */
 
1510
        i += 4 + filelen;
 
1511
        for (j = 0; j < 8; j++) {
 
1512
                unsigned long len;
 
1513
                len = buf2uint(d1buf + i);
 
1514
                i += 4 + len;
 
1515
        }
 
1516
        /* Skip another 40 bytes to location entry index */
 
1517
        i += 20;
 
1518
 
 
1519
        ix = buf2uint(d1buf + i);
 
1520
 
 
1521
        if (verb > 1) printf("Got file location index %d at 0x%x\n",ix,i);
 
1522
 
 
1523
 
 
1524
        /* Now get the ix file entry information. */
 
1525
        /* They are in 74 byte structures */
 
1526
        i = ix * 74;
 
1527
 
 
1528
        if ((i + 74) > d2sz) {
 
1529
                fprintf(stderr,"File location structure is out of range\n");
 
1530
                exit(-1);
 
1531
        }
 
1532
        
 
1533
        /* The start offset is at 8 */
 
1534
        fileso = buf2uint(d2buf + i + 8);
 
1535
 
 
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);
 
1540
                exit(-1);
 
1541
        }
 
1542
 
 
1543
        if (verb > 1) printf("File '%s' is at offset 0x%x, length %d\n",tfilename,fileso,filesz);
 
1544
 
 
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);
 
1548
                exit(-1);
 
1549
        }
 
1550
        /* Sanity check */
 
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);
 
1556
                exit(-1);
 
1557
        }
 
1558
 
 
1559
        /* Copy to new buffer and free everything */
 
1560
        msisz = filesz;
 
1561
        if ((msibuf = (unsigned char *)malloc(msisz)) == NULL) {
 
1562
                fprintf(stderr,"Failed to allocate file '%s' buffer\n",tfilename);
 
1563
                exit(-1);
 
1564
        }
 
1565
        memmove(msibuf, ibuf + ldrbase + fileso, filesz);
 
1566
 
 
1567
        free(d1buf);
 
1568
        free(d2buf);
 
1569
 
 
1570
        xf = new_xf(1);
 
1571
 
 
1572
        /* Just return base filename */
 
1573
        if ((cp = strrchr(tfilename, '/')) == NULL
 
1574
         && (cp = strrchr(tfilename, '\\')) == NULL)
 
1575
                cp = tfilename;
 
1576
        else
 
1577
                cp++;
 
1578
 
 
1579
        if ((xf[0].name = strdup(cp)) == NULL) {
 
1580
                fprintf(stderr,"mmaloc failed on filename\n");
 
1581
                exit(-1);
 
1582
        }
 
1583
        xf[0].buf = msibuf;
 
1584
        xf[0].len = filesz;
 
1585
 
 
1586
        if (verb) printf("Returning '%s' length %d from '%s'\n",xf[0].name,xf[0].len, xi[0].name);
 
1587
 
 
1588
        return xf;
 
1589
}
 
1590
 
 
1591
/* ====================================================== */
 
1592
/* Extract the .cab file from another file. */
 
1593
 
 
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) {
 
1598
        int i, j, k;
 
1599
        xfile *xf = NULL;
 
1600
        char *fid = "i1d3.xrdevice";            /* File in .cab to look for */
 
1601
        unsigned long fle = strlen(fid);
 
1602
        unsigned long cabo, cabsz;
 
1603
 
 
1604
        if (verb) printf("Attempting to extract '%s' from '%s'\n",tname,xi[0].name);
 
1605
 
 
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);
 
1612
                        break;
 
1613
                }
 
1614
        }
 
1615
 
 
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);
 
1627
                        break;
 
1628
                }
 
1629
        }
 
1630
 
 
1631
        xf = new_xf(1);
 
1632
 
 
1633
        /* Lookup the .cab size (really 64 bit, but we don't care) */
 
1634
        xf[0].len = buf2uint(xi[0].buf + i + 8);
 
1635
 
 
1636
        if (verb > 1) printf("'%s' is length %d\n",tname,xf[0].len);
 
1637
 
 
1638
        if ((xi[0].len - i) < xf[0].len) {
 
1639
                fprintf(stderr,"Not enough room for .cab file in source\n");
 
1640
                exit(-1);
 
1641
        }  
 
1642
 
 
1643
        if ((xf[0].buf = malloc(xf[0].len)) == NULL) {
 
1644
                fprintf(stderr,"maloc of .cab buffer failed\n");
 
1645
                exit(-1);
 
1646
        }
 
1647
        memmove(xf[0].buf, xi[0].buf + i ,xf[0].len);
 
1648
 
 
1649
        if ((xf[0].name = strdup(tname)) == NULL) {
 
1650
                fprintf(stderr,"maloc of .cab name failed\n");
 
1651
                exit(-1);
 
1652
        }
 
1653
 
 
1654
        if (verb) printf("Extacted '%s' length %d\n",xf[0].name,xf[0].len);
 
1655
 
 
1656
        return xf;
 
1657
}
 
1658
 
 
1659
 
 
1660
/* ================================================================ */
 
1661
/* Extract files of a given type from a .cab file */
 
1662
 
 
1663
/* Interface with inflate.c */
 
1664
/* We use globals for this */
 
1665
 
 
1666
unsigned char *i_buf = NULL;
 
1667
unsigned long i_len = 0;
 
1668
unsigned long i_ix = 0;
 
1669
 
 
1670
unsigned char *o_buf = NULL;
 
1671
unsigned long o_len = 0;
 
1672
unsigned long o_ix = 0;
 
1673
 
 
1674
/* Interface to inflate */
 
1675
 
 
1676
/* fetch the next 8 bits */
 
1677
/* if we get 0xffffffff, we are at EOF */
 
1678
unsigned int inflate_get_byte() {
 
1679
        if (i_ix < i_len)
 
1680
                return i_buf[i_ix++];
 
1681
        return 0xff;
 
1682
}
 
1683
 
 
1684
/* unget 8 bits */
 
1685
void inflate_unget_byte() {
 
1686
        if (i_ix > 0)
 
1687
                i_ix--;
 
1688
}
 
1689
 
 
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);
 
1694
                return 1;
 
1695
        }
 
1696
        memmove(o_buf + o_ix, buf, len);
 
1697
        o_ix += len;
 
1698
        return 0;
 
1699
}
 
1700
 
 
1701
/* Extract all the .edr files from the .cab */
 
1702
static xfile *cab_extract(xfile *xi, char *text, int verb) {
 
1703
        int i, j, k;
 
1704
        xfile *xf = NULL;
 
1705
        unsigned char *buf = xi[0].buf;
 
1706
        unsigned long len = xi[0].len;
 
1707
        unsigned long off;
 
1708
        unsigned long filesize, headeroffset, datastart;
 
1709
        int nofolders, nofiles, flags, comptype;
 
1710
        unsigned int totubytes;
 
1711
        int ufiles = 0;
 
1712
        unsigned char *obuf;
 
1713
        unsigned long olen;
 
1714
 
 
1715
        if (verb) printf("Attempting to extract '*%s' from '%s'\n",text, xi[0].name);
 
1716
 
 
1717
        /* Check it is a .cab file */
 
1718
        if (len < 0x2c
 
1719
         || buf[0] != 0x4d
 
1720
     || buf[1] != 0x53
 
1721
         || buf[2] != 0x43
 
1722
         || buf[3] != 0x46
 
1723
         || buf[4] != 0x00
 
1724
         || buf[5] != 0x00
 
1725
         || buf[6] != 0x00
 
1726
         || buf[7] != 0x00) {
 
1727
                fprintf(stderr,"'%s' is not a .cab file\n",xi[0].name);
 
1728
                exit(-1);
 
1729
        }
 
1730
 
 
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);
 
1736
 
 
1737
        if (filesize != len) {
 
1738
                fprintf(stderr,"'%s' filesize desn't match\n",xi[0].name);
 
1739
                exit(-1);
 
1740
        }
 
1741
        if (nofolders != 1) {
 
1742
                fprintf(stderr,"'%s' has more than one folder\n",xi[0].name);
 
1743
                exit(-1);
 
1744
        }
 
1745
        if (flags != 0) {
 
1746
                fprintf(stderr,"'%s' has non-zero flags\n",xi[0].name);
 
1747
                exit(-1);
 
1748
        }
 
1749
 
 
1750
        /* Read the first folders info (assumed flags == 0) */
 
1751
        datastart = buf2uint(buf + 0x24);
 
1752
        comptype = buf[0x2a];
 
1753
        if (comptype!= 1) {
 
1754
                fprintf(stderr,"'%s' doesn't use MSZip compression\n",xi[0].name);
 
1755
                exit(-1);
 
1756
        }
 
1757
 
 
1758
        if (verb > 1) printf(".cab headeroffset = 0x%x, datastart = 0x%x, nofiles = %d\n",headeroffset,datastart,nofiles);
 
1759
 
 
1760
        /* Look at each file */
 
1761
        for (off = headeroffset, k = 0; k < nofiles; k++) {
 
1762
                unsigned long fsize;            /* Uncompressed size */
 
1763
                unsigned long foff;
 
1764
                short ffix;
 
1765
                char fname[95];
 
1766
                
 
1767
                if (off > (len - 80)) {
 
1768
                        fprintf(stderr,"'%s' too short for directory\n",xi[0].name);
 
1769
                        exit(-1);
 
1770
                }
 
1771
 
 
1772
                fsize = buf2uint(buf + off + 0x00);
 
1773
                foff  = buf2uint(buf + off + 0x04);
 
1774
                ffix  = buf2short(buf + off + 0x08);
 
1775
 
 
1776
                strncpy(fname, (char *)buf + off + 0x10, 94);
 
1777
                fname[94] = '\000';
 
1778
 
 
1779
                if (verb > 1) printf("file %d is '%s' at 0x%x length %d\n",k,fname, foff,fsize);
 
1780
 
 
1781
                off += 0x10 + strlen(fname) + 1;                /* Next entry */
 
1782
        }
 
1783
 
 
1784
        /* Now come the data blocks */
 
1785
        totubytes = 0;
 
1786
        for (off = datastart, j = 0; ; j++) {
 
1787
                unsigned long chsum;
 
1788
                unsigned long cbytes;
 
1789
                unsigned long ubytes;
 
1790
 
 
1791
                if (off > (len - 8)) {
 
1792
                        if (verb > 1) printf("Got to end of data blocks at 0x%x\n",off);
 
1793
                        break;
 
1794
                }
 
1795
 
 
1796
                chsum = buf2uint(buf + off + 0x00);
 
1797
                cbytes = buf2short(buf + off + 0x04);
 
1798
                ubytes = buf2short(buf + off + 0x06);
 
1799
 
 
1800
                if (verb > 1) printf("Compression block %d, cbytes %d, ubytes %d\n",j,cbytes,ubytes);
 
1801
 
 
1802
                totubytes += ubytes;
 
1803
 
 
1804
                off += 8 + cbytes;
 
1805
        }
 
1806
 
 
1807
 
 
1808
        if (verb > 1) printf("Total uncompressed bytes = %d\n",totubytes);
 
1809
 
 
1810
        olen = totubytes;
 
1811
        if ((obuf = malloc(olen)) == NULL) {
 
1812
                fprintf(stderr,"maloc of uncompressed output buffer failed\n");
 
1813
                exit(-1);
 
1814
        }
 
1815
 
 
1816
        o_buf = obuf;
 
1817
        o_len = olen;
 
1818
        o_ix = 0;
 
1819
 
 
1820
        for (off = datastart, j = 0; ; j++) {
 
1821
                unsigned long chsum;
 
1822
                unsigned long cbytes;
 
1823
                unsigned long ubytes;
 
1824
 
 
1825
                if (off > (len - 8))
 
1826
                        break;
 
1827
 
 
1828
                chsum = buf2uint(buf + off + 0x00);
 
1829
                cbytes = buf2short(buf + off + 0x04);
 
1830
                ubytes = buf2short(buf + off + 0x06);
 
1831
 
 
1832
                i_buf = buf + off + 8;
 
1833
                i_len = cbytes;
 
1834
                i_ix = 0;
 
1835
 
 
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");
 
1839
                        exit (-1);
 
1840
                }
 
1841
 
 
1842
                if (inflate()) {
 
1843
                        fprintf(stderr, "inflate of '%s' failed at i_ix 0x%x, o_ix 0x%x\n",xi[0].name,i_ix,o_ix);
 
1844
                        exit (-1);
 
1845
                }
 
1846
 
 
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... */
 
1849
 
 
1850
                off += 8 + cbytes;
 
1851
        }
 
1852
 
 
1853
        xf = new_xf(0);
 
1854
 
 
1855
        /* Create a buffer for each file */
 
1856
        for (ufiles = 0, off = headeroffset, k = 0; k < nofiles; k++) {
 
1857
                unsigned long fsize;            /* Uncompressed size */
 
1858
                unsigned long foff;
 
1859
                short ffix;
 
1860
                char fname[95], *cp;
 
1861
                int namelen;
 
1862
                
 
1863
                fsize = buf2uint(buf + off + 0x00);
 
1864
                foff  = buf2uint(buf + off + 0x04);
 
1865
                ffix  = buf2short(buf + off + 0x08);
 
1866
 
 
1867
                strncpy(fname, (char *)buf + off + 0x10, 94);
 
1868
                fname[94] = '\000';
 
1869
                namelen = strlen(fname);
 
1870
 
 
1871
                /* Lop of the junk in the filename */
 
1872
                if ((cp = strrchr(fname, '.')) != NULL)
 
1873
                        *cp = '\000';
 
1874
                
 
1875
                /* See if it's the type of file we want */
 
1876
                if ((cp = strrchr(fname, '.')) != NULL
 
1877
                 && strcmp(cp, text) == 0) {
 
1878
                        xfile *xx;
 
1879
 
 
1880
                        xx = add_xf(&xf);
 
1881
 
 
1882
                        if (foff >= olen || (foff + fsize) > olen) {
 
1883
                                fprintf(stderr,"file '%s' doesn't fit in decomressed buffer\n");
 
1884
                                exit(-1);
 
1885
                        }
 
1886
                        if ((xx->buf = malloc(fsize)) == NULL) {
 
1887
                                fprintf(stderr,"maloc of file '%s' buffer len %d failed\n",fname,fsize);
 
1888
                                exit(-1);
 
1889
                        }
 
1890
                        xx->len = fsize;
 
1891
                        memmove(xx->buf, obuf + foff, fsize);
 
1892
 
 
1893
                        if ((xx->name = strdup(fname)) == NULL) {
 
1894
                                fprintf(stderr,"maloc of .edr name failed\n");
 
1895
                                exit(-1);
 
1896
                        }
 
1897
                        ufiles++;
 
1898
                }
 
1899
                off += 0x10 + namelen + 1;              /* Next entry */
 
1900
        }
 
1901
 
 
1902
        if (verb) printf("Found %d %s files out of %d files in .cab\n",ufiles, text, nofiles);
 
1903
 
 
1904
        return xf;
 
1905
}
 
1906
 
 
1907
 
 
1908