1 /* 2 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 % % 4 % % 5 % DDDD EEEEE L EEEEE GGGG AAA TTTTT EEEEE % 6 % D D E L E G A A T E % 7 % D D EEE L EEE G GG AAAAA T EEE % 8 % D D E L E G G A A T E % 9 % DDDD EEEEE LLLLL EEEEE GGG A A T EEEEE % 10 % % 11 % % 12 % MagickCore Methods to Read/Write/Invoke Delegates % 13 % % 14 % Software Design % 15 % Cristy % 16 % October 1998 % 17 % % 18 % % 19 % Copyright 1999-2016 ImageMagick Studio LLC, a non-profit organization % 20 % dedicated to making software imaging solutions freely available. % 21 % % 22 % You may not use this file except in compliance with the License. You may % 23 % obtain a copy of the License at % 24 % % 25 % http://www.imagemagick.org/script/license.php % 26 % % 27 % Unless required by applicable law or agreed to in writing, software % 28 % distributed under the License is distributed on an "AS IS" BASIS, % 29 % WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. % 30 % See the License for the specific language governing permissions and % 31 % limitations under the License. % 32 % % 33 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 % 35 % The Delegates methods associate a set of commands with a particular 36 % image format. ImageMagick uses delegates for formats it does not handle 37 % directly. 38 % 39 % Thanks to Bob Friesenhahn for the initial inspiration and design of the 40 % delegates methods. 41 % 42 % 43 */ 44 45 /* 47 Include declarations. 48 */ 49 #include "MagickCore/studio.h" 50 #include "MagickCore/artifact.h" 51 #include "MagickCore/attribute.h" 52 #include "MagickCore/blob.h" 53 #include "MagickCore/client.h" 54 #include "MagickCore/configure.h" 55 #include "MagickCore/constitute.h" 56 #include "MagickCore/delegate.h" 57 #include "MagickCore/delegate-private.h" 58 #include "MagickCore/exception.h" 59 #include "MagickCore/exception-private.h" 60 #include "MagickCore/fx-private.h" 61 #include "MagickCore/image-private.h" 62 #include "MagickCore/linked-list.h" 63 #include "MagickCore/list.h" 64 #include "MagickCore/memory_.h" 65 #include "MagickCore/nt-base-private.h" 66 #include "MagickCore/option.h" 67 #include "MagickCore/policy.h" 68 #include "MagickCore/property.h" 69 #include "MagickCore/resource_.h" 70 #include "MagickCore/semaphore.h" 71 #include "MagickCore/signature.h" 72 #include "MagickCore/string_.h" 73 #include "MagickCore/token.h" 74 #include "MagickCore/token-private.h" 75 #include "MagickCore/utility.h" 76 #include "MagickCore/utility-private.h" 77 #include "MagickCore/xml-tree.h" 78 #include "MagickCore/xml-tree-private.h" 79 80 /* 82 Define declarations. 83 */ 84 #define DelegateFilename "delegates.xml" 85 86 /* 88 Declare delegate map. 89 */ 90 static const char 91 *DelegateMap = (const char *) 92 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" 93 "<delegatemap>" 94 " <delegate decode=\"autotrace\" stealth=\"True\" command=\""autotrace" -output-format svg -output-file "%o" "%i"\"/>" 95 " <delegate decode=\"avi:decode\" stealth=\"True\" command=\""mplayer" "%i" -really-quiet -ao null -vo png:z=3\"/>" 96 " <delegate decode=\"browse\" stealth=\"True\" spawn=\"True\" command=\""xdg-open" http://www.imagemagick.org/; rm "%i"\"/>" 97 " <delegate decode=\"cgm\" thread-support=\"False\" command=\""ralcgm" -d ps -oC < "%i" > "%o" 2> "%u"\"/>" 98 " <delegate decode=\"dng:decode\" command=\""ufraw-batch" --silent --create-id=also --out-type=png --out-depth=16 "--output=%u.png" "%i"\"/>" 99 " <delegate decode=\"edit\" stealth=\"True\" command=\""xterm" -title "Edit Image Comment" -e vi "%o"\"/>" 100 " <delegate decode=\"eps\" encode=\"pdf\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pdfwrite" "-sOutputFile=%o" "-f%i"\"/>" 101 " <delegate decode=\"eps\" encode=\"ps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=ps2write" "-sOutputFile=%o" "-f%i"\"/>" 102 " <delegate decode=\"fig\" command=\""fig2dev" -L ps "%i" "%o"\"/>" 103 " <delegate decode=\"hpg\" command=\""hp2xx" -q -m eps -f `basename "%o"` "%i" mv -f `basename "%o"` "%o"\"/>" 104 " <delegate decode=\"hpgl\" command=\""hp2xx" -q -m eps -f `basename "%o"` "%i" mv -f `basename "%o"` "%o"\"/>" 105 " <delegate decode=\"htm\" command=\""html2ps" -U -o "%o" "%i"\"/>" 106 " <delegate decode=\"html\" command=\""html2ps" -U -o "%o" "%i"\"/>" 107 " <delegate decode=\"https\" command=\""curl" -s -k -L -o "%o" "https:%M"\"/>" 108 " <delegate decode=\"ilbm\" command=\""ilbmtoppm" "%i" > "%o"\"/>" 109 " <delegate decode=\"man\" command=\""groff" -man -Tps "%i" > "%o"\"/>" 110 " <delegate decode=\"mpeg:decode\" stealth=\"True\" command=\""ffmpeg" -nostdin -v -1 -vframes %S -i "%i" -vcodec pam -an -f rawvideo -y "%u.pam" 2> "%Z"\"/>" 111 " <delegate decode=\"null\" encode=\"mpeg:encode\" stealth=\"True\" command=\""ffmpeg" -nostdin -v -1 -mbd rd -trellis 2 -cmp 2 -subcmp 2 -g 300 -i "%M%%d.jpg" "%u.%m" 2> "%Z"\"/>" 112 " <delegate decode=\"pcl:color\" stealth=\"True\" command=\""pcl6" -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=ppmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "%s"\"/>" 113 " <delegate decode=\"pcl:cmyk\" stealth=\"True\" command=\""pcl6" -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=bmpsep8" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "%s"\"/>" 114 " <delegate decode=\"pcl:mono\" stealth=\"True\" command=\""pcl6" -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pbmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "%s"\"/>" 115 " <delegate decode=\"pdf\" encode=\"eps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=eps2write" "-sOutputFile=%o" "-f%i"\"/>" 116 " <delegate decode=\"pdf\" encode=\"ps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=ps2write" "-sOutputFile=%o" "-f%i"\"/>" 117 " <delegate decode=\"pnm\" encode=\"ilbm\" mode=\"encode\" command=\""ppmtoilbm" -24if "%i" > "%o"\"/>" 118 " <delegate decode=\"pnm\" encode=\"launch\" mode=\"encode\" command=\""gimp" "%i"\"/>" 119 " <delegate decode=\"pov\" command=\""povray" "+i"%i"" -D0 +o"%o" +fn%q +w%w +h%h +a -q9 -kfi"%s" -kff"%n" "convert" -concatenate "%o*.png" "%o"\"/>" 120 " <delegate decode=\"ps\" encode=\"eps\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=eps2write" "-sOutputFile=%o" "-f%i"\"/>" 121 " <delegate decode=\"ps\" encode=\"pdf\" mode=\"bi\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pdfwrite" "-sOutputFile=%o" "-f%i"\"/>" 122 " <delegate decode=\"ps\" encode=\"print\" mode=\"encode\" command=\"lpr "%i"\"/>" 123 " <delegate decode=\"ps:alpha\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>" 124 " <delegate decode=\"ps:bbox\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=bbox" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>" 125 " <delegate decode=\"ps:cmyk\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=bmpsep8" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>" 126 " <delegate decode=\"ps:color\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pnmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>" 127 " <delegate decode=\"ps:mono\" stealth=\"True\" command=\""gs" -q -dQUIET -dSAFER -dBATCH -dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pnmraw" -dTextAlphaBits=%u -dGraphicsAlphaBits=%u "-r%s" %s "-sOutputFile=%s" "-f%s" "-f%s"\"/>" 128 " <delegate decode=\"rgba\" encode=\"rle\" mode=\"encode\" command=\""rawtorle" -o "%o" -v "%i"\"/>" 129 " <delegate decode=\"scan\" command=\""scanimage" -d "%i" > "%o"\"/>" 130 " <delegate encode=\"show\" spawn=\"True\" command=\""display" -immutable -delay 0 -title "%M" "%i"\"/>" 131 " <delegate decode=\"shtml\" command=\""html2ps" -U -o "%o" "%i"\"/>" 132 " <delegate decode=\"svg\" command=\""rsvg" "%i" "%o"\"/>" 133 " <delegate decode=\"txt\" encode=\"ps\" mode=\"bi\" command=\""enscript" -o "%o" "%i"\"/>" 134 " <delegate encode=\"win\" stealth=\"True\" spawn=\"True\" command=\""display" -immutable -delay 0 -title "%M" "%i"\"/>" 135 " <delegate decode=\"wmf\" command=\""wmf2eps" -o "%o" "%i"\"/>" 136 "</delegatemap>"; 137 138 /* 140 Global declaractions. 141 */ 142 static LinkedListInfo 143 *delegate_cache = (LinkedListInfo *) NULL; 144 145 static SemaphoreInfo 146 *delegate_semaphore = (SemaphoreInfo *) NULL; 147 148 /* 150 Forward declaractions. 151 */ 152 static MagickBooleanType 153 IsDelegateCacheInstantiated(ExceptionInfo *), 154 LoadDelegateCache(LinkedListInfo *,const char *,const char *,const size_t, 155 ExceptionInfo *); 156 157 /* 159 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 160 % % 161 % % 162 % % 163 % A c q u i r e D e l e g a t e C a c h e % 164 % % 165 % % 166 % % 167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 168 % 169 % AcquireDelegateCache() caches one or more delegate configurations which 170 % provides a mapping between delegate attributes and a delegate name. 171 % 172 % The format of the AcquireDelegateCache method is: 173 % 174 % LinkedListInfo *AcquireDelegateCache(const char *filename, 175 % ExceptionInfo *exception) 176 % 177 % A description of each parameter follows: 178 % 179 % o filename: the font file name. 180 % 181 % o exception: return any errors or warnings in this structure. 182 % 183 */ 184 static LinkedListInfo *AcquireDelegateCache(const char *filename, 185 ExceptionInfo *exception) 186 { 187 LinkedListInfo 188 *cache; 189 190 MagickStatusType 191 status; 192 193 cache=NewLinkedList(0); 194 if (cache == (LinkedListInfo *) NULL) 195 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 196 status=MagickTrue; 197 #if !defined(MAGICKCORE_ZERO_CONFIGURATION_SUPPORT) 198 { 199 const StringInfo 200 *option; 201 202 LinkedListInfo 203 *options; 204 205 options=GetConfigureOptions(filename,exception); 206 option=(const StringInfo *) GetNextValueInLinkedList(options); 207 while (option != (const StringInfo *) NULL) 208 { 209 status&=LoadDelegateCache(cache,(const char *) 210 GetStringInfoDatum(option),GetStringInfoPath(option),0,exception); 211 option=(const StringInfo *) GetNextValueInLinkedList(options); 212 } 213 options=DestroyConfigureOptions(options); 214 } 215 #endif 216 if (IsLinkedListEmpty(cache) != MagickFalse) 217 status&=LoadDelegateCache(cache,DelegateMap,"built-in",0,exception); 218 return(cache); 219 } 220 221 /* 223 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 224 % % 225 % % 226 % % 227 + D e l e g a t e C o m p o n e n t G e n e s i s % 228 % % 229 % % 230 % % 231 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 232 % 233 % DelegateComponentGenesis() instantiates the delegate component. 234 % 235 % The format of the DelegateComponentGenesis method is: 236 % 237 % MagickBooleanType DelegateComponentGenesis(void) 238 % 239 */ 240 MagickPrivate MagickBooleanType DelegateComponentGenesis(void) 241 { 242 if (delegate_semaphore == (SemaphoreInfo *) NULL) 243 delegate_semaphore=AcquireSemaphoreInfo(); 244 return(MagickTrue); 245 } 246 247 /* 249 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 250 % % 251 % % 252 % % 253 % D e l e g a t e C o m p o n e n t T e r m i n u s % 254 % % 255 % % 256 % % 257 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 258 % 259 % DelegateComponentTerminus() destroys the delegate component. 260 % 261 % The format of the DelegateComponentTerminus method is: 262 % 263 % DelegateComponentTerminus(void) 264 % 265 */ 266 267 static void *DestroyDelegate(void *delegate_info) 268 { 269 register DelegateInfo 270 *p; 271 272 p=(DelegateInfo *) delegate_info; 273 if (p->path != (char *) NULL) 274 p->path=DestroyString(p->path); 275 if (p->decode != (char *) NULL) 276 p->decode=DestroyString(p->decode); 277 if (p->encode != (char *) NULL) 278 p->encode=DestroyString(p->encode); 279 if (p->commands != (char *) NULL) 280 p->commands=DestroyString(p->commands); 281 if (p->semaphore != (SemaphoreInfo *) NULL) 282 RelinquishSemaphoreInfo(&p->semaphore); 283 p=(DelegateInfo *) RelinquishMagickMemory(p); 284 return((void *) NULL); 285 } 286 287 MagickPrivate void DelegateComponentTerminus(void) 288 { 289 if (delegate_semaphore == (SemaphoreInfo *) NULL) 290 ActivateSemaphoreInfo(&delegate_semaphore); 291 LockSemaphoreInfo(delegate_semaphore); 292 if (delegate_cache != (LinkedListInfo *) NULL) 293 delegate_cache=DestroyLinkedList(delegate_cache,DestroyDelegate); 294 UnlockSemaphoreInfo(delegate_semaphore); 295 RelinquishSemaphoreInfo(&delegate_semaphore); 296 } 297 298 /* 300 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 301 % % 302 % % 303 % % 304 + E x t e r n a l D e l e g a t e C o m m a n d % 305 % % 306 % % 307 % % 308 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 309 % 310 % ExternalDelegateCommand() executes the specified command and waits until it 311 % terminates. The returned value is the exit status of the command. 312 % 313 % The format of the ExternalDelegateCommand method is: 314 % 315 % int ExternalDelegateCommand(const MagickBooleanType asynchronous, 316 % const MagickBooleanType verbose,const char *command, 317 % char *message,ExceptionInfo *exception) 318 % 319 % A description of each parameter follows: 320 % 321 % o asynchronous: a value other than 0 executes the parent program 322 % concurrently with the new child process. 323 % 324 % o verbose: a value other than 0 prints the executed command before it is 325 % invoked. 326 % 327 % o command: this string is the command to execute. 328 % 329 % o message: an option buffer to receive any message posted to stdout or 330 % stderr. 331 % 332 % o exception: return any errors here. 333 % 334 */ 335 MagickExport int ExternalDelegateCommand(const MagickBooleanType asynchronous, 336 const MagickBooleanType verbose,const char *command,char *message, 337 ExceptionInfo *exception) 338 { 339 char 340 **arguments, 341 *sanitize_command; 342 343 int 344 number_arguments, 345 status; 346 347 PolicyDomain 348 domain; 349 350 PolicyRights 351 rights; 352 353 register ssize_t 354 i; 355 356 status=(-1); 357 arguments=StringToArgv(command,&number_arguments); 358 if (arguments == (char **) NULL) 359 return(status); 360 if (*arguments[1] == '\0') 361 { 362 for (i=0; i < (ssize_t) number_arguments; i++) 363 arguments[i]=DestroyString(arguments[i]); 364 arguments=(char **) RelinquishMagickMemory(arguments); 365 return(-1); 366 } 367 rights=ExecutePolicyRights; 368 domain=DelegatePolicyDomain; 369 if (IsRightsAuthorized(domain,rights,arguments[1]) == MagickFalse) 370 { 371 errno=EPERM; 372 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError, 373 "NotAuthorized","`%s'",arguments[1]); 374 for (i=0; i < (ssize_t) number_arguments; i++) 375 arguments[i]=DestroyString(arguments[i]); 376 arguments=(char **) RelinquishMagickMemory(arguments); 377 return(-1); 378 } 379 if (verbose != MagickFalse) 380 { 381 (void) FormatLocaleFile(stderr,"%s\n",command); 382 (void) fflush(stderr); 383 } 384 sanitize_command=SanitizeString(command); 385 if (asynchronous != MagickFalse) 386 (void) ConcatenateMagickString(sanitize_command,"&",MagickPathExtent); 387 if (message != (char *) NULL) 388 *message='\0'; 389 #if defined(MAGICKCORE_POSIX_SUPPORT) 390 #if !defined(MAGICKCORE_HAVE_EXECVP) 391 status=system(sanitize_command); 392 #else 393 if ((asynchronous != MagickFalse) || 394 (strpbrk(sanitize_command,"&;<>|") != (char *) NULL)) 395 status=system(sanitize_command); 396 else 397 { 398 pid_t 399 child_pid; 400 401 /* 402 Call application directly rather than from a shell. 403 */ 404 child_pid=(pid_t) fork(); 405 if (child_pid == (pid_t) -1) 406 status=system(sanitize_command); 407 else 408 if (child_pid == 0) 409 { 410 status=execvp(arguments[1],arguments+1); 411 _exit(1); 412 } 413 else 414 { 415 int 416 child_status; 417 418 pid_t 419 pid; 420 421 child_status=0; 422 pid=(pid_t) waitpid(child_pid,&child_status,0); 423 if (pid == -1) 424 status=(-1); 425 else 426 { 427 if (WIFEXITED(child_status) != 0) 428 status=WEXITSTATUS(child_status); 429 else 430 if (WIFSIGNALED(child_status)) 431 status=(-1); 432 } 433 } 434 } 435 #endif 436 #elif defined(MAGICKCORE_WINDOWS_SUPPORT) 437 { 438 register char 439 *p; 440 441 /* 442 If a command shell is executed we need to change the forward slashes in 443 files to a backslash. We need to do this to keep Windows happy when we 444 want to 'move' a file. 445 446 TODO: This won't work if one of the delegate parameters has a forward 447 slash as aparameter. 448 */ 449 p=strstr(sanitize_command, "cmd.exe /c"); 450 if (p != (char*) NULL) 451 { 452 p+=10; 453 for (; *p != '\0'; p++) 454 if (*p == '/') 455 *p=*DirectorySeparator; 456 } 457 } 458 status=NTSystemCommand(sanitize_command,message); 459 #elif defined(macintosh) 460 status=MACSystemCommand(sanitize_command); 461 #elif defined(vms) 462 status=system(sanitize_command); 463 #else 464 # error No suitable system() method. 465 #endif 466 if (status < 0) 467 { 468 if ((message != (char *) NULL) && (*message != '\0')) 469 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, 470 "FailedToExecuteCommand","`%s' (%s)",sanitize_command,message); 471 else 472 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, 473 "FailedToExecuteCommand","`%s' (%d)",sanitize_command,status); 474 } 475 sanitize_command=DestroyString(sanitize_command); 476 for (i=0; i < (ssize_t) number_arguments; i++) 477 arguments[i]=DestroyString(arguments[i]); 478 arguments=(char **) RelinquishMagickMemory(arguments); 479 return(status); 480 } 481 482 /* 484 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 485 % % 486 % % 487 % % 488 % G e t D e l e g a t e C o m m a n d % 489 % % 490 % % 491 % % 492 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 493 % 494 % GetDelegateCommand() replaces any embedded formatting characters with the 495 % appropriate image attribute and returns the resulting command. 496 % 497 % The format of the GetDelegateCommand method is: 498 % 499 % char *GetDelegateCommand(const ImageInfo *image_info,Image *image, 500 % const char *decode,const char *encode,ExceptionInfo *exception) 501 % 502 % A description of each parameter follows: 503 % 504 % o command: Method GetDelegateCommand returns the command associated 505 % with specified delegate tag. 506 % 507 % o image_info: the image info. 508 % 509 % o image: the image. 510 % 511 % o decode: Specifies the decode delegate we are searching for as a 512 % character string. 513 % 514 % o encode: Specifies the encode delegate we are searching for as a 515 % character string. 516 % 517 % o exception: return any errors or warnings in this structure. 518 % 519 */ 520 521 static char *GetMagickPropertyLetter(ImageInfo *image_info,Image *image, 522 const char letter,ExceptionInfo *exception) 523 { 524 #define WarnNoImageReturn(format,letter) \ 525 if (image == (Image *) NULL) \ 526 { \ 527 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \ 528 "NoImageForProperty",format,letter); \ 529 break; \ 530 } 531 #define WarnNoImageInfoReturn(format,letter) \ 532 if (image_info == (ImageInfo *) NULL) \ 533 { \ 534 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, \ 535 "NoImageInfoForProperty",format,letter); \ 536 break; \ 537 } 538 539 char 540 value[MagickPathExtent]; 541 542 const char 543 *string; 544 545 if ((image != (Image *) NULL) && (image->debug != MagickFalse)) 546 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 547 else 548 if ((image_info != (ImageInfo *) NULL) && 549 (image_info->debug != MagickFalse)) 550 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-images"); 551 /* 552 Get properties that are directly defined by images. 553 */ 554 *value='\0'; /* formatted string */ 555 string=(const char *) value; 556 switch (letter) 557 { 558 case 'a': /* authentication passphase */ 559 { 560 WarnNoImageInfoReturn("\"%%%c\"",letter); 561 string=GetImageOption(image_info,"authenticate"); 562 break; 563 } 564 case 'b': /* image size read in - in bytes */ 565 { 566 WarnNoImageReturn("\"%%%c\"",letter); 567 (void) FormatMagickSize(image->extent,MagickFalse,"B",MagickPathExtent, 568 value); 569 if (image->extent == 0) 570 (void) FormatMagickSize(GetBlobSize(image),MagickFalse,"B", 571 MagickPathExtent,value); 572 break; 573 } 574 case 'd': /* Directory component of filename */ 575 { 576 WarnNoImageReturn("\"%%%c\"",letter); 577 GetPathComponent(image->magick_filename,HeadPath,value); 578 break; 579 } 580 case 'e': /* Filename extension (suffix) of image file */ 581 { 582 WarnNoImageReturn("\"%%%c\"",letter); 583 GetPathComponent(image->magick_filename,ExtensionPath,value); 584 break; 585 } 586 case 'f': /* Filename without directory component */ 587 { 588 WarnNoImageReturn("\"%%%c\"",letter); 589 GetPathComponent(image->magick_filename,TailPath,value); 590 break; 591 } 592 case 'g': /* Image geometry, canvas and offset %Wx%H+%X+%Y */ 593 { 594 WarnNoImageReturn("\"%%%c\"",letter); 595 (void) FormatLocaleString(value,MagickPathExtent, 596 "%.20gx%.20g%+.20g%+.20g",(double) image->page.width,(double) 597 image->page.height,(double) image->page.x,(double) image->page.y); 598 break; 599 } 600 case 'h': /* Image height (current) */ 601 { 602 WarnNoImageReturn("\"%%%c\"",letter); 603 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 604 (image->rows != 0 ? image->rows : image->magick_rows)); 605 break; 606 } 607 case 'i': /* Filename last used for an image (read or write) */ 608 { 609 WarnNoImageReturn("\"%%%c\"",letter); 610 string=image->filename; 611 break; 612 } 613 case 'm': /* Image format (file magick) */ 614 { 615 WarnNoImageReturn("\"%%%c\"",letter); 616 string=image->magick; 617 break; 618 } 619 case 'n': /* Number of images in the list. */ 620 { 621 if (image != (Image *) NULL) 622 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 623 GetImageListLength(image)); 624 break; 625 } 626 case 'o': /* Output Filename */ 627 { 628 WarnNoImageInfoReturn("\"%%%c\"",letter); 629 string=image_info->filename; 630 break; 631 } 632 case 'p': /* Image index in current image list */ 633 { 634 WarnNoImageReturn("\"%%%c\"",letter); 635 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 636 GetImageIndexInList(image)); 637 break; 638 } 639 case 'q': /* Quantum depth of image in memory */ 640 { 641 WarnNoImageReturn("\"%%%c\"",letter); 642 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 643 MAGICKCORE_QUANTUM_DEPTH); 644 break; 645 } 646 case 'r': /* Image storage class, colorspace, and alpha enabled. */ 647 { 648 ColorspaceType 649 colorspace; 650 651 WarnNoImageReturn("\"%%%c\"",letter); 652 colorspace=image->colorspace; 653 if (SetImageGray(image,exception) != MagickFalse) 654 colorspace=GRAYColorspace; /* FUTURE: this is IMv6 not IMv7 */ 655 (void) FormatLocaleString(value,MagickPathExtent,"%s %s %s", 656 CommandOptionToMnemonic(MagickClassOptions,(ssize_t) 657 image->storage_class),CommandOptionToMnemonic(MagickColorspaceOptions, 658 (ssize_t) colorspace),image->alpha_trait != UndefinedPixelTrait ? 659 "Alpha" : ""); 660 break; 661 } 662 case 's': /* Image scene number */ 663 { 664 WarnNoImageReturn("\"%%%c\"",letter); 665 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 666 image->scene); 667 break; 668 } 669 case 't': /* Base filename without directory or extention */ 670 { 671 WarnNoImageReturn("\"%%%c\"",letter); 672 GetPathComponent(image->magick_filename,BasePath,value); 673 break; 674 } 675 case 'u': /* Unique filename */ 676 { 677 WarnNoImageInfoReturn("\"%%%c\"",letter); 678 string=image_info->unique; 679 break; 680 } 681 case 'w': /* Image width (current) */ 682 { 683 WarnNoImageReturn("\"%%%c\"",letter); 684 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 685 (image->columns != 0 ? image->columns : image->magick_columns)); 686 break; 687 } 688 case 'x': /* Image horizontal resolution (with units) */ 689 { 690 WarnNoImageReturn("\"%%%c\"",letter); 691 (void) FormatLocaleString(value,MagickPathExtent,"%.20g", 692 fabs(image->resolution.x) > MagickEpsilon ? image->resolution.x : 72.0); 693 break; 694 } 695 case 'y': /* Image vertical resolution (with units) */ 696 { 697 WarnNoImageReturn("\"%%%c\"",letter); 698 (void) FormatLocaleString(value,MagickPathExtent,"%.20g", 699 fabs(image->resolution.y) > MagickEpsilon ? image->resolution.y : 72.0); 700 break; 701 } 702 case 'z': /* Image depth as read in */ 703 { 704 WarnNoImageReturn("\"%%%c\"",letter); 705 (void) FormatLocaleString(value,MagickPathExtent,"%.20g", 706 (double) image->depth); 707 break; 708 } 709 case 'A': /* Image alpha channel */ 710 { 711 WarnNoImageReturn("\"%%%c\"",letter); 712 string=CommandOptionToMnemonic(MagickPixelTraitOptions,(ssize_t) 713 image->alpha_trait); 714 break; 715 } 716 case 'C': /* Image compression method. */ 717 { 718 WarnNoImageReturn("\"%%%c\"",letter); 719 string=CommandOptionToMnemonic(MagickCompressOptions, 720 (ssize_t) image->compression); 721 break; 722 } 723 case 'D': /* Image dispose method. */ 724 { 725 WarnNoImageReturn("\"%%%c\"",letter); 726 string=CommandOptionToMnemonic(MagickDisposeOptions, 727 (ssize_t) image->dispose); 728 break; 729 } 730 case 'F': 731 { 732 /* 733 Magick filename - filename given incl. coder & read mods. 734 */ 735 WarnNoImageReturn("\"%%%c\"",letter); 736 (void) CopyMagickString(value,image->magick_filename,MagickPathExtent); 737 break; 738 } 739 case 'G': /* Image size as geometry = "%wx%h" */ 740 { 741 WarnNoImageReturn("\"%%%c\"",letter); 742 (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g", 743 (double) image->magick_columns,(double) image->magick_rows); 744 break; 745 } 746 case 'H': /* layer canvas height */ 747 { 748 WarnNoImageReturn("\"%%%c\"",letter); 749 (void) FormatLocaleString(value,MagickPathExtent,"%.20g", 750 (double) image->page.height); 751 break; 752 } 753 case 'M': /* Magick filename - filename given incl. coder & read mods */ 754 { 755 WarnNoImageReturn("\"%%%c\"",letter); 756 string=image->magick_filename; 757 break; 758 } 759 case 'O': /* layer canvas offset with sign = "+%X+%Y" */ 760 { 761 WarnNoImageReturn("\"%%%c\"",letter); 762 (void) FormatLocaleString(value,MagickPathExtent,"%+ld%+ld",(long) 763 image->page.x,(long) image->page.y); 764 break; 765 } 766 case 'P': /* layer canvas page size = "%Wx%H" */ 767 { 768 WarnNoImageReturn("\"%%%c\"",letter); 769 (void) FormatLocaleString(value,MagickPathExtent,"%.20gx%.20g", 770 (double) image->page.width,(double) image->page.height); 771 break; 772 } 773 case 'Q': /* image compression quality */ 774 { 775 WarnNoImageReturn("\"%%%c\"",letter); 776 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 777 (image->quality == 0 ? 92 : image->quality)); 778 break; 779 } 780 case 'S': /* Number of scenes in image list. */ 781 { 782 WarnNoImageInfoReturn("\"%%%c\"",letter); 783 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 784 (image_info->number_scenes == 0 ? 2147483647 : 785 image_info->number_scenes)); 786 break; 787 } 788 case 'T': /* image time delay for animations */ 789 { 790 WarnNoImageReturn("\"%%%c\"",letter); 791 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 792 image->delay); 793 break; 794 } 795 case 'U': /* Image resolution units. */ 796 { 797 WarnNoImageReturn("\"%%%c\"",letter); 798 string=CommandOptionToMnemonic(MagickResolutionOptions, 799 (ssize_t) image->units); 800 break; 801 } 802 case 'W': /* layer canvas width */ 803 { 804 WarnNoImageReturn("\"%%%c\"",letter); 805 (void) FormatLocaleString(value,MagickPathExtent,"%.20g",(double) 806 image->page.width); 807 break; 808 } 809 case 'X': /* layer canvas X offset */ 810 { 811 WarnNoImageReturn("\"%%%c\"",letter); 812 (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double) 813 image->page.x); 814 break; 815 } 816 case 'Y': /* layer canvas Y offset */ 817 { 818 WarnNoImageReturn("\"%%%c\"",letter); 819 (void) FormatLocaleString(value,MagickPathExtent,"%+.20g",(double) 820 image->page.y); 821 break; 822 } 823 case '%': /* percent escaped */ 824 { 825 string="%"; 826 break; 827 } 828 case '@': /* Trim bounding box, without actually trimming! */ 829 { 830 RectangleInfo 831 page; 832 833 WarnNoImageReturn("\"%%%c\"",letter); 834 page=GetImageBoundingBox(image,exception); 835 (void) FormatLocaleString(value,MagickPathExtent, 836 "%.20gx%.20g%+.20g%+.20g",(double) page.width,(double) page.height, 837 (double) page.x,(double) page.y); 838 break; 839 } 840 case '#': 841 { 842 /* 843 Image signature. 844 */ 845 WarnNoImageReturn("\"%%%c\"",letter); 846 (void) SignatureImage(image,exception); 847 string=GetImageProperty(image,"signature",exception); 848 break; 849 } 850 } 851 return(SanitizeString(string)); 852 } 853 854 static char *InterpretDelegateProperties(ImageInfo *image_info, 855 Image *image,const char *embed_text,ExceptionInfo *exception) 856 { 857 #define ExtendInterpretText(string_length) \ 858 DisableMSCWarning(4127) \ 859 { \ 860 size_t length=(string_length); \ 861 if ((size_t) (q-interpret_text+length+1) >= extent) \ 862 { \ 863 extent+=length; \ 864 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \ 865 MaxTextExtent,sizeof(*interpret_text)); \ 866 if (interpret_text == (char *) NULL) \ 867 return((char *) NULL); \ 868 q=interpret_text+strlen(interpret_text); \ 869 } \ 870 } \ 871 RestoreMSCWarning 872 873 #define AppendKeyValue2Text(key,value)\ 874 DisableMSCWarning(4127) \ 875 { \ 876 size_t length=strlen(key)+strlen(value)+2; \ 877 if ((size_t) (q-interpret_text+length+1) >= extent) \ 878 { \ 879 extent+=length; \ 880 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \ 881 MaxTextExtent,sizeof(*interpret_text)); \ 882 if (interpret_text == (char *) NULL) \ 883 return((char *) NULL); \ 884 q=interpret_text+strlen(interpret_text); \ 885 } \ 886 q+=FormatLocaleString(q,extent,"%s=%s\n",(key),(value)); \ 887 } \ 888 RestoreMSCWarning 889 890 #define AppendString2Text(string) \ 891 DisableMSCWarning(4127) \ 892 { \ 893 size_t length=strlen((string)); \ 894 if ((size_t) (q-interpret_text+length+1) >= extent) \ 895 { \ 896 extent+=length; \ 897 interpret_text=(char *) ResizeQuantumMemory(interpret_text,extent+ \ 898 MaxTextExtent,sizeof(*interpret_text)); \ 899 if (interpret_text == (char *) NULL) \ 900 return((char *) NULL); \ 901 q=interpret_text+strlen(interpret_text); \ 902 } \ 903 (void) CopyMagickString(q,(string),extent); \ 904 q+=length; \ 905 } \ 906 RestoreMSCWarning 907 908 char 909 *interpret_text, 910 *string; 911 912 register char 913 *q; /* current position in interpret_text */ 914 915 register const char 916 *p; /* position in embed_text string being expanded */ 917 918 size_t 919 extent; /* allocated length of interpret_text */ 920 921 MagickBooleanType 922 number; 923 924 assert(image == NULL || image->signature == MagickCoreSignature); 925 assert(image_info == NULL || image_info->signature == MagickCoreSignature); 926 if ((image != (Image *) NULL) && (image->debug != MagickFalse)) 927 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 928 else 929 if ((image_info != (ImageInfo *) NULL) && (image_info->debug != MagickFalse)) 930 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s","no-image"); 931 if (embed_text == (const char *) NULL) 932 return(ConstantString("")); 933 p=embed_text; 934 while ((isspace((int) ((unsigned char) *p)) != 0) && (*p != '\0')) 935 p++; 936 if (*p == '\0') 937 return(ConstantString("")); 938 /* 939 Translate any embedded format characters. 940 */ 941 interpret_text=AcquireString(embed_text); /* new string with extra space */ 942 extent=MagickPathExtent; /* allocated space in string */ 943 number=MagickFalse; /* is last char a number? */ 944 for (q=interpret_text; *p!='\0'; 945 number=isdigit(*p) ? MagickTrue : MagickFalse,p++) 946 { 947 /* 948 Interpret escape characters (e.g. Filename: %M). 949 */ 950 *q='\0'; 951 ExtendInterpretText(MagickPathExtent); 952 switch (*p) 953 { 954 case '\\': 955 { 956 switch (*(p+1)) 957 { 958 case '\0': 959 continue; 960 case 'r': /* convert to RETURN */ 961 { 962 *q++='\r'; 963 p++; 964 continue; 965 } 966 case 'n': /* convert to NEWLINE */ 967 { 968 *q++='\n'; 969 p++; 970 continue; 971 } 972 case '\n': /* EOL removal UNIX,MacOSX */ 973 { 974 p++; 975 continue; 976 } 977 case '\r': /* EOL removal DOS,Windows */ 978 { 979 p++; 980 if (*p == '\n') /* return-newline EOL */ 981 p++; 982 continue; 983 } 984 default: 985 { 986 p++; 987 *q++=(*p); 988 } 989 } 990 continue; 991 } 992 case '&': 993 { 994 if (LocaleNCompare("<",p,4) == 0) 995 { 996 *q++='<'; 997 p+=3; 998 } 999 else 1000 if (LocaleNCompare(">",p,4) == 0) 1001 { 1002 *q++='>'; 1003 p+=3; 1004 } 1005 else 1006 if (LocaleNCompare("&",p,5) == 0) 1007 { 1008 *q++='&'; 1009 p+=4; 1010 } 1011 else 1012 *q++=(*p); 1013 continue; 1014 } 1015 case '%': 1016 break; /* continue to next set of handlers */ 1017 default: 1018 { 1019 *q++=(*p); /* any thing else is 'as normal' */ 1020 continue; 1021 } 1022 } 1023 p++; /* advance beyond the percent */ 1024 /* 1025 Doubled Percent - or percent at end of string. 1026 */ 1027 if ((*p == '\0') || (*p == '\'') || (*p == '"')) 1028 p--; 1029 if (*p == '%') 1030 { 1031 *q++='%'; 1032 continue; 1033 } 1034 /* 1035 Single letter escapes %c. 1036 */ 1037 if (number != MagickFalse) 1038 { 1039 /* 1040 But only if not preceeded by a number! 1041 */ 1042 *q++='%'; /* do NOT substitute the percent */ 1043 p--; /* back up one */ 1044 continue; 1045 } 1046 string=GetMagickPropertyLetter(image_info,image,*p, exception); 1047 if (string != (char *) NULL) 1048 { 1049 AppendString2Text(string); 1050 string=DestroyString(string); 1051 continue; 1052 } 1053 (void) ThrowMagickException(exception,GetMagickModule(),OptionWarning, 1054 "UnknownImageProperty","\"%%%c\"",*p); 1055 } 1056 *q='\0'; 1057 return(interpret_text); 1058 } 1059 1060 MagickExport char *GetDelegateCommand(const ImageInfo *image_info,Image *image, 1061 const char *decode,const char *encode,ExceptionInfo *exception) 1062 { 1063 char 1064 *command, 1065 **commands; 1066 1067 const DelegateInfo 1068 *delegate_info; 1069 1070 register ssize_t 1071 i; 1072 1073 assert(image_info != (ImageInfo *) NULL); 1074 assert(image_info->signature == MagickCoreSignature); 1075 assert(image != (Image *) NULL); 1076 assert(image->signature == MagickCoreSignature); 1077 if (image->debug != MagickFalse) 1078 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1079 1080 delegate_info=GetDelegateInfo(decode,encode,exception); 1081 if (delegate_info == (const DelegateInfo *) NULL) 1082 { 1083 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, 1084 "NoTagFound","`%s'",decode ? decode : encode); 1085 return((char *) NULL); 1086 } 1087 commands=StringToList(delegate_info->commands); 1088 if (commands == (char **) NULL) 1089 { 1090 (void) ThrowMagickException(exception,GetMagickModule(), 1091 ResourceLimitError,"MemoryAllocationFailed","`%s'",decode ? decode : 1092 encode); 1093 return((char *) NULL); 1094 } 1095 command=InterpretDelegateProperties((ImageInfo *) image_info,image, 1096 commands[0],exception); 1097 if (command == (char *) NULL) 1098 (void) ThrowMagickException(exception,GetMagickModule(),ResourceLimitError, 1099 "MemoryAllocationFailed","`%s'",commands[0]); 1100 /* 1101 Relinquish resources. 1102 */ 1103 for (i=0; commands[i] != (char *) NULL; i++) 1104 commands[i]=DestroyString(commands[i]); 1105 commands=(char **) RelinquishMagickMemory(commands); 1106 return(command); 1107 } 1108 1109 /* 1111 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1112 % % 1113 % % 1114 % % 1115 % G e t D e l e g a t e C o m m a n d s % 1116 % % 1117 % % 1118 % % 1119 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1120 % 1121 % GetDelegateCommands() returns the commands associated with a delegate. 1122 % 1123 % The format of the GetDelegateCommands method is: 1124 % 1125 % const char *GetDelegateCommands(const DelegateInfo *delegate_info) 1126 % 1127 % A description of each parameter follows: 1128 % 1129 % o delegate_info: The delegate info. 1130 % 1131 */ 1132 MagickExport const char *GetDelegateCommands(const DelegateInfo *delegate_info) 1133 { 1134 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1135 1136 assert(delegate_info != (DelegateInfo *) NULL); 1137 assert(delegate_info->signature == MagickCoreSignature); 1138 return(delegate_info->commands); 1139 } 1140 1141 /* 1143 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1144 % % 1145 % % 1146 % % 1147 % G e t D e l e g a t e I n f o % 1148 % % 1149 % % 1150 % % 1151 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1152 % 1153 % GetDelegateInfo() returns any delegates associated with the specified tag. 1154 % 1155 % The format of the GetDelegateInfo method is: 1156 % 1157 % const DelegateInfo *GetDelegateInfo(const char *decode, 1158 % const char *encode,ExceptionInfo *exception) 1159 % 1160 % A description of each parameter follows: 1161 % 1162 % o decode: Specifies the decode delegate we are searching for as a 1163 % character string. 1164 % 1165 % o encode: Specifies the encode delegate we are searching for as a 1166 % character string. 1167 % 1168 % o exception: return any errors or warnings in this structure. 1169 % 1170 */ 1171 MagickExport const DelegateInfo *GetDelegateInfo(const char *decode, 1172 const char *encode,ExceptionInfo *exception) 1173 { 1174 register const DelegateInfo 1175 *p; 1176 1177 assert(exception != (ExceptionInfo *) NULL); 1178 if (IsDelegateCacheInstantiated(exception) == MagickFalse) 1179 return((const DelegateInfo *) NULL); 1180 /* 1181 Search for named delegate. 1182 */ 1183 LockSemaphoreInfo(delegate_semaphore); 1184 ResetLinkedListIterator(delegate_cache); 1185 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1186 if ((LocaleCompare(decode,"*") == 0) && (LocaleCompare(encode,"*") == 0)) 1187 { 1188 UnlockSemaphoreInfo(delegate_semaphore); 1189 return(p); 1190 } 1191 while (p != (const DelegateInfo *) NULL) 1192 { 1193 if (p->mode > 0) 1194 { 1195 if (LocaleCompare(p->decode,decode) == 0) 1196 break; 1197 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1198 continue; 1199 } 1200 if (p->mode < 0) 1201 { 1202 if (LocaleCompare(p->encode,encode) == 0) 1203 break; 1204 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1205 continue; 1206 } 1207 if (LocaleCompare(decode,p->decode) == 0) 1208 if (LocaleCompare(encode,p->encode) == 0) 1209 break; 1210 if (LocaleCompare(decode,"*") == 0) 1211 if (LocaleCompare(encode,p->encode) == 0) 1212 break; 1213 if (LocaleCompare(decode,p->decode) == 0) 1214 if (LocaleCompare(encode,"*") == 0) 1215 break; 1216 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1217 } 1218 if (p != (const DelegateInfo *) NULL) 1219 (void) InsertValueInLinkedList(delegate_cache,0, 1220 RemoveElementByValueFromLinkedList(delegate_cache,p)); 1221 UnlockSemaphoreInfo(delegate_semaphore); 1222 return(p); 1223 } 1224 1225 /* 1227 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1228 % % 1229 % % 1230 % % 1231 % G e t D e l e g a t e I n f o L i s t % 1232 % % 1233 % % 1234 % % 1235 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1236 % 1237 % GetDelegateInfoList() returns any delegates that match the specified pattern. 1238 % 1239 % The delegate of the GetDelegateInfoList function is: 1240 % 1241 % const DelegateInfo **GetDelegateInfoList(const char *pattern, 1242 % size_t *number_delegates,ExceptionInfo *exception) 1243 % 1244 % A description of each parameter follows: 1245 % 1246 % o pattern: Specifies a pointer to a text string containing a pattern. 1247 % 1248 % o number_delegates: This integer returns the number of delegates in the 1249 % list. 1250 % 1251 % o exception: return any errors or warnings in this structure. 1252 % 1253 */ 1254 1255 #if defined(__cplusplus) || defined(c_plusplus) 1256 extern "C" { 1257 #endif 1258 1259 static int DelegateInfoCompare(const void *x,const void *y) 1260 { 1261 const DelegateInfo 1262 **p, 1263 **q; 1264 1265 int 1266 cmp; 1267 1268 p=(const DelegateInfo **) x, 1269 q=(const DelegateInfo **) y; 1270 cmp=LocaleCompare((*p)->path,(*q)->path); 1271 if (cmp == 0) 1272 { 1273 if ((*p)->decode == (char *) NULL) 1274 if (((*p)->encode != (char *) NULL) && 1275 ((*q)->encode != (char *) NULL)) 1276 return(strcmp((*p)->encode,(*q)->encode)); 1277 if (((*p)->decode != (char *) NULL) && 1278 ((*q)->decode != (char *) NULL)) 1279 return(strcmp((*p)->decode,(*q)->decode)); 1280 } 1281 return(cmp); 1282 } 1283 1284 #if defined(__cplusplus) || defined(c_plusplus) 1285 } 1286 #endif 1287 1288 MagickExport const DelegateInfo **GetDelegateInfoList(const char *pattern, 1289 size_t *number_delegates,ExceptionInfo *exception) 1290 { 1291 const DelegateInfo 1292 **delegates; 1293 1294 register const DelegateInfo 1295 *p; 1296 1297 register ssize_t 1298 i; 1299 1300 /* 1301 Allocate delegate list. 1302 */ 1303 assert(number_delegates != (size_t *) NULL); 1304 assert(pattern != (char *) NULL); 1305 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); 1306 1307 *number_delegates=0; 1308 p=GetDelegateInfo("*","*",exception); 1309 if (p == (const DelegateInfo *) NULL) 1310 return((const DelegateInfo **) NULL); 1311 delegates=(const DelegateInfo **) AcquireQuantumMemory((size_t) 1312 GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates)); 1313 if (delegates == (const DelegateInfo **) NULL) 1314 return((const DelegateInfo **) NULL); 1315 /* 1316 Generate delegate list. 1317 */ 1318 LockSemaphoreInfo(delegate_semaphore); 1319 ResetLinkedListIterator(delegate_cache); 1320 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1321 for (i=0; p != (const DelegateInfo *) NULL; ) 1322 { 1323 if( (p->stealth == MagickFalse) && 1324 ( GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse || 1325 GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse) ) 1326 delegates[i++]=p; 1327 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1328 } 1329 UnlockSemaphoreInfo(delegate_semaphore); 1330 qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateInfoCompare); 1331 delegates[i]=(DelegateInfo *) NULL; 1332 *number_delegates=(size_t) i; 1333 return(delegates); 1334 } 1335 1336 /* 1338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1339 % % 1340 % % 1341 % % 1342 % G e t D e l e g a t e L i s t % 1343 % % 1344 % % 1345 % % 1346 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1347 % 1348 % GetDelegateList() returns any image format delegates that match the 1349 % specified pattern. 1350 % 1351 % The format of the GetDelegateList function is: 1352 % 1353 % char **GetDelegateList(const char *pattern, 1354 % size_t *number_delegates,ExceptionInfo *exception) 1355 % 1356 % A description of each parameter follows: 1357 % 1358 % o pattern: Specifies a pointer to a text string containing a pattern. 1359 % 1360 % o number_delegates: This integer returns the number of delegates 1361 % in the list. 1362 % 1363 % o exception: return any errors or warnings in this structure. 1364 % 1365 */ 1366 1367 #if defined(__cplusplus) || defined(c_plusplus) 1368 extern "C" { 1369 #endif 1370 1371 static int DelegateCompare(const void *x,const void *y) 1372 { 1373 register const char 1374 **p, 1375 **q; 1376 1377 p=(const char **) x; 1378 q=(const char **) y; 1379 return(LocaleCompare(*p,*q)); 1380 } 1381 1382 #if defined(__cplusplus) || defined(c_plusplus) 1383 } 1384 #endif 1385 1386 MagickExport char **GetDelegateList(const char *pattern, 1387 size_t *number_delegates,ExceptionInfo *exception) 1388 { 1389 char 1390 **delegates; 1391 1392 register const DelegateInfo 1393 *p; 1394 1395 register ssize_t 1396 i; 1397 1398 /* 1399 Allocate delegate list. 1400 */ 1401 assert(pattern != (char *) NULL); 1402 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",pattern); 1403 1404 assert(number_delegates != (size_t *) NULL); 1405 *number_delegates=0; 1406 p=GetDelegateInfo("*","*",exception); 1407 if (p == (const DelegateInfo *) NULL) 1408 return((char **) NULL); 1409 delegates=(char **) AcquireQuantumMemory((size_t) 1410 GetNumberOfElementsInLinkedList(delegate_cache)+1UL,sizeof(*delegates)); 1411 if (delegates == (char **) NULL) 1412 return((char **) NULL); 1413 LockSemaphoreInfo(delegate_semaphore); 1414 ResetLinkedListIterator(delegate_cache); 1415 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1416 for (i=0; p != (const DelegateInfo *) NULL; ) 1417 { 1418 if( (p->stealth == MagickFalse) && 1419 GlobExpression(p->decode,pattern,MagickFalse) != MagickFalse ) 1420 delegates[i++]=ConstantString(p->decode); 1421 if( (p->stealth == MagickFalse) && 1422 GlobExpression(p->encode,pattern,MagickFalse) != MagickFalse ) 1423 delegates[i++]=ConstantString(p->encode); 1424 p=(const DelegateInfo *) GetNextValueInLinkedList(delegate_cache); 1425 } 1426 UnlockSemaphoreInfo(delegate_semaphore); 1427 qsort((void *) delegates,(size_t) i,sizeof(*delegates),DelegateCompare); 1428 delegates[i]=(char *) NULL; 1429 *number_delegates=(size_t) i; 1430 return(delegates); 1431 } 1432 1433 /* 1435 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1436 % % 1437 % % 1438 % % 1439 % G e t D e l e g a t e M o d e % 1440 % % 1441 % % 1442 % % 1443 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1444 % 1445 % GetDelegateMode() returns the mode of the delegate. 1446 % 1447 % The format of the GetDelegateMode method is: 1448 % 1449 % ssize_t GetDelegateMode(const DelegateInfo *delegate_info) 1450 % 1451 % A description of each parameter follows: 1452 % 1453 % o delegate_info: The delegate info. 1454 % 1455 */ 1456 MagickExport ssize_t GetDelegateMode(const DelegateInfo *delegate_info) 1457 { 1458 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1459 1460 assert(delegate_info != (DelegateInfo *) NULL); 1461 assert(delegate_info->signature == MagickCoreSignature); 1462 return(delegate_info->mode); 1463 } 1464 1465 /* 1467 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1468 % % 1469 % % 1470 % % 1471 + G e t D e l e g a t e T h r e a d S u p p o r t % 1472 % % 1473 % % 1474 % % 1475 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1476 % 1477 % GetDelegateThreadSupport() returns MagickTrue if the delegate supports 1478 % threads. 1479 % 1480 % The format of the GetDelegateThreadSupport method is: 1481 % 1482 % MagickBooleanType GetDelegateThreadSupport( 1483 % const DelegateInfo *delegate_info) 1484 % 1485 % A description of each parameter follows: 1486 % 1487 % o delegate_info: The delegate info. 1488 % 1489 */ 1490 MagickExport MagickBooleanType GetDelegateThreadSupport( 1491 const DelegateInfo *delegate_info) 1492 { 1493 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"..."); 1494 1495 assert(delegate_info != (DelegateInfo *) NULL); 1496 assert(delegate_info->signature == MagickCoreSignature); 1497 return(delegate_info->thread_support); 1498 } 1499 1500 /* 1502 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1503 % % 1504 % % 1505 % % 1506 + I s D e l e g a t e C a c h e I n s t a n t i a t e d % 1507 % % 1508 % % 1509 % % 1510 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1511 % 1512 % IsDelegateCacheInstantiated() determines if the delegate cache is 1513 % instantiated. If not, it instantiates the cache and returns it. 1514 % 1515 % The format of the IsDelegateInstantiated method is: 1516 % 1517 % MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception) 1518 % 1519 % A description of each parameter follows. 1520 % 1521 % o exception: return any errors or warnings in this structure. 1522 % 1523 */ 1524 static MagickBooleanType IsDelegateCacheInstantiated(ExceptionInfo *exception) 1525 { 1526 if (delegate_cache == (LinkedListInfo *) NULL) 1527 { 1528 if (delegate_semaphore == (SemaphoreInfo *) NULL) 1529 ActivateSemaphoreInfo(&delegate_semaphore); 1530 LockSemaphoreInfo(delegate_semaphore); 1531 if (delegate_cache == (LinkedListInfo *) NULL) 1532 delegate_cache=AcquireDelegateCache(DelegateFilename,exception); 1533 UnlockSemaphoreInfo(delegate_semaphore); 1534 } 1535 return(delegate_cache != (LinkedListInfo *) NULL ? MagickTrue : MagickFalse); 1536 } 1537 1538 /* 1540 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1541 % % 1542 % % 1543 % % 1544 % I n v o k e D e l e g a t e % 1545 % % 1546 % % 1547 % % 1548 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1549 % 1550 % InvokeDelegate replaces any embedded formatting characters with the 1551 % appropriate image attribute and executes the resulting command. MagickFalse 1552 % is returned if the commands execute with success otherwise MagickTrue. 1553 % 1554 % The format of the InvokeDelegate method is: 1555 % 1556 % MagickBooleanType InvokeDelegate(ImageInfo *image_info,Image *image, 1557 % const char *decode,const char *encode,ExceptionInfo *exception) 1558 % 1559 % A description of each parameter follows: 1560 % 1561 % o image_info: the imageInfo. 1562 % 1563 % o image: the image. 1564 % 1565 % o exception: return any errors or warnings in this structure. 1566 % 1567 */ 1568 1569 static MagickBooleanType CopyDelegateFile(const char *source, 1570 const char *destination,const MagickBooleanType overwrite) 1571 { 1572 int 1573 destination_file, 1574 source_file; 1575 1576 MagickBooleanType 1577 status; 1578 1579 register size_t 1580 i; 1581 1582 size_t 1583 length, 1584 quantum; 1585 1586 ssize_t 1587 count; 1588 1589 struct stat 1590 attributes; 1591 1592 unsigned char 1593 *buffer; 1594 1595 /* 1596 Copy source file to destination. 1597 */ 1598 assert(source != (const char *) NULL); 1599 assert(destination != (char *) NULL); 1600 if (overwrite == MagickFalse) 1601 { 1602 status=GetPathAttributes(destination,&attributes); 1603 if (status != MagickFalse) 1604 return(MagickTrue); 1605 } 1606 destination_file=open_utf8(destination,O_WRONLY | O_BINARY | O_CREAT,S_MODE); 1607 if (destination_file == -1) 1608 return(MagickFalse); 1609 source_file=open_utf8(source,O_RDONLY | O_BINARY,0); 1610 if (source_file == -1) 1611 { 1612 (void) close(destination_file); 1613 return(MagickFalse); 1614 } 1615 quantum=(size_t) MagickMaxBufferExtent; 1616 if ((fstat(source_file,&attributes) == 0) && (attributes.st_size > 0)) 1617 quantum=MagickMin((size_t) attributes.st_size,MagickMaxBufferExtent); 1618 buffer=(unsigned char *) AcquireQuantumMemory(quantum,sizeof(*buffer)); 1619 if (buffer == (unsigned char *) NULL) 1620 { 1621 (void) close(source_file); 1622 (void) close(destination_file); 1623 return(MagickFalse); 1624 } 1625 length=0; 1626 for (i=0; ; i+=count) 1627 { 1628 count=(ssize_t) read(source_file,buffer,quantum); 1629 if (count <= 0) 1630 break; 1631 length=(size_t) count; 1632 count=(ssize_t) write(destination_file,buffer,length); 1633 if ((size_t) count != length) 1634 break; 1635 } 1636 (void) close(destination_file); 1637 (void) close(source_file); 1638 buffer=(unsigned char *) RelinquishMagickMemory(buffer); 1639 return(i != 0 ? MagickTrue : MagickFalse); 1640 } 1641 1642 MagickExport MagickBooleanType InvokeDelegate(ImageInfo *image_info, 1643 Image *image,const char *decode,const char *encode,ExceptionInfo *exception) 1644 { 1645 char 1646 *command, 1647 **commands, 1648 input_filename[MagickPathExtent], 1649 output_filename[MagickPathExtent]; 1650 1651 const DelegateInfo 1652 *delegate_info; 1653 1654 MagickBooleanType 1655 status, 1656 temporary; 1657 1658 PolicyRights 1659 rights; 1660 1661 register ssize_t 1662 i; 1663 1664 /* 1665 Get delegate. 1666 */ 1667 assert(image_info != (ImageInfo *) NULL); 1668 assert(image_info->signature == MagickCoreSignature); 1669 assert(image != (Image *) NULL); 1670 assert(image->signature == MagickCoreSignature); 1671 if (image->debug != MagickFalse) 1672 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"%s",image->filename); 1673 rights=ExecutePolicyRights; 1674 if (IsRightsAuthorized(DelegatePolicyDomain,rights,decode) == MagickFalse) 1675 { 1676 errno=EPERM; 1677 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError, 1678 "NotAuthorized","`%s'",decode); 1679 return(MagickFalse); 1680 } 1681 if (IsRightsAuthorized(DelegatePolicyDomain,rights,encode) == MagickFalse) 1682 { 1683 errno=EPERM; 1684 (void) ThrowMagickException(exception,GetMagickModule(),PolicyError, 1685 "NotAuthorized","`%s'",encode); 1686 return(MagickFalse); 1687 } 1688 temporary=*image->filename == '\0' ? MagickTrue : MagickFalse; 1689 if ((temporary != MagickFalse) && (AcquireUniqueFilename(image->filename) == 1690 MagickFalse)) 1691 { 1692 ThrowFileException(exception,FileOpenError,"UnableToCreateTemporaryFile", 1693 image->filename); 1694 return(MagickFalse); 1695 } 1696 delegate_info=GetDelegateInfo(decode,encode,exception); 1697 if (delegate_info == (DelegateInfo *) NULL) 1698 { 1699 if (temporary != MagickFalse) 1700 (void) RelinquishUniqueFileResource(image->filename); 1701 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, 1702 "NoTagFound","`%s'",decode ? decode : encode); 1703 return(MagickFalse); 1704 } 1705 if (*image_info->filename == '\0') 1706 { 1707 if (AcquireUniqueFilename(image_info->filename) == MagickFalse) 1708 { 1709 if (temporary != MagickFalse) 1710 (void) RelinquishUniqueFileResource(image->filename); 1711 ThrowFileException(exception,FileOpenError, 1712 "UnableToCreateTemporaryFile",image_info->filename); 1713 return(MagickFalse); 1714 } 1715 image_info->temporary=MagickTrue; 1716 } 1717 if ((delegate_info->mode != 0) && (((decode != (const char *) NULL) && 1718 (delegate_info->encode != (char *) NULL)) || 1719 ((encode != (const char *) NULL) && 1720 (delegate_info->decode != (char *) NULL)))) 1721 { 1722 char 1723 *magick; 1724 1725 ImageInfo 1726 *clone_info; 1727 1728 register Image 1729 *p; 1730 1731 /* 1732 Delegate requires a particular image format. 1733 */ 1734 if (AcquireUniqueFilename(image_info->unique) == MagickFalse) 1735 { 1736 ThrowFileException(exception,FileOpenError, 1737 "UnableToCreateTemporaryFile",image_info->unique); 1738 return(MagickFalse); 1739 } 1740 magick=InterpretImageProperties(image_info,image,decode != (char *) NULL ? 1741 delegate_info->encode : delegate_info->decode,exception); 1742 if (magick == (char *) NULL) 1743 { 1744 (void) RelinquishUniqueFileResource(image_info->unique); 1745 if (temporary != MagickFalse) 1746 (void) RelinquishUniqueFileResource(image->filename); 1747 (void) ThrowMagickException(exception,GetMagickModule(), 1748 DelegateError,"DelegateFailed","`%s'",decode ? decode : encode); 1749 return(MagickFalse); 1750 } 1751 LocaleUpper(magick); 1752 clone_info=CloneImageInfo(image_info); 1753 (void) CopyMagickString((char *) clone_info->magick,magick, 1754 MagickPathExtent); 1755 if (LocaleCompare(magick,"NULL") != 0) 1756 (void) CopyMagickString(image->magick,magick,MagickPathExtent); 1757 magick=DestroyString(magick); 1758 (void) FormatLocaleString(clone_info->filename,MagickPathExtent,"%s:", 1759 delegate_info->decode); 1760 (void) SetImageInfo(clone_info,(unsigned int) GetImageListLength(image), 1761 exception); 1762 (void) CopyMagickString(clone_info->filename,image_info->filename, 1763 MagickPathExtent); 1764 (void) CopyMagickString(image_info->filename,image->filename, 1765 MagickPathExtent); 1766 for (p=image; p != (Image *) NULL; p=GetNextImageInList(p)) 1767 { 1768 (void) FormatLocaleString(p->filename,MagickPathExtent,"%s:%s", 1769 delegate_info->decode,clone_info->filename); 1770 status=WriteImage(clone_info,p,exception); 1771 if (status == MagickFalse) 1772 { 1773 (void) RelinquishUniqueFileResource(image_info->unique); 1774 if (temporary != MagickFalse) 1775 (void) RelinquishUniqueFileResource(image->filename); 1776 clone_info=DestroyImageInfo(clone_info); 1777 (void) ThrowMagickException(exception,GetMagickModule(), 1778 DelegateError,"DelegateFailed","`%s'",decode ? decode : encode); 1779 return(MagickFalse); 1780 } 1781 if (clone_info->adjoin != MagickFalse) 1782 break; 1783 } 1784 (void) RelinquishUniqueFileResource(image_info->unique); 1785 clone_info=DestroyImageInfo(clone_info); 1786 } 1787 /* 1788 Invoke delegate. 1789 */ 1790 commands=StringToList(delegate_info->commands); 1791 if (commands == (char **) NULL) 1792 { 1793 if (temporary != MagickFalse) 1794 (void) RelinquishUniqueFileResource(image->filename); 1795 (void) ThrowMagickException(exception,GetMagickModule(), 1796 ResourceLimitError,"MemoryAllocationFailed","`%s'", 1797 decode ? decode : encode); 1798 return(MagickFalse); 1799 } 1800 command=(char *) NULL; 1801 status=MagickTrue; 1802 (void) CopyMagickString(output_filename,image_info->filename, 1803 MagickPathExtent); 1804 (void) CopyMagickString(input_filename,image->filename,MagickPathExtent); 1805 for (i=0; commands[i] != (char *) NULL; i++) 1806 { 1807 (void) AcquireUniqueSymbolicLink(output_filename,image_info->filename); 1808 if (AcquireUniqueFilename(image_info->unique) == MagickFalse) 1809 { 1810 ThrowFileException(exception,FileOpenError, 1811 "UnableToCreateTemporaryFile",image_info->unique); 1812 break; 1813 } 1814 if (LocaleCompare(decode,"SCAN") != 0) 1815 { 1816 status=AcquireUniqueSymbolicLink(input_filename,image->filename); 1817 if (status == MagickFalse) 1818 { 1819 ThrowFileException(exception,FileOpenError, 1820 "UnableToCreateTemporaryFile",input_filename); 1821 break; 1822 } 1823 } 1824 status=MagickTrue; 1825 command=InterpretDelegateProperties(image_info,image,commands[i],exception); 1826 if (command != (char *) NULL) 1827 { 1828 /* 1829 Execute delegate. 1830 */ 1831 if (ExternalDelegateCommand(delegate_info->spawn,image_info->verbose, 1832 command,(char *) NULL,exception) != 0) 1833 status=MagickFalse; 1834 if (delegate_info->spawn != MagickFalse) 1835 { 1836 ssize_t 1837 count; 1838 1839 /* 1840 Wait for input file to 'disappear', or maximum 10 seconds. 1841 */ 1842 count=100; 1843 while ((count-- > 0) && (access_utf8(image->filename,F_OK) == 0)) 1844 (void) MagickDelay(100); /* sleep 0.1 seconds */ 1845 } 1846 command=DestroyString(command); 1847 } 1848 if (LocaleCompare(decode,"SCAN") != 0) 1849 { 1850 if (CopyDelegateFile(image->filename,input_filename,MagickFalse) == MagickFalse) 1851 (void) RelinquishUniqueFileResource(input_filename); 1852 } 1853 if ((strcmp(input_filename,output_filename) != 0) && 1854 (CopyDelegateFile(image_info->filename,output_filename,MagickTrue) == MagickFalse)) 1855 (void) RelinquishUniqueFileResource(output_filename); 1856 if (image_info->temporary != MagickFalse) 1857 (void) RelinquishUniqueFileResource(image_info->filename); 1858 (void) RelinquishUniqueFileResource(image_info->unique); 1859 (void) RelinquishUniqueFileResource(image_info->filename); 1860 (void) RelinquishUniqueFileResource(image->filename); 1861 if (status == MagickFalse) 1862 { 1863 (void) ThrowMagickException(exception,GetMagickModule(),DelegateError, 1864 "DelegateFailed","`%s'",commands[i]); 1865 break; 1866 } 1867 commands[i]=DestroyString(commands[i]); 1868 } 1869 (void) CopyMagickString(image_info->filename,output_filename, 1870 MagickPathExtent); 1871 (void) CopyMagickString(image->filename,input_filename,MagickPathExtent); 1872 /* 1873 Relinquish resources. 1874 */ 1875 for ( ; commands[i] != (char *) NULL; i++) 1876 commands[i]=DestroyString(commands[i]); 1877 commands=(char **) RelinquishMagickMemory(commands); 1878 if (temporary != MagickFalse) 1879 (void) RelinquishUniqueFileResource(image->filename); 1880 return(status); 1881 } 1882 1883 /* 1885 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1886 % % 1887 % % 1888 % % 1889 % L i s t D e l e g a t e I n f o % 1890 % % 1891 % % 1892 % % 1893 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1894 % 1895 % ListDelegateInfo() lists the image formats to a file. 1896 % 1897 % The format of the ListDelegateInfo method is: 1898 % 1899 % MagickBooleanType ListDelegateInfo(FILE *file,ExceptionInfo *exception) 1900 % 1901 % A description of each parameter follows. 1902 % 1903 % o file: An pointer to a FILE. 1904 % 1905 % o exception: return any errors or warnings in this structure. 1906 % 1907 */ 1908 MagickExport MagickBooleanType ListDelegateInfo(FILE *file, 1909 ExceptionInfo *exception) 1910 { 1911 const DelegateInfo 1912 **delegate_info; 1913 1914 char 1915 **commands, 1916 delegate[MagickPathExtent]; 1917 1918 const char 1919 *path; 1920 1921 register ssize_t 1922 i; 1923 1924 size_t 1925 number_delegates; 1926 1927 ssize_t 1928 j; 1929 1930 if (file == (const FILE *) NULL) 1931 file=stdout; 1932 delegate_info=GetDelegateInfoList("*",&number_delegates,exception); 1933 if (delegate_info == (const DelegateInfo **) NULL) 1934 return(MagickFalse); 1935 path=(const char *) NULL; 1936 for (i=0; i < (ssize_t) number_delegates; i++) 1937 { 1938 if (delegate_info[i]->stealth != MagickFalse) 1939 continue; 1940 if ((path == (const char *) NULL) || 1941 (LocaleCompare(path,delegate_info[i]->path) != 0)) 1942 { 1943 if (delegate_info[i]->path != (char *) NULL) 1944 (void) FormatLocaleFile(file,"\nPath: %s\n\n",delegate_info[i]->path); 1945 (void) FormatLocaleFile(file,"Delegate Command\n"); 1946 (void) FormatLocaleFile(file, 1947 "-------------------------------------------------" 1948 "------------------------------\n"); 1949 } 1950 path=delegate_info[i]->path; 1951 *delegate='\0'; 1952 if (delegate_info[i]->encode != (char *) NULL) 1953 (void) CopyMagickString(delegate,delegate_info[i]->encode, 1954 MagickPathExtent); 1955 (void) ConcatenateMagickString(delegate," ",MagickPathExtent); 1956 delegate[8]='\0'; 1957 commands=StringToList(delegate_info[i]->commands); 1958 if (commands == (char **) NULL) 1959 continue; 1960 (void) FormatLocaleFile(file,"%11s%c=%c%s ",delegate_info[i]->decode ? 1961 delegate_info[i]->decode : "",delegate_info[i]->mode <= 0 ? '<' : ' ', 1962 delegate_info[i]->mode >= 0 ? '>' : ' ',delegate); 1963 StripString(commands[0]); 1964 (void) FormatLocaleFile(file,"\"%s\"\n",commands[0]); 1965 for (j=1; commands[j] != (char *) NULL; j++) 1966 { 1967 StripString(commands[j]); 1968 (void) FormatLocaleFile(file," \"%s\"\n",commands[j]); 1969 } 1970 for (j=0; commands[j] != (char *) NULL; j++) 1971 commands[j]=DestroyString(commands[j]); 1972 commands=(char **) RelinquishMagickMemory(commands); 1973 } 1974 (void) fflush(file); 1975 delegate_info=(const DelegateInfo **) 1976 RelinquishMagickMemory((void *) delegate_info); 1977 return(MagickTrue); 1978 } 1979 1980 /* 1982 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1983 % % 1984 % % 1985 % % 1986 + L o a d D e l e g a t e C a c h e % 1987 % % 1988 % % 1989 % % 1990 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 1991 % 1992 % LoadDelegateCache() loads the delegate configurations which provides a 1993 % mapping between delegate attributes and a delegate name. 1994 % 1995 % The format of the LoadDelegateCache method is: 1996 % 1997 % MagickBooleanType LoadDelegateCache(LinkedListInfo *cache, 1998 % const char *xml,const char *filename,const size_t depth, 1999 % ExceptionInfo *exception) 2000 % 2001 % A description of each parameter follows: 2002 % 2003 % o xml: The delegate list in XML format. 2004 % 2005 % o filename: The delegate list filename. 2006 % 2007 % o depth: depth of <include /> statements. 2008 % 2009 % o exception: return any errors or warnings in this structure. 2010 % 2011 */ 2012 static MagickBooleanType LoadDelegateCache(LinkedListInfo *cache, 2013 const char *xml,const char *filename,const size_t depth, 2014 ExceptionInfo *exception) 2015 { 2016 char 2017 keyword[MagickPathExtent], 2018 *token; 2019 2020 const char 2021 *q; 2022 2023 DelegateInfo 2024 *delegate_info; 2025 2026 MagickStatusType 2027 status; 2028 2029 size_t 2030 extent; 2031 2032 /* 2033 Load the delegate map file. 2034 */ 2035 (void) LogMagickEvent(ConfigureEvent,GetMagickModule(), 2036 "Loading delegate configuration file \"%s\" ...",filename); 2037 if (xml == (const char *) NULL) 2038 return(MagickFalse); 2039 status=MagickTrue; 2040 delegate_info=(DelegateInfo *) NULL; 2041 token=AcquireString(xml); 2042 extent=strlen(token)+MagickPathExtent; 2043 for (q=(const char *) xml; *q != '\0'; ) 2044 { 2045 /* 2046 Interpret XML. 2047 */ 2048 GetNextToken(q,&q,extent,token); 2049 if (*token == '\0') 2050 break; 2051 (void) CopyMagickString(keyword,token,MagickPathExtent); 2052 if (LocaleNCompare(keyword,"<!DOCTYPE",9) == 0) 2053 { 2054 /* 2055 Doctype element. 2056 */ 2057 while ((LocaleNCompare(q,"]>",2) != 0) && (*q != '\0')) 2058 GetNextToken(q,&q,extent,token); 2059 continue; 2060 } 2061 if (LocaleNCompare(keyword,"<!--",4) == 0) 2062 { 2063 /* 2064 Comment element. 2065 */ 2066 while ((LocaleNCompare(q,"->",2) != 0) && (*q != '\0')) 2067 GetNextToken(q,&q,extent,token); 2068 continue; 2069 } 2070 if (LocaleCompare(keyword,"<include") == 0) 2071 { 2072 /* 2073 Include element. 2074 */ 2075 while (((*token != '/') && (*(token+1) != '>')) && (*q != '\0')) 2076 { 2077 (void) CopyMagickString(keyword,token,MagickPathExtent); 2078 GetNextToken(q,&q,extent,token); 2079 if (*token != '=') 2080 continue; 2081 GetNextToken(q,&q,extent,token); 2082 if (LocaleCompare(keyword,"file") == 0) 2083 { 2084 if (depth > 200) 2085 (void) ThrowMagickException(exception,GetMagickModule(), 2086 ConfigureError,"IncludeElementNestedTooDeeply","`%s'",token); 2087 else 2088 { 2089 char 2090 path[MagickPathExtent], 2091 *file_xml; 2092 2093 GetPathComponent(filename,HeadPath,path); 2094 if (*path != '\0') 2095 (void) ConcatenateMagickString(path,DirectorySeparator, 2096 MagickPathExtent); 2097 if (*token == *DirectorySeparator) 2098 (void) CopyMagickString(path,token,MagickPathExtent); 2099 else 2100 (void) ConcatenateMagickString(path,token,MagickPathExtent); 2101 file_xml=FileToXML(path,~0UL); 2102 if (file_xml != (char *) NULL) 2103 { 2104 status&=LoadDelegateCache(cache,file_xml,path, 2105 depth+1,exception); 2106 file_xml=DestroyString(file_xml); 2107 } 2108 } 2109 } 2110 } 2111 continue; 2112 } 2113 if (LocaleCompare(keyword,"<delegate") == 0) 2114 { 2115 /* 2116 Delegate element. 2117 */ 2118 delegate_info=(DelegateInfo *) AcquireMagickMemory( 2119 sizeof(*delegate_info)); 2120 if (delegate_info == (DelegateInfo *) NULL) 2121 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed"); 2122 (void) ResetMagickMemory(delegate_info,0,sizeof(*delegate_info)); 2123 delegate_info->path=ConstantString(filename); 2124 delegate_info->thread_support=MagickTrue; 2125 delegate_info->signature=MagickCoreSignature; 2126 continue; 2127 } 2128 if (delegate_info == (DelegateInfo *) NULL) 2129 continue; 2130 if (LocaleCompare(keyword,"/>") == 0) 2131 { 2132 status=AppendValueToLinkedList(cache,delegate_info); 2133 if (status == MagickFalse) 2134 (void) ThrowMagickException(exception,GetMagickModule(), 2135 ResourceLimitError,"MemoryAllocationFailed","`%s'", 2136 delegate_info->commands); 2137 delegate_info=(DelegateInfo *) NULL; 2138 continue; 2139 } 2140 GetNextToken(q,(const char **) NULL,extent,token); 2141 if (*token != '=') 2142 continue; 2143 GetNextToken(q,&q,extent,token); 2144 GetNextToken(q,&q,extent,token); 2145 switch (*keyword) 2146 { 2147 case 'C': 2148 case 'c': 2149 { 2150 if (LocaleCompare((char *) keyword,"command") == 0) 2151 { 2152 char 2153 *commands; 2154 2155 commands=AcquireString(token); 2156 #if defined(MAGICKCORE_WINDOWS_SUPPORT) 2157 if (strchr(commands,'@') != (char *) NULL) 2158 { 2159 char 2160 path[MagickPathExtent]; 2161 2162 NTGhostscriptEXE(path,MagickPathExtent); 2163 (void) SubstituteString((char **) &commands,"@PSDelegate@", 2164 path); 2165 (void) SubstituteString((char **) &commands,"\\","/"); 2166 } 2167 (void) SubstituteString((char **) &commands,""","\""); 2168 #else 2169 (void) SubstituteString((char **) &commands,""","'"); 2170 #endif 2171 (void) SubstituteString((char **) &commands,"&","&"); 2172 (void) SubstituteString((char **) &commands,">",">"); 2173 (void) SubstituteString((char **) &commands,"<","<"); 2174 delegate_info->commands=commands; 2175 break; 2176 } 2177 break; 2178 } 2179 case 'D': 2180 case 'd': 2181 { 2182 if (LocaleCompare((char *) keyword,"decode") == 0) 2183 { 2184 delegate_info->decode=ConstantString(token); 2185 delegate_info->mode=1; 2186 break; 2187 } 2188 break; 2189 } 2190 case 'E': 2191 case 'e': 2192 { 2193 if (LocaleCompare((char *) keyword,"encode") == 0) 2194 { 2195 delegate_info->encode=ConstantString(token); 2196 delegate_info->mode=(-1); 2197 break; 2198 } 2199 break; 2200 } 2201 case 'M': 2202 case 'm': 2203 { 2204 if (LocaleCompare((char *) keyword,"mode") == 0) 2205 { 2206 delegate_info->mode=1; 2207 if (LocaleCompare(token,"bi") == 0) 2208 delegate_info->mode=0; 2209 else 2210 if (LocaleCompare(token,"encode") == 0) 2211 delegate_info->mode=(-1); 2212 break; 2213 } 2214 break; 2215 } 2216 case 'S': 2217 case 's': 2218 { 2219 if (LocaleCompare((char *) keyword,"spawn") == 0) 2220 { 2221 delegate_info->spawn=IsStringTrue(token); 2222 break; 2223 } 2224 if (LocaleCompare((char *) keyword,"stealth") == 0) 2225 { 2226 delegate_info->stealth=IsStringTrue(token); 2227 break; 2228 } 2229 break; 2230 } 2231 case 'T': 2232 case 't': 2233 { 2234 if (LocaleCompare((char *) keyword,"thread-support") == 0) 2235 { 2236 delegate_info->thread_support=IsStringTrue(token); 2237 if (delegate_info->thread_support == MagickFalse) 2238 delegate_info->semaphore=AcquireSemaphoreInfo(); 2239 break; 2240 } 2241 break; 2242 } 2243 default: 2244 break; 2245 } 2246 } 2247 token=(char *) RelinquishMagickMemory(token); 2248 return(status != 0 ? MagickTrue : MagickFalse); 2249 } 2250