[tools] add mktitanimg to create Titan (AR7-based) images (#6632)
[openwrt.git] / tools / firmware-utils / src / mktitanimg.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include "mktitanimg.h"
5
6
7 struct checksumrecord
8 {
9                 unsigned int magic;
10         unsigned int    chksum;     /* The checksum for the complete header.
11  Excepting the
12                                            checksum block */
13 };
14 /***************************************************************************
15  * void print_help(void)
16  ***************************************************************************/
17 void print_help(void)
18 {
19         static char* help_page[]=
20         {
21                 "mknspimg version 1.0, Texas Instruments, 2004",
22                 "Syntax:",
23                 "        mknspimg -o outfile -i image1 image2 -a align1 align2 [-v] [-b] [-p prod_id] [-r rel_id] [-s rel_name] [-f flags]",
24                 "Example:",
25                 "        mknspimg -o nsp_image.bin -i kernel.bin files.img -a 0 4096",
26                 "This generates 'nsp_image.bin' from two input files aligning first to 0 and second to 4096 bytes."
27         };
28
29         int num_lines = sizeof(help_page)/sizeof(char*);
30         int i;
31         for(i=0; i < num_lines; i++) {
32                 printf("%s\n", help_page[i]);
33         }
34 }
35
36 /***************************************************************************
37  * void mknspimg_print_hdr(NSP_IMG_HDR* p_img_hdr)
38  ***************************************************************************/
39 void mknspimg_print_hdr(struct nsp_img_hdr *hdr)
40 {
41         struct nsp_img_hdr_chksum       *chksum;
42         struct nsp_img_hdr_section_info *sect_info;
43         struct nsp_img_hdr_sections     *section;
44         int i;
45
46         printf("****************** NSP Image Summary ******************\n");
47         printf("Magic:             0x%x\n",             hdr->head.magic);
48         printf("Image Header Size: 0x%x bytes\n",       hdr->head.hdr_size);
49         printf("Total Image Size:  %d bytes\n",         hdr->head.image_size);
50         printf("Product ID:        0x%x\n",             hdr->head.prod_id);
51         printf("Release ID:        0x%x\n",             hdr->head.rel_id);
52         printf("Version ID:        0x%x\n",             hdr->head.version);
53
54         printf("Offset Info:       0x%x\n",             hdr->head.info_offset);
55         printf("Offset Sect info:  0x%x\n",             hdr->head.sect_info_offset);
56         printf("Offset Sections:   0x%x\n",             hdr->sect_info.sections_offset);
57
58         chksum=(struct nsp_img_hdr_chksum *)((unsigned int)hdr+hdr->head.chksum_offset);
59         printf("Header Checksum:   0x%x\n",             chksum->hdr_chksum);
60
61         printf("+++ Section Information +++\n");
62         printf("# of sections:     %u\n", hdr->sect_info.num_sects);
63         section=&(hdr->sections);
64         for(i = 0; i < hdr->sect_info.num_sects; i++, section++) {
65                 printf("+++++ Section %d +++++\n", i);
66                 printf("Total size:  %u bytes\n",       section->total_size);
67                 printf("Raw Size:    %u bytes\n",       section->raw_size);
68                 printf("Offset:      0x%x\n",           section->offset);
69                 printf("Type:        0x%x\n",           section->type);
70                 printf("Name:        %s\n",             section->name);
71         }
72         printf("*******************************************************\n");
73 }
74
75 CMDLINE_CFG     cmd_line_cfg =
76 {
77         {
78                 /*      MIN     MAX     FLAGS                                   OPTION  */
79                 {       2,      2,      (CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },     /* '-a' align1 align2 */
80                 {       0,      0,      CMDLINE_OPTFLAG_ALLOW },                /* '-b' bootstrap */
81                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-c' */
82                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-d' */
83                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-e' */
84                 {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-f' flags */
85                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-g' */
86                 {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-h' */
87                 {       2,      2,      (CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },     /* '-i arg1 arg2 ' */
88                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-j' */
89                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-k' */
90                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-l' */
91                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-m' */
92                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-n' */
93                 {       1,      1,      (CMDLINE_OPTFLAG_ALLOW | CMDLINE_OPTFLAG_MANDAT) },     /* '-o arg' */
94                 {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-p' PROD_ID */
95                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-q' */
96                 {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-r' REL_ID */
97                 {       1,      1,      CMDLINE_OPTFLAG_ALLOW },                /* '-s' "Release XXX.XXX" */
98                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-t' */
99                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-u' */
100                 {       0,      0,      CMDLINE_OPTFLAG_ALLOW },                /* '-v' control VERBOSE/NON-VERBOSE mode */
101                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-w' */
102                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-x' */
103                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW },               /* '-y' */
104                 {       0,      0,      !CMDLINE_OPTFLAG_ALLOW }                /* '-z' */
105         },
106         {       0,              0,      !CMDLINE_OPTFLAG_ALLOW },               /* global arguments */
107 };
108
109 /***************************************************************************
110  * int nsp_img_write(void* image, char* file, int padding)
111  * Write out the image.
112  ***************************************************************************/
113 int main(int argc, char* argv[], char* env[])
114 {
115         FILE*   nsp_image       = NULL;
116         int header_version=1;
117         int     cmdline_err;
118         char*   cmdline_error_msg;
119
120         char*   filen_kernel;
121         char*   filen_files;
122         char*   filen_out;
123
124         int     i,count;                        /* loop variables */
125         int     num_sects = 2;                  /* We require exactly two image with -i option
126                                                            (see CMDLINE_CFG structure above) */
127         int     desc_count=0;
128         int     total = 0;
129
130         int     header_size=0;
131         struct nsp_img_hdr_head         *img_hdr_head;  /* Start of image header */
132         struct nsp_img_hdr_info *img_hdr_info;
133         struct nsp_img_hdr_section_info *img_hdr_section_info ;
134         struct nsp_img_hdr_sections     *img_hdr_sections, *section;    /* Section pointers */
135         
136
137         /* Configure the command line. */
138         cmdline_configure(&cmd_line_cfg);
139
140         /* Read and parse the command line. */
141         cmdline_err = cmdline_read(argc, argv);
142
143         /* Check for parsing errors. */
144         if(cmdline_err != 0) {
145                 /* Get the parse error message */
146                 cmdline_error_msg = cmdline_error(cmdline_err);
147
148                 /* Print it out */
149                 printf("%s\n", cmdline_error_msg);
150
151                 /* Print our help too */
152                 print_help();
153                 return -1;
154         }
155         if(cmdline_getopt_count('h') > 0)
156         {
157                 header_version=atoi(argv[cmdline_getarg(cmdline_getarg_list('h'),0)]);
158         }
159         /* Set up arguments */
160         filen_kernel    = argv[cmdline_getarg(cmdline_getarg_list('i'),0)];
161         filen_files     = argv[cmdline_getarg(cmdline_getarg_list('i'),1)];
162         filen_out       = argv[cmdline_getarg(cmdline_getarg_list('o'),0)];
163         /* Command line arguments have been parsed. Start doing our work. */
164
165         /* Caculate the header size, and allocate the memory, and assign the sub pointers */
166         header_size =   sizeof(struct nsp_img_hdr_head) +               /* This has a single section
167                                                                    desc block already */
168                                 (header_version==1?0:4) + 
169                                 sizeof(struct nsp_img_hdr_info) + 
170                                 sizeof(struct nsp_img_hdr_section_info) + 
171                         sizeof(struct nsp_img_hdr_sections) * num_sects ;
172
173         img_hdr_head = (struct nsp_img_hdr_head *)malloc(header_size);
174         memset(img_hdr_head, 0x0, header_size);
175         img_hdr_info = (struct nsp_img_hdr_info*)((char *)img_hdr_head + sizeof(struct nsp_img_hdr_head) + (header_version==1?0:4));
176         img_hdr_section_info = (struct nsp_img_hdr_section_info*)((char *)img_hdr_info + sizeof(struct nsp_img_hdr_info));
177         img_hdr_sections = (struct nsp_img_hdr_sections*)((char *)img_hdr_section_info + sizeof(struct nsp_img_hdr_section_info));
178         section = img_hdr_sections;
179         memset(img_hdr_head, 0xff, (void*)img_hdr_info - (void*)img_hdr_head);
180         
181         img_hdr_head->hdr_version = header_version;
182         img_hdr_head->hdr_size = header_size;
183         img_hdr_head->info_offset = (void*)img_hdr_info - (void*)img_hdr_head;
184         img_hdr_head->sect_info_offset = (void*)img_hdr_section_info - (void*)img_hdr_head;
185         
186         img_hdr_section_info->num_sects = num_sects;
187         img_hdr_section_info->sect_size = sizeof(struct nsp_img_hdr_sections);
188         img_hdr_section_info->sections_offset = (void*)img_hdr_sections - (void*)img_hdr_head;
189         
190 /*      chksum = (struct nsp_img_hdr_chksum *)
191                         ((unsigned int)image_hdr + header_size - sizeof(struct nsp_img_hdr_chksum));*/
192
193         /* Open the out file */
194         nsp_image = fopen(filen_out,"wb+");
195         if(nsp_image==NULL) {
196                 printf("ERROR: can't open %s for writing.\n", filen_out);
197                 return -1;
198         }
199
200         /* Skip image header. We'll come back to it after we've written out the images. */      
201         fseek(nsp_image,header_size,SEEK_SET);
202         total = ftell(nsp_image);
203         total = header_size;
204         printf("total=%x\n",total);
205         {
206                 int align;
207                 int     padding;
208                 char * buf;
209                 align = (header_version==1?0x10000:0x4000);
210                 if(align==0) {
211                         /* The user indicated no padding */
212                         padding = 0;
213                 } else {
214                         /* Calculate number padding bytes */
215                         if((total %align) ==0)
216                                 padding=0;
217                         else
218                                 padding = align - (total % align);
219                 }
220                 if(padding>0)
221                 {
222                         buf=malloc(padding);
223                         memset(buf, 0xff, padding);
224                         if(fwrite((void*)buf,1,padding,nsp_image)!=padding) {
225                                 printf("ERROR: can't write to %s.\n", filen_out);
226                                 free(buf);
227                                 return -1;
228                         }
229                         free(buf);
230                         
231                 }
232                 total+=padding;
233                 
234
235         }
236         /* Write out all specified images (with -i option) */
237         for(i=0; i < num_sects; i++) {
238                 char*   file_name;              /* input file name */
239                 FILE*   filep;                  /* input file pointer */
240                 int     padding;                /* number of padding bytes to prepend */
241                 int     align;                  /* align factor from command line */
242                 int     result;                 /* intermediate result */
243                 char * buf;
244
245                 /* Open the specified image for reading */
246                 file_name       = argv[cmdline_getarg(cmdline_getarg_list('i'),i)];
247                 filep           = fopen(file_name, "rb");
248                 if(filep==NULL) {
249                         printf("ERROR: can't open file %s for reading.\n", file_name);
250                         return -1;
251                 }
252                 section->flags = ~0x00;
253                 /* Determine file size */
254                 fseek(filep,0,SEEK_END);
255                 section->raw_size=ftell(filep);
256                 fseek(filep,0,SEEK_SET);
257                 cs_calc_sum(filep,(unsigned long *)&section->chksum,0);
258                 fseek(filep,0,SEEK_SET);
259
260                 /* Retrieve the alignment constant */
261                 /* Set image offset from the beginning of the out file */
262                 section->offset=total;// + padding;
263
264                 //total += padding;
265
266                 /* Copy the image file into nsp_image */
267                 count = section->raw_size;
268                 buf=malloc(count);
269                 result=fread(buf, 1, count, filep);
270                 fwrite(buf, 1, result, nsp_image);
271                 free(buf);
272                 
273                 /* HACK: This is a hack to get the names and types to the files.
274                         TODO: Fix this to be a real method */
275                 if(i==0){
276                         section->type=NSP_IMG_SECTION_TYPE_KERNEL;
277                         strncpy(section->name, "kernel", 16);
278                 } else if(i==1){
279                         section->type=NSP_IMG_SECTION_TYPE_FILESYSTEM_ROOT;
280                         strncpy(section->name, "root", 16);
281                 }
282
283                 /* Account for the total */
284                 align   =  strtoul(argv[cmdline_getarg(cmdline_getarg_list('a'),i)],NULL,0);
285                 if(i==0){
286                         if(align==0 || (((section->raw_size+ section->offset)%align)==0))
287                                 padding=0;
288                         else
289                                 padding = align - ((section->raw_size+ section->offset) % align);
290
291                                 section->total_size=section->raw_size + padding;
292                 }
293                 else{
294                         #define EXTRA_BLOCK 0x10000
295                         unsigned int squash_padding;
296                         squash_padding = EXTRA_BLOCK - section->raw_size % EXTRA_BLOCK;
297                         buf=malloc(EXTRA_BLOCK + 4);
298                         memset(buf, 0, squash_padding);
299                         fwrite(buf, 1, squash_padding, nsp_image);
300                         memset(buf, 0, EXTRA_BLOCK + 4);
301                         *((unsigned int *)buf)=0xdec0adde;
302                         *((unsigned int *)(buf+EXTRA_BLOCK))=0xdec0adde;
303                         fwrite(buf, 1, EXTRA_BLOCK+4, nsp_image);
304                         free(buf);
305                         
306                         if(align==0 || (((section->raw_size + (EXTRA_BLOCK + 4 + squash_padding)) %align)==0))
307                                 padding=0;
308                         else
309                                 padding = align - ((section->raw_size + (EXTRA_BLOCK + 4 + squash_padding)) % align);
310                         section->total_size=section->raw_size + (EXTRA_BLOCK + 4 + squash_padding) + padding;
311                 }
312                 if(padding>0){
313                         buf=malloc(padding);
314                         memset(buf, 0xff, padding);
315                         fwrite(buf, 1, padding, nsp_image);
316                         free(buf);
317                 }
318                 printf("*****padding is %d\ttotal_size=%d\traw_size=%d\n",padding, section->total_size, section->raw_size);
319
320                 //total += section->raw_size;
321                 total = section->total_size + section->offset;
322                 printf("total=0x%x\n",total);
323                 /* Close the input file */
324                 fclose(filep);
325
326                 /* Move the section pointer to the next slot */
327                 section++;
328         }
329
330         /* Take care of the NSP image header fields */
331
332         /* head fields */
333         img_hdr_head->magic             = NSP_IMG_MAGIC_NUMBER;
334         img_hdr_head->boot_offset       = img_hdr_sections->offset;
335         img_hdr_head->flags             = ~0x00;                        /* Set to all 1's */
336
337         if(cmdline_getopt_count('b'))
338                 img_hdr_head->flags     &= ~(NSP_IMG_FLAG_FAILBACK_5 | NSP_IMG_FLAG_FAILBACK_1);
339
340         if(cmdline_getopt_count('f'))
341                 img_hdr_head->flags     = strtoul(argv[cmdline_getarg(cmdline_getarg_list('f'),0)], 0, 16);
342
343 #if 0
344         img_hdr_head->hdr_version       = 2;
345         img_hdr_head->hdr_size  = header_size;
346 #endif
347
348         if(cmdline_getopt_count('p'))
349                 img_hdr_head->prod_id           = strtoul(argv[cmdline_getarg(cmdline_getarg_list('p'),0)], 0, 16);
350         else
351                 img_hdr_head->prod_id           = 0x4C575943;
352
353         if(cmdline_getopt_count('r'))
354                 img_hdr_head->rel_id            = strtoul(argv[cmdline_getarg(cmdline_getarg_list('r'),0)], 0, 0);
355         else
356                 img_hdr_head->rel_id            = 0x10203040;
357
358         if(cmdline_getopt_count('s'))
359                 img_hdr_head->version           = strtoul(argv[cmdline_getarg(cmdline_getarg_list('s'),0)], 0, 0);
360         else
361                 img_hdr_head->version           = 0x0b040000;
362         img_hdr_head->image_size        = total;
363 #if 0
364         img_hdr_head->info_offset       = (unsigned int)(&(image_hdr->info)) -
365                                                 (unsigned int)image_hdr;
366         img_hdr_head->sect_info_offset= (unsigned int)(&(image_hdr->sect_info)) -
367                                                 (unsigned int)image_hdr;
368 #endif
369 //      image_hdr->head.chksum_offset   = (unsigned int)chksum - (unsigned int)image_hdr;
370         img_hdr_head->chksum_offset = 0xffffffff;
371 //      image_hdr->head.pad1 = 0xffffffff;
372         /* info fields */
373         /* TODO: Fix. Do nothing yet */
374 //      strncpy(nsp_img_hdr.id.prod_info,NSP_PRODINFO_STRING,sizeof(NSP_PRODINFO_STRING));
375         strcpy(img_hdr_info->image_filename, (const char *)basename(filen_out));
376         /* section fields */
377 #if 0
378         img_hdr_section_info->num_sects=                num_sects;
379         img_hdr_section_info->sect_size=                sizeof(struct nsp_img_hdr_sections);
380         img_hdr_section_info->sections_offset=  (unsigned int)(&(image_hdr->sections)) -
381                                                 (unsigned int)image_hdr;
382 #endif
383
384         /* Calculate checksum(s) */
385 #if 0
386         chksum->hdr_chksum = cs_calc_buf_sum((char*)image_hdr,
387                         header_size - sizeof(struct nsp_img_hdr_chksum));
388 #endif
389         /* Write out the NSP header. */
390         fseek(nsp_image,0,SEEK_SET);
391         count = fwrite((void*)img_hdr_head, header_size, 1, nsp_image);
392         if(count!=1) {
393                 printf("ERROR: can't write to %s.\n", filen_out);
394                 return -1;
395         }
396
397         /* Check if -v option was specified (no arg needed) */
398         if(cmdline_getopt_count('v') > 0)
399         {
400                 struct nsp_img_hdr_head head;
401                 struct nsp_img_hdr      *hdr;
402
403                 /* Rewind the file back to the beginning */
404                 fseek(nsp_image,0,SEEK_SET);
405
406                 /* Read header from the file */
407                 fread((void*)&head, sizeof(struct nsp_img_hdr_head),
408                                 1, nsp_image);
409
410                 /* Get memory to store the complete header */
411                 hdr = (struct nsp_img_hdr *)malloc(head.hdr_size);
412
413                 /* Read header from the file */
414                 fseek(nsp_image,0,SEEK_SET);
415                 fread((void*)hdr, head.hdr_size, 1, nsp_image);
416
417                 /* Print it out */
418                 mknspimg_print_hdr(hdr);
419                 printf("Generated total %d bytes\n",total);
420                 free(hdr);
421         }
422
423         free(img_hdr_head);
424
425       {
426           struct checksumrecord cr;
427       cr.magic=CKSUM_MAGIC_NUMBER;
428       cs_calc_sum(nsp_image, (unsigned long *)&cr.chksum, 0);
429       fseek(nsp_image,0, SEEK_END);
430       fwrite(&cr, 1, sizeof(cr), nsp_image);
431           }
432           {
433                 FILE * non_web;
434                 char fname[256];
435                 char * img_buf;
436                 unsigned int len;
437                 strcpy(fname, filen_out);
438                 strcat(fname, ".non_web");
439                 non_web = fopen(fname,"wb+");
440                 fseek(nsp_image, 0, SEEK_END);
441                 len = ftell(nsp_image);
442                 img_buf=malloc(len);
443                 fseek(nsp_image, 0, SEEK_SET);
444                 fread(img_buf, 1, len, nsp_image);
445                 img_buf[0xb] = 0x17;
446                 fwrite(img_buf, 1, len-sizeof(struct checksumrecord), non_web);
447                 fclose(non_web);
448                 free(img_buf);
449           }
450           /* Close NSP image file */
451         fclose(nsp_image);
452
453         /* return result */
454         return(0);
455 }
456
457 #ifdef DMALLOC
458 #include <dmalloc.h>
459 #endif /* DMALLOC */
460
461 #define BUFLEN (1 << 16)
462
463 static unsigned long crctab[256] =
464 {
465         0x0,
466         0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B,
467         0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6,
468         0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD,
469         0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC,
470         0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F,
471         0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A,
472         0x745E66CD, 0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039,
473         0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58,
474         0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033,
475         0xA4AD16EA, 0xA06C0B5D, 0xD4326D90, 0xD0F37027, 0xDDB056FE,
476         0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95,
477         0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4,
478         0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 0x34867077, 0x30476DC0,
479         0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5,
480         0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16,
481         0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 0x7897AB07,
482         0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C,
483         0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1,
484         0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA,
485         0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B,
486         0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698,
487         0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D,
488         0x94EA7B2A, 0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E,
489         0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F,
490         0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34,
491         0xDC3ABDED, 0xD8FBA05A, 0x690CE0EE, 0x6DCDFD59, 0x608EDB80,
492         0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB,
493         0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A,
494         0x58C1663D, 0x558240E4, 0x51435D53, 0x251D3B9E, 0x21DC2629,
495         0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C,
496         0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF,
497         0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 0xF12F560E,
498         0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65,
499         0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8,
500         0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3,
501         0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2,
502         0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71,
503         0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74,
504         0x857130C3, 0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640,
505         0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21,
506         0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A,
507         0x61043093, 0x65C52D24, 0x119B4BE9, 0x155A565E, 0x18197087,
508         0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC,
509         0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D,
510         0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 0xC5A92679, 0xC1683BCE,
511         0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB,
512         0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18,
513         0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 0x89B8FD09,
514         0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662,
515         0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF,
516         0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4
517 };
518
519 int cs_is_tagged(FILE *fp)
520 {
521         char buf[8];
522
523         fseek(fp, -8, SEEK_END);
524         fread(buf, 8, 1, fp);
525         if(*(unsigned long*)buf == CKSUM_MAGIC_NUMBER)
526                 return 1;
527         return 0;
528 }
529
530 unsigned long cs_read_sum(FILE *fp)
531 {
532         char buf[8];
533
534         fseek(fp, -8, SEEK_END);
535         fread(buf, 8, 1, fp);
536         return *((unsigned long*)&buf[4]);
537 }
538
539 int cs_calc_sum(FILE *fp, unsigned long *res, int tagged)
540 {
541         unsigned char buf[BUFLEN];
542         unsigned long crc = 0;
543         uintmax_t length = 0;
544         size_t bytes_read;
545
546         fseek(fp, 0, SEEK_SET);
547
548         while((bytes_read = fread(buf, 1, BUFLEN, fp)) > 0)
549         {
550                 unsigned char *cp = buf;
551
552                 if(length + bytes_read < length)
553                         return 0;
554
555                 if(bytes_read != BUFLEN && tagged)
556                         bytes_read -= 8;
557
558                 length += bytes_read;
559                 while(bytes_read--)
560                         crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
561         }
562
563         if(ferror(fp))
564                 return 0;
565
566         for(; length; length >>= 8)
567                 crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
568
569         crc = ~crc & 0xFFFFFFFF;
570
571         *res = crc;
572
573         return 1;
574 }
575
576 unsigned long cs_calc_buf_sum(char *buf, int size)
577 {
578         unsigned long crc = 0;
579         char *cp = buf;
580         unsigned long length = size;
581
582         while(size--)
583                 crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
584
585         for(; length; length >>= 8)
586                 crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
587
588         crc = ~crc & 0xFFFFFFFF;
589
590         return crc;
591 }
592
593 unsigned long cs_calc_buf_sum_ds(char *buf, int buf_size, char *sign, int sign_len)
594 {
595         unsigned long crc = 0;
596         char *cp = buf;
597         unsigned long length = buf_size+sign_len;
598
599         while(buf_size--)
600                 crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
601
602         cp = sign;
603         while(sign_len--)
604                 crc =(crc << 8) ^ crctab[((crc >> 24) ^ *cp++) & 0xFF];
605
606
607         for(; length; length >>= 8)
608                 crc =(crc << 8) ^ crctab[((crc >> 24) ^ length) & 0xFF];
609
610         crc = ~crc & 0xFFFFFFFF;
611
612         return crc;
613 }
614
615 int cs_set_sum(FILE *fp, unsigned long sum, int tagged)
616 {
617         unsigned long magic = CKSUM_MAGIC_NUMBER;
618
619         if(tagged)
620                 fseek(fp, -8, SEEK_END);
621         else
622                 fseek(fp, 0, SEEK_END);
623
624         if(fwrite(&magic, 1, 4, fp) < 4)
625                 return 0;
626         if(fwrite(&sum, 1, 4, fp) < 4)
627                 return 0;
628
629         return 1;
630 }
631
632 void cs_get_sum(FILE *fp, unsigned long *sum)
633 {
634         unsigned long magic = 0;
635
636         fseek(fp, -8, SEEK_END);
637
638         fread(&magic, 4, 1, fp);
639         fread(sum, 4, 1, fp);
640 }
641
642 int cs_validate_file(char *filename)
643 {
644         FILE *pFile = NULL;
645         unsigned long sum = 0, res = 0;
646
647         if((pFile = fopen(filename, "r")) == NULL)
648                 return 0;
649
650         if(!cs_is_tagged(pFile))
651         {
652                 fclose(pFile);
653                 return 0;
654         }
655         if(!cs_calc_sum(pFile, &sum, 1))
656         {
657                 fclose(pFile);
658                 return 0;
659         }
660         cs_get_sum(pFile, &res);
661         fclose(pFile);
662
663         if(sum != res)
664                 return 0;
665         return 1;
666 }
667
668 /* ********* Library internal data ********* */
669 #define CMDLINE_TRUE                    1
670 #define CMDLINE_FALSE                   0
671
672 typedef enum CMDLINE_ERR
673 {
674         CMDLINE_ERR_OK          = 0,    /* No Error (OK) */
675         CMDLINE_ERR_ERROR       = -1,   /* Unspecified error */
676         CMDLINE_ERR_INVKEY      = -3,   /* Invalid option key */
677         CMDLINE_ERR_MANYARG     = -4,   /* Too many arguments */
678         CMDLINE_ERR_FEWARG      = -5,   /* Too few arguments */
679         CMDLINE_ERR_ILLOPT      = -6,   /* Option not allowed (illegal option) */
680         CMDLINE_ERR_NOMEM       = -7,   /* No memory */
681         CMDLINE_ERR_OPTMIS      = -8    /* A mandatory option is missing */
682 } CMDLINE_ERR;
683
684 /* Argument list */
685 typedef struct CMDLINE_ARG
686 {
687         int                             index;          /* Index of the argument in the command line */
688         struct CMDLINE_ARG*     p_next; /* Next node in the linked list */
689 } CMDLINE_ARG;
690
691 /* Master control block for an option */
692 typedef struct CMDLINE_ARGS
693 {
694         int                             argc;           /* Total count of arguments found */
695         int                             optc;           /* Total count of options found */
696         CMDLINE_ARG*    list;           /* Argument list */
697 } CMDLINE_ARGS;
698
699 /* Master control block for all found arguments */
700 typedef struct CMDLINE_DATA
701 {
702         CMDLINE_ARGS    opt_args[26];   /* Array of MCBs for each option ('a' through 'z') */
703         CMDLINE_ARGS    glb_args;               /* Global arguments */
704         int                             parsed;                 /* Internal flag to prevent client calls if library is not initialized */
705 } CMDLINE_DATA;
706
707 /* ********* Local Data ********* */
708 static CMDLINE_CFG cmdline_cfg;
709 static CMDLINE_DATA cmdline_data;
710
711 char*   cmdline_errmsg = "CMDLINE ERROR";
712
713 /* ***************************************************************
714 * Print all found command line options and their arguments
715 ****************************************************************** */
716 void* cmdline_getarg_list(char opt)
717 {
718         int index = (opt - 'a');
719
720         /* Check the validity of the index */
721         if((index < 0) || (index > 25))
722         {
723                 /* ERROR: Wrong option */
724                 return NULL;
725         }
726
727         /* Return a pointer to the ARGS control structure */
728         return((void*)(&cmdline_data.opt_args[index]));
729 }
730
731 /* ***************************************************************
732 * Print all found command line options and their arguments
733 ****************************************************************** */
734 int cmdline_getarg_count(void* list)
735 {
736         CMDLINE_ARGS*   p_args = (CMDLINE_ARGS*)list;
737
738         /* Return number of arguments for this option */
739         return(p_args->argc);
740 }
741
742 /* ***************************************************************
743 * Print all found command line options and their arguments
744 ****************************************************************** */
745 int cmdline_getopt_count(char opt)
746 {
747         int                             index;
748
749         /* Calculate index value */
750         index = opt - 'a';
751         if(index < 0 || index > 25) return -1;
752
753         /* Return number of arguments for this option */
754         return(cmdline_data.opt_args[index].optc);
755 }
756
757 /* ***************************************************************
758 * Print all found command line options and their arguments
759 ****************************************************************** */
760 int cmdline_getarg(void* list, int num)
761 {
762         int i;
763         CMDLINE_ARGS*   p_args = (CMDLINE_ARGS*)list;
764         CMDLINE_ARG*    p_arg;
765
766         /* Search the 'num' argument in the list for this option */
767         for(i=0,p_arg=p_args->list; (p_arg!=NULL) && (i<p_args->argc); i++, p_arg=p_arg->p_next)
768         {
769                 /* if num matches i, we found it */
770                 if(i==num) return(p_arg->index);
771         }
772         /* We did not find the specified argument or the list was empty */
773         return -1;
774 }
775
776 /* ***************************************************************
777 * Print all found command line options and their arguments
778 ****************************************************************** */
779 int cmdline_configure(CMDLINE_CFG* p_cfg)
780 {
781         /* reset global data */
782         memset(&cmdline_cfg,0,sizeof(cmdline_cfg));
783         memset(&cmdline_data,0,sizeof(cmdline_data));
784
785         /* Copy the user's config structure */
786         cmdline_cfg = *p_cfg;
787         return 0;
788 }
789
790 /* ***************************************************************
791 * Print all found command line options and their arguments
792 ****************************************************************** */
793 char* cmdline_error(int err)
794 {
795         /* TODO: implement a table of error messages */
796         return(cmdline_errmsg);
797 }
798
799 /* ***************************************************************
800 * Print all found command line options and their arguments
801 ****************************************************************** */
802 static void cmdline_print_args(CMDLINE_ARGS* p_arglist, char* argv[])
803 {
804         CMDLINE_ARG*    p_arg;
805
806         printf("   Number of times option was specified: %d\n", p_arglist->optc);
807         printf("   Number of Arguments:                  %d\n", p_arglist->argc);
808
809         if(p_arglist->argc > 0)
810         {
811                 printf("   Argument List: ");
812
813                 for(p_arg=p_arglist->list; p_arg != NULL; p_arg=p_arg->p_next)
814                         printf("%s ", argv[p_arg->index]);
815         }
816
817         printf("\n");
818 }
819
820 /* ***************************************************************
821 * Print all found command line options and their arguments
822 ****************************************************************** */
823 void cmdline_print(char* argv[])
824 {
825         int i;
826
827         /* Check if the command line was parsed */
828         if(cmdline_data.parsed != CMDLINE_TRUE)
829         {
830                 printf("The command line has not been parsed yet.\n");
831                 return;
832         }
833
834         /* Print out option arguments */
835         for( i = 0; i < 26; i++ )
836         {
837                 /* Check if the option was specified */
838                 if(cmdline_data.opt_args[i].optc !=0 )
839                 {
840                         /* Print out option name and arguments */
841                         printf("Option: -%c\n", (char)('a'+i));
842                         cmdline_print_args(&(cmdline_data.opt_args[i]), argv);
843                 }
844         }
845
846         /* Print out global arguments */
847         printf("Global arguments:\n");
848         cmdline_print_args(&(cmdline_data.glb_args), argv);
849 }
850
851 /* ***************************************************************
852 * Print configuration
853 ****************************************************************** */
854 void cmdline_print_cfg(void)
855 {
856
857 }
858
859 static void cmdline_argadd(CMDLINE_ARGS* p_arglist, CMDLINE_ARG* p_arg)
860 {
861         CMDLINE_ARG*    p_list;
862         CMDLINE_ARG*    p_prev=NULL;
863
864         /* See if we had anything in the list */
865         if(p_arglist->argc == 0)
866         {
867                 /* Link the argument in */
868                 p_arglist->list = p_arg;
869         }
870         else
871         {
872                 /* Find the tail of the list */
873                 for(p_list=p_arglist->list; p_list != NULL; p_list=p_list->p_next)
874                         p_prev = p_list;
875
876                 /* Link the argument in */
877                 p_prev->p_next=p_arg;
878         }
879
880         /* Keep track of arg number */
881         p_arglist->argc++;
882 }
883
884 /* ***************************************************************
885 * cmdline_read()
886 * Read and parse command line arguments
887 ****************************************************************** */
888 int cmdline_read(int argc, char* argv[])
889 {
890         int i, option=0;
891
892         /* Process every command line argument in argv[] array */
893         for( i = 1; i < argc; i++ )
894         {
895                 /* Does the argument start with a dash? */
896                 if( *argv[i] == '-' )
897                 {
898                         /* The argument must be two characters: a dash, and a letter */
899                         if( strlen(argv[i]) != 2 )
900                         {
901                                 /* ERROR: option syntax (needs to be a dash and one letter) */
902                                 return(CMDLINE_ERR_ERROR);
903                         }
904
905                         /* Check validity of the option key ('a' through 'z') */
906                         if( ((*(argv[i] + 1)) < 'a') || ((*(argv[i] + 1)) > 'z') )
907                         {
908                                 /* ERROR: option sysntax (invalid option key) */
909                                 return(CMDLINE_ERR_INVKEY);
910                         }
911
912                         /* Calculate the option index */
913                         option = (*(argv[i] + 1)) - 'a';
914                         if((option < 0) || (option > 25)) return(CMDLINE_ERR_INVKEY);
915
916                         /* Check to see if the option is allowed */
917                         if( cmdline_cfg.opts[option].flags & CMDLINE_OPTFLAG_ALLOW )
918                         {
919                                 /* Option allowed. */
920                                 cmdline_data.opt_args[option].optc++;
921                                 continue;
922                         }
923                         else
924                         {
925                                 /* ERROR: Option is not allowed */
926                                 return(CMDLINE_ERR_ILLOPT);
927                         }
928                 }
929                 else
930                 {
931                         /* Read the arguments for the option */
932                         CMDLINE_ARG*    p_arg;
933
934                         /* Allocate space for the argument node */
935                         p_arg = (CMDLINE_ARG*)calloc(1,sizeof(CMDLINE_ARG));
936                         if( p_arg== NULL )
937                         {
938                                 /* ERROR: Can't allocate memory for the argument index */
939                                 return(CMDLINE_ERR_NOMEM);
940                         }
941
942                         /* Initialize the argument */
943                         p_arg->index    = i;
944                         p_arg->p_next   = NULL;
945
946                         /* Check if we can add to the list of arguments for this option */
947                         if( (option < 0)                                                                                                                                /* Do we have to add to the global list? */
948                                 || (cmdline_data.opt_args[option].argc == cmdline_cfg.opts[option].max)         /* Did we reach MAX arguments? */
949                                 )
950                         {
951                                 /* This option does not require arguments. Keep the argument in the global list. */
952                                 cmdline_argadd(&(cmdline_data.glb_args), p_arg);
953                                 continue;
954                         }
955                         else
956                         {
957                                 /* See if the current count has reached max for this option */
958                                 if( cmdline_data.opt_args[option].argc == cmdline_cfg.opts[option].max )
959                                 {
960                                         /* ERROR: too many arguments for an option */
961                                         return(CMDLINE_ERR_MANYARG);
962                                 }
963                                 else
964                                 {
965                                         /* Link the argument to the arg list of the option */
966                                         cmdline_argadd(&(cmdline_data.opt_args[option]), p_arg);
967                                         continue;
968                                 }
969                         }
970                 }
971         }
972
973         /* ****** We read the complete command line. See if what we collected matches the configuration ******* */
974
975         /* Check every collected option against its configuration */
976         for( i=0; i < 26; i++ )
977         {
978                 /* Check if this option was allowed */
979                 if(cmdline_cfg.opts[i].flags & CMDLINE_OPTFLAG_ALLOW)
980                 {
981                         /* See if it was mandatory */
982                         if(cmdline_cfg.opts[i].flags & CMDLINE_OPTFLAG_MANDAT)
983                         {
984                                 /* Check if we really collected this option on the command line. */
985                                 if(cmdline_data.opt_args[i].optc == 0)
986                                 {
987                                         /* ERROR: a missing mandatory option */
988                                         return(CMDLINE_ERR_OPTMIS);
989                                 }
990                                 else
991                                 {
992                                         /* Option was there. Check how many args we got for it. */
993                                         if(cmdline_data.opt_args[i].argc < cmdline_cfg.opts[i].min)
994                                         {
995                                                 /* ERROR: too few arguments for an option */
996                                                 return(CMDLINE_ERR_FEWARG);
997                                         }
998                                         else
999                                         {
1000                                                 /* This mandatory option was proper. */
1001                                                 continue;
1002                                         }
1003                                 }
1004                         }
1005                         else    /* This is non-mandatory option: */
1006                         {
1007                                 /* Check if the option was specified on the command line */
1008                                 if(cmdline_data.opt_args[i].optc == 0)
1009                                 {
1010                                         /* option wasn't specified, go to the next */
1011                                         continue;
1012                                 }
1013                                 else
1014                                 {
1015                                         /* Option was there. Check how many args we collected for it. */
1016                                         if(cmdline_data.opt_args[i].argc < cmdline_cfg.opts[i].min)
1017                                         {
1018                                                 /* ERROR: too few arguments for a non-mandatory option */
1019                                                 return(CMDLINE_ERR_FEWARG);
1020                                         }
1021                                         else
1022                                         {
1023                                                 /* This non-mandatory option was proper. */
1024                                                 continue;
1025                                         }
1026                                 }
1027                         }
1028                 }
1029                 else    /* Option was not allowed. */
1030                 {
1031                         /* We should not get here as the non-allowed options should have been
1032                         trapped eariler. */
1033                 }
1034         }
1035
1036         /* Command line was proper as far as the number of options and their arguments */
1037         cmdline_data.parsed = CMDLINE_TRUE;
1038         return(CMDLINE_ERR_OK);
1039 }