root/WizardsToolkit/trunk/utilities/digest.c

Revision 245, 30.4 KB (checked in by cristy, 8 weeks ago)
Line 
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3%                                                                             %
4%                                                                             %
5%                                                                             %
6%                  DDDD   IIIII   GGGG  EEEEE  SSSSS  TTTTT                   %
7%                  D   D    I    G      E      SS       T                     %
8%                  D   D    I    G GG   EEE     SSS     T                     %
9%                  D   D    I    G   G  E         SS    T                     %
10%                  DDDD   IIIII   GGG   EEEEE  SSSSS    T                     %
11%                                                                             %
12%                                                                             %
13%                       Compute Content Message Digest.                       %
14%                                                                             %
15%                              Software Design                                %
16%                                John Cristy                                  %
17%                                January 2008                                 %
18%                                                                             %
19%                                                                             %
20%  Copyright 1999-2009 ImageMagick Studio LLC, a non-profit organization      %
21%  dedicated to making software imaging solutions freely available.           %
22%                                                                             %
23%  You may not use this file except in compliance with the License.  You may  %
24%  obtain a copy of the License at                                            %
25%                                                                             %
26%    http://www.wizards-toolkit.org/script/license.php                        %
27%                                                                             %
28%  Unless required by applicable law or agreed to in writing, software        %
29%  distributed under the License is distributed on an "AS IS" BASIS,          %
30%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
31%  See the License for the specific language governing permissions and        %
32%  limitations under the License.                                             %
33%                                                                             %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36%
37*/
38
39/*
40  Include declarations.
41*/
42#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45#include <time.h>
46#include "wizard/studio.h"
47#include "wizard/WizardsToolkit.h"
48#include "wizard/blob-private.h"
49#include "wizard/exception-private.h"
50#if defined(__WINDOWS__)
51#include <windows.h>
52#endif
53#include "content.h"
54#include "utility_.h"
55
56/*
57%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58%                                                                             %
59%                                                                             %
60%                                                                             %
61+   D i g e s t C o m m a n d                                                 %
62%                                                                             %
63%                                                                             %
64%                                                                             %
65%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
66%
67%  DigestCommand() reads content from one or more files and generates its
68%  message digest as RDF.
69%
70%  The format of the DigestCommand method is:
71%
72%      WizardBooleanType DigestCommand(int argc,char **argv,
73%        ExceptionInfo *exception)
74%
75%  A description of each parameter follows:
76%
77%    o argc: The number of elements in the argument vector.
78%
79%    o argv: A text array containing the command line arguments.
80%
81%    o exception: Return any errors or warnings in this structure.
82%
83*/
84
85static void DigestUsage()
86{
87  static const char
88    *options[]=
89    {
90      "-authenticate        read message digests from a file and authenticate them",
91      "-debug events        display copious debugging information",
92      "-(de)compress        automagically (de)compress BZIP and ZIP files",
93      "-hash type           compute the message digest with this hash",
94      "-help                print program options",
95      "-list type           print a list of supported option arguments",
96      "-version             print version information",
97      (char *) NULL
98    };
99
100  const char
101    **p;
102
103  (void) fprintf(stdout,"Version: %s\n",GetWizardVersion(
104    (unsigned long *) NULL));
105  (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
106  (void) fprintf(stdout,"Usage: %s [options ...] file [ file ...] digest-rdf\n",
107    GetClientName());
108  (void) fprintf(stdout,"       %s -authenticate [options ...] digest-rdf "
109    "[ digest-rdf ...]\n",GetClientName());
110  (void) fprintf(stdout,"\nWhere options include:\n");
111  for (p=options; *p != (char *) NULL; p++)
112    (void) fprintf(stdout,"  %s\n",*p);
113  Exit(0);
114}
115
116static WizardBooleanType AuthenticateDigest(int argc,char **argv,
117  ExceptionInfo *exception)
118{
119#define DestroyDigest() \
120{ \
121  for (i=0; i < (long) argc; i++) \
122    argv[i]=DestroyString(argv[i]); \
123}
124#define ThrowDigestException(asperity,tag,context) \
125{ \
126  (void) ThrowWizardException(exception,GetWizardModule(),asperity,tag, \
127    context); \
128  DestroyDigest(); \
129  return(WizardFalse); \
130}
131
132  BlobInfo
133    *authenticate_blob,
134    *content_blob,
135    *digest_blob;
136
137  char
138    *create_date,
139    date[MaxTextExtent],
140    *digest,
141    key[MaxTextExtent],
142    *message,
143    *modify_date,
144    *option,
145    *options,
146    *path,
147    *timestamp;
148
149  HashInfo
150    *hash_info;
151
152  HashType
153    hash;
154
155  int
156    c;
157
158  register long
159    i;
160
161  size_t
162    length;
163
164  ssize_t
165    count;
166
167  StringInfo
168    *content;
169
170  WizardBooleanType
171    compress,
172    status;
173
174  status=WizardFalse;
175  authenticate_blob=OpenBlob(argv[argc-1],WriteBinaryBlobMode,WizardTrue,
176    exception);
177  if (authenticate_blob == (BlobInfo *) NULL)
178    return(WizardFalse);
179  hash=UndefinedHash;
180  compress=WizardFalse;
181  for (i=1; i < (argc-1); i++)
182  {
183    option=argv[i];
184    if (*option == '-')
185      {
186        switch(*(option+1))
187        {
188          case '(':
189          {
190            if (LocaleCompare(option+1,"(de)compress") == 0)
191              {
192                compress=(*option == '-') ? WizardTrue : WizardFalse;
193                break;
194              }
195            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
196              option);
197            break;
198          }
199          case 'a':
200          {
201            if (strcasecmp(option,"-authenticate") == 0)
202              break;
203            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
204              option);
205            break;
206          }
207          case 'd':
208          {
209            if (strcasecmp(option,"-debug") == 0)
210              {
211                LogEventType
212                  event_mask;
213
214                i++;
215                if (i == argc)
216                  ThrowDigestException(OptionError,"missing log event mask: "
217                    "`%s'",option);
218                event_mask=SetLogEventMask(argv[i]);
219                if (event_mask == UndefinedEvents)
220                  ThrowDigestException(OptionFatalError,"unrecognized log "
221                    "event type: `%s'",argv[i]);
222                break;
223              }
224            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
225              option);
226            break;
227          }
228          case 'l':
229          {
230            if (LocaleCompare(option,"-list") == 0)
231              {
232                long
233                  list;
234
235                if (*option == '+')
236                  break;
237                i++;
238                if (i == (long) argc)
239                  ThrowDigestException(OptionError,"missing list type: `%s'",
240                    option);
241                if (LocaleCompare(argv[i],"configure") == 0)
242                  {
243                    (void) ListConfigureInfo((FILE *) NULL,exception);
244                    Exit(0);
245                  }
246                list=ParseWizardOption(WizardListOptions,WizardFalse,argv[i]);
247                if (list < 0)
248                  ThrowDigestException(OptionFatalError,"unrecognized list "
249                    "type: `%s'",argv[i]);
250                (void) ListWizardOptions((FILE *) NULL,(WizardOption) list,
251                  exception);
252                Exit(0);
253              }
254            if (LocaleCompare("log",option+1) == 0)
255              {
256                if (*option == '+')
257                  break;
258                i++;
259                if ((i == (long) argc) ||
260                    (strchr(argv[i],'%') == (char *) NULL))
261                  ThrowDigestException(OptionFatalError,"missing argument: "
262                    "`%s'",option);
263                break;
264              }
265            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
266              option);
267            break;
268          }
269          case 'v':
270          {
271            if (strcasecmp(option,"-version") == 0)
272              {
273                (void) fprintf(stdout,"Version: %s\n",
274                  GetWizardVersion((unsigned long *) NULL));
275                (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
276                exit(0);
277              }
278            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
279              option);
280            break;
281          }
282          default:
283          {
284            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
285              option);
286            break;
287          }
288        }
289        continue;
290      }
291    /*
292      Read message digests from a file and verify them.
293    */
294    digest_blob=OpenBlob(argv[i],ReadBinaryBlobMode,WizardTrue,exception);
295    if (digest_blob == (BlobInfo *) NULL)
296      return(WizardFalse);
297    (void) ResetWizardMemory(key,0,sizeof(key));
298    create_date=ConstantString("unknown");
299    digest=ConstantString("unknown");
300    path=ConstantString("unknown");
301    modify_date=ConstantString("unknown");
302    timestamp=ConstantString("unknown");
303    hash=SHA256Hash;
304    for (c=ReadBlobByte(digest_blob); (c != '>') && (c != EOF); )
305    {
306      length=MaxTextExtent;
307      options=AcquireString((char *) NULL);
308      while ((isgraph(c) != WizardFalse) && (c != '>') && (c != EOF))
309      {
310        register char
311          *p;
312 
313        if ((isalnum(c) == WizardFalse) && (c != '/'))
314          c=ReadBlobByte(digest_blob);
315        else
316          {
317            /*
318              Get the key.
319            */
320            p=key;
321            do
322            {
323              if (isspace((int) ((unsigned char) c)) != 0)
324                break;
325              if (c == (int) '>')
326                break;
327              if ((size_t) (p-key) < MaxTextExtent)
328                *p++=(char) c;
329              c=ReadBlobByte(digest_blob);
330            } while (c != EOF);
331            *p='\0';
332            p=options;
333            while (isspace((int) ((unsigned char) c)) != 0)
334              c=ReadBlobByte(digest_blob);
335            if (c == (int) '>')
336              {
337                /*
338                  Get the value.
339                */
340                c=ReadBlobByte(digest_blob);
341                while ((c != (int) '<') && (c != EOF))
342                {
343                  if ((size_t) (p-options+1) >= length)
344                    {
345                      *p='\0';
346                      length<<=1;
347                      options=(char *) ResizeQuantumMemory(options,length+
348                        MaxTextExtent,sizeof(*options));
349                      if (options == (char *) NULL)
350                        break;
351                      p=options+strlen(options);
352                    }
353                  if (options == (char *) NULL)
354                    {
355                      (void) ThrowWizardException(exception,GetWizardModule(),
356                        ResourceError,"memory allocation failed: `%s'",
357                        GetBlobFilename(digest_blob));
358                      return(WizardFalse);
359                    }
360                  *p++=(char) c;
361                  c=ReadBlobByte(digest_blob);
362                  if (*options != '<')
363                    if (isspace((int) ((unsigned char) c)) != 0)
364                      break;
365                }
366              }
367            *p='\0';
368            /*
369              Interpret key.
370            */
371            switch (*key)
372            {
373              case 'd':
374              case 'D':
375              {
376                if (LocaleCompare(key,"digest:create-date") == 0)
377                  {
378                    StripString(options);
379                    create_date=ConstantString(options);
380                    break;
381                  }
382                if (LocaleCompare(key,"digest:modify-date") == 0)
383                  {
384                    StripString(options);
385                    modify_date=ConstantString(options);
386                    break;
387                  }
388                if (LocaleCompare(key,"digest:timestamp") == 0)
389                  {
390                    StripString(options);
391                    timestamp=ConstantString(options);
392                    break;
393                  }
394                if (LocaleNCompare(key,"digest:",7) == 0)
395                  {
396                    long
397                      algorithm;
398
399                    algorithm=ParseWizardOption(WizardHashOptions,WizardFalse,
400                      key+7);
401                    if (algorithm < 0)
402                      break;
403                    hash=(HashType) algorithm;
404                    StripString(options);
405                    digest=ConstantString(options);
406                    break;
407                  }
408                break;
409              }
410              case 'r':
411              case 'R':
412              {
413                if (LocaleNCompare(key,"rdf:about",9) == 0)
414                  {
415                    StripString(key+10);
416                    if (path != (char *) NULL)
417                      path=DestroyString(path);
418                    path=ConstantString(key+10);
419                    if (digest != (char *) NULL)
420                      {
421                        digest=DestroyString(digest);
422                        digest=ConstantString("unknown");
423                      }
424                    if (timestamp != (char *) NULL)
425                      {
426                        timestamp=DestroyString(timestamp);
427                        timestamp=ConstantString("timestamp");
428                      }
429                    if (create_date != (char *) NULL)
430                      {
431                        create_date=DestroyString(create_date);
432                        create_date=ConstantString("unknown");
433                      }
434                    if (modify_date != (char *) NULL)
435                      {
436                        modify_date=DestroyString(modify_date);
437                        modify_date=ConstantString("unknown");
438                      }
439                    break;
440                  }
441                break;
442              }
443              case '/':
444              {
445                if ((LocaleCompare(key,"/digest:Content") == 0) ||
446                    (LocaleCompare(key,"/rdf:Description") == 0))
447                  {
448                    content_blob=OpenBlob(path,ReadBinaryBlobMode,WizardTrue,
449                      exception);
450                    if (content_blob == (BlobInfo *) NULL)
451                      break;
452                    /*
453                      Compute content message digest and verify.
454                    */
455                    hash_info=AcquireHashInfo(SHA256Hash);
456                    InitializeHash(hash_info);
457                    for (content=AcquireStringInfo(WizardMaxBufferExtent); ; )
458                    {
459                      count=ReadBlobChunk(content_blob,WizardMaxBufferExtent,
460                        GetStringInfoDatum(content));
461                      if (count <= 0)
462                        break;
463                      length=(size_t) count;
464                      SetStringInfoLength(content,length);
465                      UpdateHash(hash_info,content);
466                    }
467                    FinalizeHash(hash_info);
468                    content=DestroyStringInfo(content);
469                    if (strcmp(digest,GetHashHexDigest(hash_info)) != 0)
470                      {
471                        message=AcquireString("Path: ");
472                        (void) ConcatenateString(&message,path);
473                        (void) ConcatenateString(&message,"\n");
474                        (void) ConcatenateString(&message,"  create date: ");
475                        (void) ConcatenateString(&message,create_date);
476                        (void) ConcatenateString(&message,"\n");
477                        (void) ConcatenateString(&message,"  modify date: ");
478                        (void) ConcatenateString(&message,modify_date);
479                        (void) ConcatenateString(&message,"\n");
480                        (void) ConcatenateString(&message,"  digest (");
481                        (void) ConcatenateString(&message,timestamp);
482                        (void) ConcatenateString(&message,"):\n    ");
483                        (void) ConcatenateString(&message,digest);
484                        (void) ConcatenateString(&message,"\n");
485                        (void) ConcatenateString(&message,"  errant digest (");
486                        (void) FormatWizardTime(time((time_t *) NULL),
487                          MaxTextExtent,date);
488                        (void) ConcatenateString(&message,date);
489                        (void) ConcatenateString(&message,"):\n    ");
490                        (void) ConcatenateString(&message,GetHashHexDigest(
491                          hash_info));
492                        (void) ConcatenateString(&message,"\n");
493                        count=WriteBlobString(authenticate_blob,message);
494                        if (count != (ssize_t) strlen(message))
495                          ThrowFileException(exception,FileError,argv[argc-1]);
496                        message=DestroyString(message);
497                      }
498                    hash_info=DestroyHashInfo(hash_info);
499                    if (CloseBlob(content_blob) != WizardFalse)
500                      ThrowFileException(exception,FileError,argv[i]);
501                    content_blob=DestroyBlob(content_blob);
502                    break;
503                  }
504              }
505              default:
506                break;
507            }
508          }
509        while (isspace((int) ((unsigned char) c)) != 0)
510          c=ReadBlobByte(digest_blob);
511      }
512      options=DestroyString(options);
513      if (CloseBlob(digest_blob) != WizardFalse)
514        ThrowFileException(exception,FileError,argv[i]);
515    }
516    if (path != (char *) NULL)
517      path=DestroyString(path);
518    if (digest != (char *) NULL)
519      digest=DestroyString(digest);
520    if (timestamp != (char *) NULL)
521      timestamp=DestroyString(timestamp);
522    if (create_date != (char *) NULL)
523      create_date=DestroyString(create_date);
524    if (modify_date != (char *) NULL)
525      modify_date=DestroyString(modify_date);
526  }
527  (void) CloseBlob(authenticate_blob);
528  authenticate_blob=DestroyBlob(authenticate_blob);
529  if (hash == UndefinedHash)
530    ThrowDigestException(OptionError,"missing a digest RDF file: `%s'",
531      argv[argc-1]);
532  return(status);
533}
534
535WizardExport WizardBooleanType DigestCommand(int argc,char **argv,
536  ExceptionInfo *exception)
537{
538  BlobInfo
539    *content_blob,
540    *digest_blob;
541
542  char
543    algorithm[MaxTextExtent],
544    *canonical_path,
545    content_extent[MaxTextExtent],
546    *digest_rdf,
547    *digest,
548    *option,
549    timestamp[MaxTextExtent];
550
551  const struct stat
552    *properties;
553
554  HashInfo
555    *hash_info;
556
557  HashType
558    hash;
559
560  register long
561    i;
562
563  size_t
564    length;
565
566  ssize_t
567    count;
568
569  StringInfo
570    *content;
571
572  WizardBooleanType
573    compress,
574    status;
575
576  WizardSizeType
577    extent;
578
579  /*
580    Parse command-line options.
581  */
582  if (argc == 2)
583    {
584      option=argv[1];
585      if ((LocaleCompare("version",option+1) == 0) ||
586          (LocaleCompare("-version",option+1) == 0))
587        {
588          (void) fprintf(stdout,"Version: %s\n",GetWizardVersion(
589            (unsigned long *) NULL));
590          (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
591          return(WizardTrue);
592        }
593    }
594  if (argc < 3)
595    DigestUsage();
596  status=ExpandFilenames(&argc,&argv);
597  if (status == WizardFalse)
598    ThrowDigestException(ResourceError,"memory allocation failed: `%s'",
599      strerror(errno));
600  for (i=1; i < (argc-1); i++)
601  {
602    option=argv[i];
603    if (LocaleCompare(option+1,"authenticate") == 0)
604      {
605        status=AuthenticateDigest(argc,argv,exception);
606        DestroyDigest();
607        return(status);
608      }
609  }
610  digest_blob=OpenBlob(argv[argc-1],WriteBinaryBlobMode,WizardTrue,exception);
611  if (digest_blob == (BlobInfo *) NULL)
612    return(WizardFalse);
613  hash=SHA256Hash;
614  (void) WriteBlobString(digest_blob,"<?xml version=\"1.0\"?>\n");
615  (void) WriteBlobString(digest_blob,"<rdf:RDF xmlns:rdf=\""
616    "http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\n");
617  (void) WriteBlobString(digest_blob,"         xmlns:digest=\""
618     "http://www.wizards-toolkit.org/digest/1.0/\">\n");
619  compress=WizardFalse;
620  for (i=1; i < (argc-1); i++)
621  {
622    option=argv[i];
623    if (*option == '-')
624      {
625        switch(*(option+1))
626        {
627          case '(':
628          {
629            if (LocaleCompare(option+1,"(de)compress") == 0)
630              {
631                compress=(*option == '-') ? WizardTrue : WizardFalse;
632                break;
633              }
634            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
635              option);
636            break;
637          }
638          case 'd':
639          {
640            if (strcasecmp(option,"-debug") == 0)
641              {
642                LogEventType
643                  event_mask;
644
645                i++;
646                if (i == argc)
647                  ThrowDigestException(OptionError,"missing log event mask: "
648                    "`%s'",option);
649                event_mask=SetLogEventMask(argv[i]);
650                if (event_mask == UndefinedEvents)
651                  ThrowDigestException(OptionFatalError,"unrecognized log "
652                    "event type: `%s'",argv[i]);
653                break;
654              }
655            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
656              option);
657            break;
658          }
659          case 'h':
660          {
661            if (LocaleCompare("hash",option+1) == 0)
662              {
663                long
664                  type;
665
666                if (*option == '+')
667                  break;
668                i++;
669                if (i == (long) argc)
670                  ThrowDigestException(OptionError,"missing hash type: `%s'",
671                    option);
672                type=ParseWizardOption(WizardHashOptions,WizardFalse,argv[i]);
673                if (type < 0)
674                  ThrowDigestException(OptionFatalError,"unrecognized hash "
675                    "type: `%s'",argv[i]);
676                hash=(HashType) type;
677                break;
678              }
679            if ((LocaleCompare("help",option+1) == 0) ||
680                (LocaleCompare("-help",option+1) == 0))
681              DigestUsage();
682            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
683              option);
684            break;
685          }
686          case 'l':
687          {
688            if (LocaleCompare("log",option+1) == 0)
689              {
690                if (*option == '+')
691                  break;
692                i++;
693                if ((i == (long) argc) ||
694                    (strchr(argv[i],'%') == (char *) NULL))
695                  ThrowDigestException(OptionFatalError,"missing argument: "
696                    "`%s'",option);
697                break;
698              }
699            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
700              option);
701            break;
702          }
703          case 'v':
704          {
705            if (strcasecmp(option,"-version") == 0)
706              {
707                (void) fprintf(stdout,"Version: %s\n",
708                  GetWizardVersion((unsigned long *) NULL));
709                (void) fprintf(stdout,"Copyright: %s\n\n",GetWizardCopyright());
710                exit(0);
711              }
712            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
713              option);
714            break;
715          }
716          default:
717          {
718            ThrowDigestException(OptionFatalError,"unrecognized option: `%s'",
719              option);
720            break;
721          }
722        }
723        continue;
724      }
725    /*
726      Compute message digest for this content.
727    */
728    content_blob=OpenBlob(argv[i],ReadBinaryBlobMode,compress,exception);
729    if (content_blob == (BlobInfo *) NULL)
730      continue;
731    properties=GetBlobProperties(content_blob);
732    hash_info=AcquireHashInfo(SHA256Hash);
733    InitializeHash(hash_info);
734    extent=0;
735    for (content=AcquireStringInfo(WizardMaxBufferExtent); ; )
736    {
737      count=ReadBlobChunk(content_blob,WizardMaxBufferExtent,GetStringInfoDatum(
738        content));
739      if (count <= 0)
740        break;
741      length=(size_t) count;
742      SetStringInfoLength(content,length);
743      UpdateHash(hash_info,content);
744      extent+=length;
745    }
746    FinalizeHash(hash_info);
747    digest_rdf=AcquireString("  <digest:Content rdf:about=\"");
748    canonical_path=CanonicalXMLContent(argv[i],WizardFalse);
749    (void) ConcatenateString(&digest_rdf,canonical_path);
750    canonical_path=DestroyString(canonical_path);
751    (void) ConcatenateString(&digest_rdf,"\">\n");
752    (void) ConcatenateString(&digest_rdf,"    <digest:timestamp>");
753    (void) FormatWizardTime(time((time_t *) NULL),MaxTextExtent,timestamp);
754    (void) ConcatenateString(&digest_rdf,timestamp);
755    (void) ConcatenateString(&digest_rdf,"</digest:timestamp>\n");
756    (void) ConcatenateString(&digest_rdf,"    <digest:modify-date>");
757    (void) FormatWizardTime(properties->st_mtime,MaxTextExtent,timestamp);
758    (void) ConcatenateString(&digest_rdf,timestamp);
759    (void) ConcatenateString(&digest_rdf,"</digest:modify-date>\n");
760    (void) ConcatenateString(&digest_rdf,"    <digest:create-date>");
761    (void) FormatWizardTime(properties->st_mtime,MaxTextExtent,timestamp);
762    (void) ConcatenateString(&digest_rdf,timestamp);
763    (void) ConcatenateString(&digest_rdf,"</digest:create-date>\n");
764    (void) ConcatenateString(&digest_rdf,"    <digest:extent>");
765    (void) FormatWizardString(content_extent,MaxTextExtent,WizardSizeFormat,
766      extent);
767    (void) ConcatenateString(&digest_rdf,content_extent);
768    (void) ConcatenateString(&digest_rdf,"</digest:extent>\n");
769    (void) ConcatenateString(&digest_rdf,"    <digest:");
770    (void) FormatWizardString(algorithm,MaxTextExtent,"%s",
771      WizardOptionToMnemonic(WizardHashOptions,hash));
772    LocaleLower(algorithm);
773    (void) ConcatenateString(&digest_rdf,algorithm);
774    (void) ConcatenateString(&digest_rdf,">");
775    digest=GetHashHexDigest(hash_info);
776    (void) ConcatenateString(&digest_rdf,digest);
777    digest=DestroyString(digest);
778    (void) ConcatenateString(&digest_rdf,"</digest:");
779    (void) FormatWizardString(algorithm,MaxTextExtent,"%s",
780      WizardOptionToMnemonic(WizardHashOptions,hash));
781    LocaleLower(algorithm);
782    (void) ConcatenateString(&digest_rdf,algorithm);
783    (void) ConcatenateString(&digest_rdf,">\n");
784    (void) ConcatenateString(&digest_rdf,"  </digest:Content>\n");
785    content=DestroyStringInfo(content);
786    hash_info=DestroyHashInfo(hash_info);
787    if (CloseBlob(content_blob) != WizardFalse)
788      ThrowFileException(exception,FileError,argv[i]);
789    content_blob=DestroyBlob(content_blob);
790    length=strlen(digest_rdf);
791    count=WriteBlob(digest_blob,length,(unsigned char *) digest_rdf);
792    digest_rdf=DestroyString(digest_rdf);
793    if (count != (ssize_t) length)
794      ThrowFileException(exception,FileError,argv[argc-1]);
795  }
796  (void) WriteBlobString(digest_blob,"</rdf:RDF>\n");
797  status=CloseBlob(digest_blob);
798  /*
799    Free resources.
800  */
801  digest_blob=DestroyBlob(digest_blob);
802  DestroyDigest();
803  return(status);
804}
805
806/*
807%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
808%                                                                             %
809%                                                                             %
810%                                                                             %
811%  M a i n                                                                    %
812%                                                                             %
813%                                                                             %
814%                                                                             %
815%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
816%
817%
818*/
819int main(int argc,char **argv)
820{
821  char
822    *option;
823
824  double
825    elapsed_time,
826    user_time;
827
828  ExceptionInfo
829    *exception;
830
831  register long
832    i;
833
834  TimerInfo
835    *timer;
836
837  unsigned int
838    iterations;
839
840  WizardBooleanType
841    regard_warnings,
842    status;
843
844  WizardsToolkitGenesis(*argv);
845  exception=AcquireExceptionInfo();
846  iterations=1;
847  status=WizardTrue;
848  regard_warnings=WizardFalse;
849  for (i=1; i < (long) (argc-1); i++)
850  {
851    option=argv[i];
852    if ((strlen(option) == 1) || ((*option != '-') && (*option != '+')))
853      continue;
854    if (LocaleCompare("bench",option+1) == 0)
855      iterations=(unsigned int) atol(argv[++i]);
856    if (LocaleCompare("debug",option+1) == 0)
857      (void) SetLogEventMask(argv[++i]);
858    if (LocaleCompare("regard-warnings",option+1) == 0)
859      regard_warnings=WizardTrue;
860  }
861  timer=(TimerInfo *) NULL;
862  if (iterations > 1)
863    timer=AcquireTimerInfo();
864  for (i=0; i < (long) iterations; i++)
865  {
866    status=DigestCommand(argc,argv,exception);
867    if ((status == WizardFalse) ||
868        (GetExceptionSeverity(exception) != UndefinedException))
869      {
870        if ((GetExceptionSeverity(exception) < ErrorException) &&
871            (regard_warnings == WizardFalse))
872          status=WizardTrue;
873        CatchException(exception);
874      }
875  }
876  if (iterations > 1)
877    {
878      elapsed_time=GetElapsedTime(timer);
879      user_time=GetUserTime(timer);
880      (void) fprintf(stderr,"Performance: %ui %gips %0.3fu %ld:%02ld.%03ld\n",
881        iterations,1.0*iterations/elapsed_time,user_time,(long)
882        (elapsed_time/60.0+0.5),(long) floor(fmod(elapsed_time,60.0)),
883        (long) (1000.0*(elapsed_time-floor(elapsed_time))+0.5));
884      timer=DestroyTimerInfo(timer);
885    }
886  exception=DestroyExceptionInfo(exception);
887  WizardsToolkitTerminus();
888  return(status == WizardFalse ? 1 : 0);
889}
Note: See TracBrowser for help on using the browser.