MagickCache 1.0.0
MagickCache: an Efficient Image Cache
Loading...
Searching...
No Matches
magick-cache.c
1/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% M M AAA GGGG IIIII CCCC K K %
7% MM MM A A G I C K K %
8% M M M AAAAA G GGG I C KKK %
9% M M A A G G I C K K %
10% M M A A GGGG IIIII CCCC K K %
11% %
12% CCCC AAA CCCC H H EEEEE %
13% C A A C H H E %
14% C AAAAA C HHHHH EEE %
15% C A A C H H E %
16% CCCC A A CCCC H H EEEEE %
17% %
18% MagickCache CRUD Methods %
19% %
20% Software Design %
21% Cristy %
22% March 2021 %
23% %
24% %
25% Copyright 1999 ImageMagick Studio LLC, a non-profit organization %
26% dedicated to making software imaging solutions freely available. %
27% %
28% You may not use this file except in compliance with the License. You may %
29% obtain a copy of the License at %
30% %
31% https://imagemagick.org/script/license.php %
32% %
33% Unless required by applicable law or agreed to in writing, software %
34% distributed under the License is distributed on an "AS IS" BASIS, %
35% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
36% See the License for the specific language governing permissions and %
37% limitations under the License. %
38% %
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40%
41% The MagickCache offers robust techniques and utilities for caching
42% various types of content, including images, image sequences, videos,
43% audio files, and metadata, within a designated local directory. All
44% content is memory-mapped to optimize retrieval efficiency. Furthermore,
45% you can enhance efficiency by selectively retrieving specific portions
46% of an image. Content can either be retained indefinitely or assigned
47% a time-to-live (TTL) to automatically remove it once the TTL duration
48% elapses. MagickCache is capable of accommodating an extensive library of
49% content, scaling to handle billions of images, making it a well-suited
50% choice for use as a web-based image service.
51%
52*/
53
54#include <MagickCore/studio.h>
55#include <MagickCore/MagickCore.h>
56#include "MagickCache/MagickCache.h"
57#include "MagickCache/magick-cache-private.h"
58
59/*
60 MagickCache defines.
61*/
62#define MagickCacheAPIVersion 1
63#define MagickCacheMax(x,y) (((x) > (y)) ? (x) : (y))
64#define MagickCacheMin(x,y) (((x) < (y)) ? (x) : (y))
65#define MagickCacheDigestExtent 64
66#define MagickCacheNonce "MagickCache"
67#define MagickCacheNonceExtent 8
68#define MagickCacheSignature 0xabacadabU
69#define ThrowMagickCacheException(severity,tag,context) \
70{ \
71 (void) ThrowMagickException(cache->exception,GetMagickModule(),severity,tag, \
72 "`%s'",context); \
73 CatchException(cache->exception); \
74}
75
76/*
77 MagickCache structures.
78*/
80{
81 char
82 *path;
83
84 StringInfo
85 *nonce,
86 *passkey;
87
88 char
89 *digest;
90
91 time_t
92 timestamp;
93
94 ExceptionInfo
95 *exception;
96
97 RandomInfo
98 *random_info;
99
100 MagickBooleanType
101 debug;
102
103 size_t
104 signature;
105};
106
108{
109 MagickCacheResourceType
110 resource_type;
111
112 char
113 *iri,
114 *project,
115 *type,
116 *id;
117
118 size_t
119 columns,
120 rows,
121 extent,
122 version;
123
124 StringInfo
125 *nonce;
126
127 time_t
128 timestamp,
129 ttl;
130
131 void
132 *blob;
133
134 MagickBooleanType
135 memory_mapped;
136
137 ExceptionInfo
138 *exception;
139
140 MagickBooleanType
141 debug;
142
143 size_t
144 signature;
145};
146
148{
149 char
150 *path;
151
152 struct ResourceNode
153 *previous,
154 *next;
155};
156
157/*
158%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159% %
160% %
161% %
162% A c q u i r e M a g i c k C a c h e %
163% %
164% %
165% %
166%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167%
168% AcquireMagickCache() creates a MagickCache structure for getting or putting
169% resources, from or to the MagickCache repository. NULL is returned if the
170% MagickCache repo is not found or if the repo is not compatible with the
171% current API version.
172%
173% The format of the AcquireMagickCache method is:
174%
175% MagickCache *AcquireMagickCache(const char *path,
176% const StringInfo *passkey)
177%
178% A description of each parameter follows:
179%
180% o path: the MagickCache path, absolute (e.g. /myrepo) or relative (e.g.
181% ./myrepo).
182%
183% o passkey: the MagickCache passkey.
184%
185*/
186
187static void GetMagickCacheSentinel(MagickCache *cache,unsigned char *sentinel)
188{
189 unsigned char
190 *p;
191
192 unsigned int
193 signature;
194
195 /*
196 Retrieve the MagickCache sentinel.
197 */
198 p=sentinel;
199 p+=sizeof(signature);
200 (void) memcpy(GetStringInfoDatum(cache->nonce),p,
201 GetStringInfoLength(cache->nonce));
202 p+=GetStringInfoLength(cache->nonce);
203 (void) memcpy(cache->digest,p,strlen(cache->digest));
204 p+=strlen(cache->digest);
205}
206
207static inline unsigned int GetMagickCacheSignature(const StringInfo *nonce)
208{
209 StringInfo
210 *version;
211
212 unsigned char
213 *p;
214
215 unsigned int
216 signature;
217
218 /*
219 Generate a MagickCache signature based on the MagickCache properties.
220 */
221 version=AcquireStringInfo(MagickPathExtent);
222 p=GetStringInfoDatum(version);
223 (void) memcpy(p,MagickCachePackageName,strlen(MagickCachePackageName));
224 p+=strlen(MagickCachePackageName);
225 signature=MagickCacheAPIVersion;
226 (void) memcpy(p,&signature,sizeof(signature));
227 p+=sizeof(signature);
228 signature=MagickCacheSignature;
229 (void) memcpy(p,&signature,sizeof(signature));
230 p+=sizeof(signature);
231 SetStringInfoLength(version,(size_t) (p-GetStringInfoDatum(version)));
232 ConcatenateStringInfo(version,nonce);
233 signature=CRC32(GetStringInfoDatum(version),GetStringInfoLength(version));
234 version=DestroyStringInfo(version);
235 return(signature);
236}
237
238MagickExport MagickCache *AcquireMagickCache(const char *path,
239 const StringInfo *passkey)
240{
241 char
242 *sentinel_path;
243
245 *cache;
246
247 size_t
248 extent;
249
250 struct stat
251 attributes;
252
253 unsigned int
254 signature;
255
256 void
257 *sentinel;
258
259 /*
260 Confirm the path exists.
261 */
262 if (path == (const char *) NULL)
263 return((MagickCache *) NULL);
264 if (GetPathAttributes(path,&attributes) <= 0)
265 return((MagickCache *) NULL);
266 /*
267 Basic sanity check passes, allocate & initialize a MagickCache struture.
268 */
269 cache=(MagickCache *) AcquireCriticalMemory(sizeof(*cache));
270 (void) memset(cache,0,sizeof(*cache));
271 cache->path=ConstantString(path);
272 cache->timestamp=(time_t) attributes.st_ctime;
273 cache->random_info=AcquireRandomInfo();
274 cache->nonce=AcquireStringInfo(MagickCacheNonceExtent);
275 if (passkey == (StringInfo *) NULL)
276 cache->passkey=AcquireStringInfo(0);
277 else
278 cache->passkey=CloneStringInfo(passkey);
279 cache->digest=StringInfoToDigest(cache->passkey);
280 cache->exception=AcquireExceptionInfo();
281 cache->debug=IsEventLogging();
282 cache->signature=MagickCacheSignature;
283 /*
284 Validate the MagickCache sentinel.
285 */
286 sentinel_path=AcquireString(path);
287 (void) ConcatenateString(&sentinel_path,"/");
288 (void) ConcatenateString(&sentinel_path,MagickCacheSentinel);
289 sentinel=FileToBlob(sentinel_path,~0UL,&extent,cache->exception);
290 sentinel_path=DestroyString(sentinel_path);
291 if (sentinel == NULL)
292 {
293 cache=DestroyMagickCache(cache);
294 return((MagickCache *) NULL);
295 }
296 GetMagickCacheSentinel(cache,(unsigned char *) sentinel);
297 signature=GetMagickCacheSignature(cache->nonce);
298 if (memcmp(&signature,sentinel,sizeof(signature)) != 0)
299 {
300 sentinel=RelinquishMagickMemory(sentinel);
301 cache=DestroyMagickCache(cache);
302 return((MagickCache *) NULL);
303 }
304 sentinel=RelinquishMagickMemory(sentinel);
305 return(cache);
306}
307
308/*
309%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
310% %
311% %
312% %
313% A c q u i r e M a g i c k C a c h e R e s o u r c e %
314% %
315% %
316% %
317%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318%
319% AcquireMagickCacheResource() allocates the MagickCacheResource structure.
320% It is required before you can get or put metadata associated with resource
321% content.
322%
323% The format of the AcquireMagickCacheResource method is:
324%
325% MagickCacheResource *AcquireMagickCacheResource(MagickCache *cache,
326% const char *iri)
327%
328% A description of each parameter follows:
329%
330% o cache: the cache repository.
331%
332% o iri: the IRI.
333%
334*/
335MagickExport MagickCacheResource *AcquireMagickCacheResource(MagickCache *cache,
336 const char *iri)
337{
339 *resource;
340
341 resource=(MagickCacheResource *) AcquireCriticalMemory(sizeof(*resource));
342 (void) memset(resource,0,sizeof(*resource));
343 resource->nonce=GetRandomKey(cache->random_info,MagickCacheNonceExtent);
344 resource->version=MagickCacheAPIVersion;
345 resource->exception=AcquireExceptionInfo();
346 resource->signature=MagickCacheSignature;
347 (void) SetMagickCacheResourceIRI(cache,resource,iri);
348 return(resource);
349}
350
351/*
352%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353% %
354% %
355% %
356% C l e a r M a g i c k C a c h e E x c e p t i o n %
357% %
358% %
359% %
360%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
361%
362% ClearMagickCacheException() clears any exceptions associated with the cache.
363%
364% The format of the ClearMagickCacheException method is:
365%
366% MagickBooleanType ClearMagickCacheException(MagickCache *cache)
367%
368% A description of each parameter follows:
369%
370% o cache: the cache repository.
371%
372*/
373MagickExport MagickBooleanType ClearMagickCacheException(MagickCache *cache)
374{
375 assert(cache != (MagickCache *) NULL);
376 assert(cache->signature == MagickCacheSignature);
377 if (cache->debug != MagickFalse)
378 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
379 cache->path != (char *) NULL ? cache->path : "");
380 ClearMagickException(cache->exception);
381 return(MagickTrue);
382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386% %
387% %
388% %
389% C l e a r M a g i c k C a c h e R e s o u r c e E x c e p t i o n %
390% %
391% %
392% %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
395% ClearMagickCacheResourceException() clears any exceptions associated with
396% the resource.
397%
398% The format of the ClearMagickCacheResourceException method is:
399%
400% MagickBooleanType ClearMagickCacheResourceException(
401% MagickCacheResource *resource)
402%
403% A description of each parameter follows:
404%
405% o resource: the resource.
406%
407*/
408MagickExport MagickBooleanType ClearMagickCacheResourceException(
409 MagickCacheResource *resource)
410{
411 assert(resource != (MagickCacheResource *) NULL);
412 assert(resource->signature == MagickCacheSignature);
413 if (resource->debug != MagickFalse)
414 (void) LogMagickEvent(CacheEvent,GetMagickModule(),"%s",
415 resource->iri != (char *) NULL ? resource->iri : "");
416 ClearMagickException(resource->exception);
417 return(MagickTrue);
418}
419
420/*
421%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
422% %
423% %
424% %
425% G e t M a g i c k C a c h e R e s o u r c e E x t e n t %
426% %
427% %
428% %
429%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430%
431% GetMagickCacheResourceExtent() returns the resource extent associated with
432% the resource. That is, the number of bytes the resource consumes on disk.
433%
434% The format of the GetMagickCacheResourceExtent method is:
435%
436% size_t GetMagickCacheResourceExtent(const MagickCacheResource *resource)
437%
438% A description of each parameter follows:
439%
440% o resource: the resource.
441%
442*/
443MagickExport size_t GetMagickCacheResourceExtent(
444 const MagickCacheResource *resource)
445{
446 assert(resource != (MagickCacheResource *) NULL);
447 assert(resource->signature == MagickCacheSignature);
448 return(resource->extent);
449}
450
451/*
452%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453% %
454% %
455% %
456% C r e a t e M a g i c k C a c h e %
457% %
458% % % %
459%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460%
461% CreateMagickCache() creates a MagickCache repository suitably prepared for
462% storing and retrieving images, image sequences, video, and metadata
463% resources.
464%
465% The format of the CreateMagickCache method is:
466%
467% MagickBooleanType CreateMagickCache(const char *path,
468% const StringInfo *passkey)
469%
470% A description of each parameter follows:
471%
472% o path: the MagickCache directory path, absolute (e.g. /myrepo) or
473% relative (e.g. ./myrepo).
474%
475% o passkey: the MagickCache passkey.
476*/
477
478static StringInfo *SetMagickCacheSentinel(const char *path,
479 const StringInfo *passkey)
480{
481 char
482 *digest;
483
484 RandomInfo
485 *random_info;
486
487 StringInfo
488 *key_info,
489 *cache_key,
490 *sentinel;
491
492 unsigned char
493 *p;
494
495 unsigned int
496 signature;
497
498 /*
499 Create a MagickCache sentiinel.
500 */
501 sentinel=AcquireStringInfo(MagickPathExtent);
502 random_info=AcquireRandomInfo();
503 key_info=GetRandomKey(random_info,MagickCacheNonceExtent);
504 p=GetStringInfoDatum(sentinel);
505 signature=GetMagickCacheSignature(key_info);
506 (void) memcpy(p,&signature,sizeof(signature));
507 p+=sizeof(signature);
508 (void) memcpy(p,GetStringInfoDatum(key_info),MagickCacheNonceExtent);
509 p+=MagickCacheNonceExtent;
510 cache_key=StringToStringInfo(path);
511 if (passkey != (const StringInfo *) NULL)
512 ConcatenateStringInfo(cache_key,passkey);
513 ConcatenateStringInfo(cache_key,key_info);
514 digest=StringInfoToDigest(cache_key);
515 cache_key=DestroyStringInfo(cache_key);
516 (void) memcpy(p,digest,strlen(digest));
517 p+=strlen(digest);
518 SetStringInfoLength(sentinel,(size_t) (p-GetStringInfoDatum(sentinel)));
519 digest=DestroyString(digest);
520 key_info=DestroyStringInfo(key_info);
521 random_info=DestroyRandomInfo(random_info);
522 return(sentinel);
523}
524
525MagickExport MagickBooleanType CreateMagickCache(const char *path,
526 const StringInfo *passkey)
527{
528 char
529 *sentinel_path;
530
531 ExceptionInfo
532 *exception;
533
534 MagickBooleanType
535 status;
536
537 StringInfo
538 *meta;
539
540 /*
541 Create the MagickCache path.
542 */
543 if (MagickCreatePath(path) == MagickFalse)
544 return(MagickFalse);
545 /*
546 Create the MagickCache sentinel.
547 */
548 sentinel_path=AcquireString(path);
549 (void) ConcatenateString(&sentinel_path,"/");
550 (void) ConcatenateString(&sentinel_path,MagickCacheSentinel);
551 if (IsPathAccessible(sentinel_path) != MagickFalse)
552 {
553 sentinel_path=DestroyString(sentinel_path);
554 errno=EEXIST;
555 return(MagickFalse);
556 }
557 meta=SetMagickCacheSentinel(path,passkey);
558 exception=AcquireExceptionInfo();
559 status=BlobToFile(sentinel_path,GetStringInfoDatum(meta),
560 GetStringInfoLength(meta),exception);
561 exception=DestroyExceptionInfo(exception);
562 meta=DestroyStringInfo(meta);
563 sentinel_path=DestroyString(sentinel_path);
564 return(status);
565}
566
567/*
568%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
569% %
570% %
571% %
572% D e l e t e M a g i c k C a c h e R e s o u r c e %
573% %
574% %
575% %
576%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
577%
578% DeleteMagickCacheResource() deletes a resource within the cache repository.
579%
580% The format of the DeleteMagickCacheResource method is:
581%
582% MagickBooleanType DeleteMagickCacheResource(MagickCache *cache,
583% MagickCacheResource *resource)
584%
585% A description of each parameter follows:
586%
587% o cache: the cache repository.
588%
589% o resource: the MagickCache resource.
590%
591*/
592MagickExport MagickBooleanType DeleteMagickCacheResource(MagickCache *cache,
593 MagickCacheResource *resource)
594{
595 char
596 *iri,
597 *path;
598
599 MagickBooleanType
600 status;
601
602 /*
603 Check that resource id exists in MagickCache.
604 */
605 assert(cache != (MagickCache *) NULL);
606 assert(cache->signature == MagickCacheSignature);
607 assert(resource != (MagickCacheResource *) NULL);
608 assert(resource->signature == MagickCacheSignature);
609 status=GetMagickCacheResource(cache,resource);
610 if (status == MagickFalse)
611 return(MagickFalse);
612 /*
613 Delete resource ID in MagickCache.
614 */
615 path=AcquireString(cache->path);
616 (void) ConcatenateString(&path,"/");
617 (void) ConcatenateString(&path,resource->iri);
618 (void) ConcatenateString(&path,"/");
619 (void) ConcatenateString(&path,resource->id);
620 if (remove_utf8(path) != 0)
621 {
622 path=DestroyString(path);
623 return(MagickFalse);
624 }
625 if (resource->resource_type == ImageResourceType)
626 {
627 /*
628 Delete image cache file.
629 */
630 (void) ConcatenateString(&path,".cache");
631 (void) remove_utf8(path);
632 }
633 path=DestroyString(path);
634 /*
635 Delete resource sentinel in MagickCache.
636 */
637 path=AcquireString(cache->path);
638 (void) ConcatenateString(&path,"/");
639 (void) ConcatenateString(&path,resource->iri);
640 (void) ConcatenateString(&path,"/");
641 (void) ConcatenateString(&path,MagickCacheResourceSentinel);
642 if (remove_utf8(path) != 0)
643 {
644 path=DestroyString(path);
645 return(MagickFalse);
646 }
647 path=DestroyString(path);
648 /*
649 Delete resource IRI in MagickCache.
650 */
651 iri=AcquireString(resource->iri);
652 for ( ; *iri != '\0'; GetPathComponent(iri,HeadPath,iri))
653 {
654 path=AcquireString(cache->path);
655 (void) ConcatenateString(&path,"/");
656 (void) ConcatenateString(&path,iri);
657 (void) remove_utf8(path);
658 path=DestroyString(path);
659 }
660 iri=DestroyString(iri);
661 return(MagickTrue);
662}
663
664/*
665%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
666% %
667% %
668% %
669% D e s t r o y M a g i c k C a c h e %
670% %
671% %
672% %
673%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
674%
675% DestroyMagickCache() deallocates memory associated with a MagickCache.
676%
677% The format of the CloseMagickCache method is:
678%
679% MagickCache *CloseMagickCache(MagickCache *cache)
680%
681% A description of each parameter follows:
682%
683% o cache: the cache repository.
684%
685*/
686MagickExport MagickCache *DestroyMagickCache(MagickCache *cache)
687{
688 assert(cache != (MagickCache *) NULL);
689 assert(cache->signature == MagickCacheSignature);
690 if (cache->path != (char *) NULL )
691 cache->path=DestroyString(cache->path);
692 if (cache->nonce != (StringInfo *) NULL )
693 cache->nonce=DestroyStringInfo(cache->nonce);
694 if (cache->digest != (char *) NULL )
695 cache->digest=DestroyString(cache->digest);
696 if (cache->random_info != (RandomInfo *) NULL)
697 cache->random_info=DestroyRandomInfo(cache->random_info);
698 if (cache->passkey != (StringInfo *) NULL )
699 cache->passkey=DestroyStringInfo(cache->passkey);
700 if (cache->exception != (ExceptionInfo *) NULL)
701 cache->exception=DestroyExceptionInfo(cache->exception);
702 cache->signature=(~MagickCacheSignature);
703 cache=(MagickCache *) RelinquishMagickMemory(cache);
704 return(cache);
705}
706
707/*
708%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
709% %
710% %
711% %
712% D e s t r o y M a g i c k C a c h e R e s o u r c e %
713% %
714% %
715% %
716%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
717%
718% DestroyMagickCacheResource() deallocates memory associated with a resource.
719%
720% The format of the DestroyMagickCacheResource method is:
721%
722% MagickCacheResource *DestroyMagickCacheResource(
723% MagickCacheResource *resource)
724%
725% A description of each parameter follows:
726%
727% o resource: the resource.
728%
729*/
730
731static MagickBooleanType UnmapResourceBlob(void *map,const size_t length)
732{
733#if defined(MAGICKCORE_HAVE_MMAP)
734 int
735 status;
736
737 status=munmap(map,length);
738 return(status == -1 ? MagickFalse : MagickTrue);
739#else
740 (void) map;
741 (void) length;
742 return(MagickFalse);
743#endif
744}
745
746static void DestroyMagickCacheResourceBlob(MagickCacheResource *resource)
747{
748 if (resource->resource_type == ImageResourceType)
749 resource->blob=DestroyImageList((Image *) resource->blob);
750 else
751 if (resource->memory_mapped == MagickFalse)
752 resource->blob=RelinquishMagickMemory(resource->blob);
753 else
754 {
755 (void) UnmapResourceBlob(resource->blob,resource->extent);
756 resource->memory_mapped=MagickFalse;
757 }
758}
759
760MagickExport MagickCacheResource *DestroyMagickCacheResource(
761 MagickCacheResource *resource)
762{
763 /*
764 Deallocate memory associated with a resource.
765 */
766 assert(resource != (MagickCacheResource *) NULL);
767 assert(resource->signature == MagickCoreSignature);
768 if (resource->blob != NULL)
769 DestroyMagickCacheResourceBlob(resource);
770 if (resource->iri != (char *) NULL)
771 resource->iri=DestroyString(resource->iri);
772 if (resource->project != (char *) NULL)
773 resource->project=DestroyString(resource->project);
774 if (resource->type != (char *) NULL)
775 resource->type=DestroyString(resource->type);
776 if (resource->id != (char *) NULL)
777 resource->id=DestroyString(resource->id);
778 if (resource->nonce != (StringInfo *) NULL)
779 resource->nonce=DestroyStringInfo(resource->nonce);
780 if (resource->exception != (ExceptionInfo *) NULL)
781 resource->exception=DestroyExceptionInfo(resource->exception);
782 resource->signature=(~MagickCacheSignature);
783 resource=(MagickCacheResource *) RelinquishMagickMemory(resource);
784 return(resource);
785}
786
787/*
788%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
789% %
790% %
791% %
792% G e t M a g i c k C a c h e E x c e p t i o n %
793% %
794% %
795% %
796%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
797%
798% GetMagickCacheException() returns the severity, reason, and description of
799% any exception that occurs associated with the cache repository.
800%
801% The format of the GetMagickCacheException method is:
802%
803% char *GetMagickCacheException(const MagickCache *cache,
804% ExceptionType *severity)
805%
806% A description of each parameter follows:
807%
808% o cache: the cache repository.
809%
810% o severity: the severity of the error is returned here.
811%
812*/
813MagickExport char *GetMagickCacheException(const MagickCache *cache,
814 ExceptionType *severity)
815{
816 char
817 *description;
818
819 assert(cache != (const MagickCache *) NULL);
820 assert(cache->signature == MagickCacheSignature);
821 if (cache->debug != MagickFalse)
822 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",cache->path);
823 assert(severity != (ExceptionType *) NULL);
824 *severity=cache->exception->severity;
825 description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent,
826 sizeof(*description));
827 if (description == (char *) NULL)
828 {
829 (void) ThrowMagickException(cache->exception,GetMagickModule(),CacheError,
830 "MemoryAllocationFailed","`%s'",cache->path);
831 return((char *) NULL);
832 }
833 *description='\0';
834 if (cache->exception->reason != (char *) NULL)
835 (void) CopyMagickString(description,GetLocaleExceptionMessage(
836 cache->exception->severity,cache->exception->reason),MagickPathExtent);
837 if (cache->exception->description != (char *) NULL)
838 {
839 (void) ConcatenateMagickString(description," (",MagickPathExtent);
840 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
841 cache->exception->severity,cache->exception->description),
842 MagickPathExtent);
843 (void) ConcatenateMagickString(description,")",MagickPathExtent);
844 }
845 return(description);
846}
847
848/*
849%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
850% %
851% %
852% %
853% G e t M a g i c k C a c h e R e s o u r c e %
854% %
855% %
856% %
857%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
858%
859% GetMagickCacheResource() get meta content associated with a resource
860% identified by its IRI. MagickTrue is returned if the resource exists
861% otherwise MagickFalse.
862%
863% The format of the GetMagickCacheResource method is:
864%
865% MagickBooleanType GetMagickCacheResource(MagickCache *cache,
866% MagickCacheResource *resource)
867%
868% A description of each parameter follows:
869%
870% o cache: the cache repository.
871%
872% o resource: the resource.
873%
874*/
875
876static void GetMagickCacheResourceSentinel(MagickCacheResource *resource,
877 unsigned char *sentinel)
878{
879 unsigned char
880 *p;
881
882 unsigned int
883 signature;
884
885 /*
886 Get the MagickCache resource sentinel.
887 */
888 p=sentinel;
889 p+=sizeof(signature);
890 (void) memcpy(GetStringInfoDatum(resource->nonce),p,
891 GetStringInfoLength(resource->nonce));
892 p+=GetStringInfoLength(resource->nonce);
893 (void) memcpy(&resource->ttl,p,sizeof(resource->ttl));
894 p+=sizeof(resource->ttl);
895 (void) memcpy(&resource->columns,p,sizeof(resource->columns));
896 p+=sizeof(resource->columns);
897 (void) memcpy(&resource->rows,p,sizeof(resource->rows));
898 p+=sizeof(resource->rows);
899 if (resource->id != (char *) NULL)
900 resource->id=DestroyString(resource->id);
901 resource->id=StringInfoToDigest(resource->nonce);
902 (void) memcpy(resource->id,p,strlen(resource->id));
903 p+=strlen(resource->id);
904}
905
906static void SetMagickCacheResourceID(MagickCache *cache,
907 MagickCacheResource *resource)
908{
909 char
910 *digest;
911
912 StringInfo
913 *signature;
914
915 /*
916 Set a MagickCache resource ID.
917 */
918 signature=StringToStringInfo(resource->iri);
919 ConcatenateStringInfo(signature,resource->nonce);
920 ConcatenateStringInfo(signature,cache->passkey);
921 ConcatenateStringInfo(signature,cache->nonce);
922 digest=StringInfoToDigest(signature);
923 signature=DestroyStringInfo(signature);
924 if (resource->id != (char *) NULL)
925 resource->id=DestroyString(resource->id);
926 resource->id=digest;
927}
928
929MagickExport MagickBooleanType GetMagickCacheResource(MagickCache *cache,
930 MagickCacheResource *resource)
931{
932 char
933 *digest,
934 *path;
935
936 size_t
937 extent;
938
939 StringInfo
940 *passkey;
941
942 struct stat
943 attributes;
944
945 unsigned int
946 signature;
947
948 void
949 *sentinel;
950
951 /*
952 Validate the MagickCache resource sentinel.
953 */
954 assert(cache != (MagickCache *) NULL);
955 assert(cache->signature == MagickCacheSignature);
956 assert(resource != (MagickCacheResource *) NULL);
957 assert(resource->signature == MagickCacheSignature);
958 path=AcquireString(cache->path);
959 (void) ConcatenateString(&path,"/");
960 (void) ConcatenateString(&path,resource->iri);
961 (void) ConcatenateString(&path,"/");
962 (void) ConcatenateString(&path,MagickCacheResourceSentinel);
963 sentinel=FileToBlob(path,~0UL,&extent,resource->exception);
964 path=DestroyString(path);
965 if (sentinel == NULL)
966 return(MagickFalse);
967 GetMagickCacheResourceSentinel(resource,(unsigned char *) sentinel);
968 signature=GetMagickCacheSignature(resource->nonce);
969 /*
970 If no cache passkey, generate the resource ID.
971 */
972 if (memcmp(&signature,sentinel,sizeof(signature)) != 0)
973 {
974 sentinel=RelinquishMagickMemory(sentinel);
975 (void) ThrowMagickException(resource->exception,GetMagickModule(),
976 CacheError,"resource sentinel signature mismatch","`%s'",path);
977 return(MagickFalse);
978 }
979 sentinel=RelinquishMagickMemory(sentinel);
980 passkey=StringToStringInfo(cache->path);
981 ConcatenateStringInfo(passkey,cache->passkey);
982 ConcatenateStringInfo(passkey,cache->nonce);
983 digest=StringInfoToDigest(passkey);
984 passkey=DestroyStringInfo(passkey);
985 if (strcmp(cache->digest,digest) != 0)
986 SetMagickCacheResourceID(cache,resource);
987 digest=DestroyString(digest);
988 /*
989 Verify resource exists.
990 */
991 path=AcquireString(cache->path);
992 (void) ConcatenateString(&path,"/");
993 (void) ConcatenateString(&path,resource->iri);
994 (void) ConcatenateString(&path,"/");
995 (void) ConcatenateString(&path,resource->id);
996 if (GetPathAttributes(path,&attributes) <= 0)
997 {
998 path=DestroyString(path);
999 (void) ThrowMagickException(resource->exception,GetMagickModule(),
1000 CacheError,"cannot access resource sentinel","`%s'",path);
1001 return(MagickFalse);
1002 }
1003 resource->timestamp=(time_t) attributes.st_ctime;
1004 resource->extent=(size_t) attributes.st_size;
1005 path=DestroyString(path);
1006 return(MagickTrue);
1007}
1008
1009/*
1010%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1011% %
1012% %
1013% %
1014% G e t M a g i c k C a c h e R e s o u r c e B l o b %
1015% %
1016% %
1017% %
1018%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1019%
1020% GetMagickCacheResourceBlob() gets a blob associated with a resource
1021% identified by its IRI.
1022%
1023% The format of the GetMagickCacheResourceBlob method is:
1024%
1025% void *GetMagickCacheResourceBlob(MagickCache *cache,
1026% MagickCacheResource *resource)
1027%
1028% A description of each parameter follows:
1029%
1030% o cache: the cache repository.
1031%
1032% o resource: the resource.
1033%
1034*/
1035
1036static void *MapResourceBlob(int file,const MapMode mode,
1037 const MagickOffsetType offset,const size_t length)
1038{
1039#if defined(MAGICKCORE_HAVE_MMAP)
1040 int
1041 flags,
1042 protection;
1043
1044 void
1045 *map;
1046
1047 /*
1048 Map file.
1049 */
1050 flags=0;
1051 if (file == -1)
1052#if defined(MAP_ANONYMOUS)
1053 flags|=MAP_ANONYMOUS;
1054#else
1055 return(NULL);
1056#endif
1057 switch (mode)
1058 {
1059 case ReadMode:
1060 default:
1061 {
1062 protection=PROT_READ;
1063 flags|=MAP_PRIVATE;
1064 break;
1065 }
1066 case WriteMode:
1067 {
1068 protection=PROT_WRITE;
1069 flags|=MAP_SHARED;
1070 break;
1071 }
1072 case IOMode:
1073 {
1074 protection=PROT_READ | PROT_WRITE;
1075 flags|=MAP_SHARED;
1076 break;
1077 }
1078 }
1079#if !defined(MAGICKCORE_HAVE_HUGEPAGES) || !defined(MAP_HUGETLB)
1080 map=mmap((char *) NULL,length,protection,flags,file,offset);
1081#else
1082 map=mmap((char *) NULL,length,protection,flags | MAP_HUGETLB,file,offset);
1083 if (map == MAP_FAILED)
1084 map=mmap((char *) NULL,length,protection,flags,file,offset);
1085#endif
1086 if (map == MAP_FAILED)
1087 return(NULL);
1088 return(map);
1089#else
1090 (void) file;
1091 (void) mode;
1092 (void) offset;
1093 (void) length;
1094 return(NULL);
1095#endif
1096}
1097
1098static MagickBooleanType ResourceToBlob(MagickCacheResource *resource,
1099 const char *path)
1100{
1101 int
1102 file;
1103
1104 ssize_t
1105 count = 0,
1106 i;
1107
1108 struct stat
1109 attributes;
1110
1111 /*
1112 Convert the resource identified by its IRI to a blob.
1113 */
1114 if (GetPathAttributes(path,&attributes) == MagickFalse)
1115 {
1116 (void) ThrowMagickException(resource->exception,GetMagickModule(),
1117 CacheError,"cannot get resource","`%s'",resource->iri);
1118 return(MagickFalse);
1119 }
1120 resource->extent=(size_t) attributes.st_size;
1121 file=open_utf8(path,O_RDONLY | O_BINARY,0);
1122 if (resource->blob != NULL)
1123 DestroyMagickCacheResourceBlob(resource);
1124 resource->blob=MapResourceBlob(file,ReadMode,0,resource->extent);
1125 if (resource->blob != NULL)
1126 {
1127 resource->memory_mapped=MagickTrue;
1128 file=close(file)-1;
1129 return(MagickTrue);
1130 }
1131 resource->blob=AcquireMagickMemory(resource->extent);
1132 if (resource->blob == NULL)
1133 return(MagickFalse);
1134 for (i=0; i < (ssize_t) resource->extent; i+=count)
1135 {
1136 ssize_t
1137 count;
1138
1139 count=read(file,(unsigned char *) resource->blob+i,(size_t)
1140 MagickCacheMin(resource->extent-(size_t) i,(size_t) SSIZE_MAX));
1141 if (count <= 0)
1142 {
1143 count=0;
1144 if (errno != EINTR)
1145 break;
1146 }
1147 }
1148 if (i < (ssize_t) resource->extent)
1149 {
1150 file=close(file)-1;
1151 resource->blob=RelinquishMagickMemory(resource->blob);
1152 (void) ThrowMagickException(resource->exception,GetMagickModule(),
1153 CacheError,"cannot get resource","`%s'",resource->iri);
1154 return(MagickFalse);
1155 }
1156 if (close(file) == -1)
1157 {
1158 resource->blob=RelinquishMagickMemory(resource->blob);
1159 (void) ThrowMagickException(resource->exception,GetMagickModule(),
1160 CacheError,"cannot get resource","`%s'",resource->iri);
1161 return(MagickFalse);
1162 }
1163 return(MagickTrue);
1164}
1165
1166MagickExport void *GetMagickCacheResourceBlob(MagickCache *cache,
1167 MagickCacheResource *resource)
1168{
1169 char
1170 *path;
1171
1172 MagickBooleanType
1173 status;
1174
1175 /*
1176 Get the blob associated with a resource identified by its IRI.
1177 */
1178 assert(cache != (MagickCache *) NULL);
1179 assert(cache->signature == MagickCacheSignature);
1180 assert(resource != (MagickCacheResource *) NULL);
1181 assert(resource->signature == MagickCacheSignature);
1182 status=GetMagickCacheResource(cache,resource);
1183 if (status == MagickFalse)
1184 return(NULL);
1185 path=AcquireString(cache->path);
1186 (void) ConcatenateString(&path,"/");
1187 (void) ConcatenateString(&path,resource->iri);
1188 (void) ConcatenateString(&path,"/");
1189 (void) ConcatenateString(&path,resource->id);
1190 status=ResourceToBlob(resource,path);
1191 path=DestroyString(path);
1192 if (status == MagickFalse)
1193 return((void *) NULL);
1194 return((void *) resource->blob);
1195}
1196
1197/*
1198%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1199% %
1200% %
1201% %
1202% G e t M a g i c k C a c h e R e s o u r c e E x c e p t i o n %
1203% %
1204% %
1205% %
1206%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1207%
1208% GetMagickCacheResourceException() returns the severity, reason, and
1209% description of any exception that occurs assoicated with a resource.
1210%
1211% The format of the GetMagickCacheException method is:
1212%
1213% char *GetMagickCacheResourceException(
1214% const MagickCacheResource *resource,ExceptionType *severity)
1215%
1216% A description of each parameter follows:
1217%
1218% o resource: the magick resource.
1219%
1220% o severity: the severity of the error is returned here.
1221%
1222*/
1223MagickExport char *GetMagickCacheResourceException(
1224 const MagickCacheResource *resource,ExceptionType *severity)
1225{
1226 char
1227 *description;
1228
1229 /*
1230 Get a MagickCache resource exception.
1231 */
1232 assert(resource != (const MagickCacheResource *) NULL);
1233 assert(resource->signature == MagickCacheSignature);
1234 if (resource->debug != MagickFalse)
1235 (void) LogMagickEvent(WandEvent,GetMagickModule(),"%s",resource->iri);
1236 assert(severity != (ExceptionType *) NULL);
1237 *severity=resource->exception->severity;
1238 description=(char *) AcquireQuantumMemory(2UL*MagickPathExtent,
1239 sizeof(*description));
1240 if (description == (char *) NULL)
1241 {
1242 (void) ThrowMagickException(resource->exception,GetMagickModule(),
1243 CacheError,"MemoryAllocationFailed","`%s'",resource->iri);
1244 return((char *) NULL);
1245 }
1246 *description='\0';
1247 if (resource->exception->reason != (char *) NULL)
1248 (void) CopyMagickString(description,GetLocaleExceptionMessage(
1249 resource->exception->severity,resource->exception->reason),
1250 MagickPathExtent);
1251 if (resource->exception->description != (char *) NULL)
1252 {
1253 (void) ConcatenateMagickString(description," (",MagickPathExtent);
1254 (void) ConcatenateMagickString(description,GetLocaleExceptionMessage(
1255 resource->exception->severity,resource->exception->description),
1256 MagickPathExtent);
1257 (void) ConcatenateMagickString(description,")",MagickPathExtent);
1258 }
1259 return(description);
1260}
1261
1262/*
1263%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1264% %
1265% %
1266% %
1267% G e t M a g i c k C a c h e R e s o u r c e I D %
1268% %
1269% %
1270% %
1271%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1272%
1273% GetMagickCacheResourceID() returns a unique resource ID in the ID parameter.
1274%
1275% The format of the GetMagickCacheResourceID method is:
1276%
1277% MagickBooleanType GetMagickCacheResourceID(MagickCache *cache,
1278% const size_t length,char *id)
1279%
1280% A description of each parameter follows:
1281%
1282% o cache: the cache repository.
1283%
1284% o length: the length of the ID.
1285%
1286% o id: a buffer that is at least `length` bytes long.
1287%
1288*/
1289MagickExport MagickBooleanType GetMagickCacheResourceID(MagickCache *cache,
1290 const size_t length,char *id)
1291{
1292 ssize_t
1293 i,
1294 j;
1295
1296 StringInfo
1297 *passkey;
1298
1299 unsigned char
1300 *code;
1301
1302 /*
1303 Get the MagickCache resource ID.
1304 */
1305 assert(cache != (const MagickCache *) NULL);
1306 assert(cache->signature == MagickCacheSignature);
1307 for (j=0; j < (ssize_t) length; j++)
1308 {
1309 passkey=GetRandomKey(cache->random_info,length);
1310 if (passkey == (StringInfo *) NULL)
1311 return(MagickFalse);
1312 code=GetStringInfoDatum(passkey);
1313 for (i=0; i < (ssize_t) length; i++)
1314 {
1315 if ((code[i] <= 32) || ((code[i] <= 0x9f && code[i] > 0x7F)))
1316 continue;
1317 id[j++]=(char) code[i];
1318 if (j == (ssize_t) length)
1319 break;
1320 }
1321 passkey=DestroyStringInfo(passkey);
1322 }
1323 return(MagickTrue);
1324}
1325
1326/*
1327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1328% %
1329% %
1330% %
1331% G e t M a g i c k C a c h e R e s o u r c e I m a g e %
1332% %
1333% %
1334% %
1335%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1336%
1337% GetMagickCacheResourceImage() gets an image associated with a resource
1338% identified by its IRI from the cache repository. To retrieve the entire
1339% image, set the extract parameter to NULL. Otherwise specify the size and
1340% offset of a portion of the image, e.g. 100x100+0+1. If you do not specify
1341% the offset, the image is instead resized, e.g. 100x100 returns the image
1342% resized while still retaining the original aspect ratio.
1343%
1344% The format of the GetMagickCacheResourceImage method is:
1345%
1346% Image *GetMagickCacheResourceImage(MagickCache *cache,
1347% MagickCacheResource *resource,const char *extract)
1348%
1349% A description of each parameter follows:
1350%
1351% o cache: the cache repository.
1352%
1353% o resource: the resource.
1354%
1355% o extract: the extract geometry.
1356%
1357*/
1358MagickExport Image *GetMagickCacheResourceImage(MagickCache *cache,
1359 MagickCacheResource *resource,const char *extract)
1360{
1361 char
1362 *path;
1363
1364 ExceptionInfo
1365 *exception;
1366
1367 ImageInfo
1368 *image_info;
1369
1370 MagickBooleanType
1371 status;
1372
1373 /*
1374 Return the resource identified by its IRI as an image.
1375 */
1376 assert(cache != (MagickCache *) NULL);
1377 assert(cache->signature == MagickCacheSignature);
1378 assert(resource != (MagickCacheResource *) NULL);
1379 assert(resource->signature == MagickCacheSignature);
1380 status=GetMagickCacheResource(cache,resource);
1381 if (status == MagickFalse)
1382 return((Image *) NULL);
1383 path=AcquireString(cache->path);
1384 (void) ConcatenateString(&path,"/");
1385 (void) ConcatenateString(&path,resource->iri);
1386 (void) ConcatenateString(&path,"/");
1387 (void) ConcatenateString(&path,resource->id);
1388 if (extract != (const char *) NULL)
1389 {
1390 (void) ConcatenateString(&path,"[");
1391 (void) ConcatenateString(&path,extract);
1392 (void) ConcatenateString(&path,"]");
1393 }
1394 if (strlen(path) > (MagickPathExtent-2))
1395 {
1396 path=DestroyString(path);
1397 errno=ENAMETOOLONG;
1398 return((Image *) NULL);
1399 }
1400 image_info=AcquireImageInfo();
1401 (void) CopyMagickString(image_info->filename,path,MagickPathExtent);
1402 (void) CopyMagickString(image_info->magick,"MPC",MagickPathExtent);
1403 exception=AcquireExceptionInfo();
1404 if (resource->blob != NULL)
1405 DestroyMagickCacheResourceBlob(resource);
1406 resource->blob=(void *) ReadImage(image_info,exception);
1407 exception=DestroyExceptionInfo(exception);
1408 if (resource->blob == (void *) NULL)
1409 (void) ThrowMagickException(resource->exception,GetMagickModule(),
1410 CacheError,"cannot get resource","`%s'",resource->iri);
1411 else
1412 {
1413 const Image *image = (const Image *) resource->blob;
1414 resource->columns=image->columns;
1415 resource->rows=image->rows;
1416 }
1417 path=DestroyString(path);
1418 image_info=DestroyImageInfo(image_info);
1419 return((Image *) resource->blob);
1420}
1421
1422/*
1423%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424% %
1425% %
1426% %
1427% G e t M a g i c k C a c h e R e s o u r c e I R I %
1428% %
1429% %
1430% %
1431%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1432%
1433% GetMagickCacheResourceIRI() gets a resource identified by its IRI in the
1434% cache repository.
1435%
1436% The format of the GetMagickCacheResourceIRI method is:
1437%
1438% char *GetMagickCacheResourceIRI(MagickCacheResource *resource)
1439%
1440% A description of each parameter follows:
1441%
1442% o resource: the resource.
1443%
1444*/
1445MagickExport char *GetMagickCacheResourceIRI(
1446 const MagickCacheResource *resource)
1447{
1448 assert(resource != (MagickCacheResource *) NULL);
1449 assert(resource->signature == MagickCacheSignature);
1450 return(resource->iri);
1451}
1452
1453/*
1454%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1455% %
1456% %
1457% %
1458% G e t M a g i c k C a c h e R e s o u r c e M e t a %
1459% %
1460% %
1461% %
1462%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1463%
1464% GetMagickCacheResourceMeta() gets any metadata associated with the resource
1465% in the cache repository..
1466%
1467% The format of the GetMagickCacheResourceMeta method is:
1468%
1469% char *GetMagickCacheResourceMeta(MagickCacheResource *resource)
1470%
1471% A description of each parameter follows:
1472%
1473% o cache: the cache repository.
1474%
1475% o resource: the resource.
1476%
1477*/
1478MagickExport char *GetMagickCacheResourceMeta(MagickCache *cache,
1479 MagickCacheResource *resource)
1480{
1481 char
1482 *path;
1483
1484 MagickBooleanType
1485 status;
1486
1487 /*
1488 Return the resource identified by its IRI as metadata.
1489 */
1490 assert(cache != (MagickCache *) NULL);
1491 assert(cache->signature == MagickCacheSignature);
1492 assert(resource != (MagickCacheResource *) NULL);
1493 assert(resource->signature == MagickCacheSignature);
1494 status=GetMagickCacheResource(cache,resource);
1495 if (status == MagickFalse)
1496 return((char *) NULL);
1497 path=AcquireString(cache->path);
1498 (void) ConcatenateString(&path,"/");
1499 (void) ConcatenateString(&path,resource->iri);
1500 (void) ConcatenateString(&path,"/");
1501 (void) ConcatenateString(&path,resource->id);
1502 if (strlen(path) > (MagickPathExtent-2))
1503 {
1504 path=DestroyString(path);
1505 errno=ENAMETOOLONG;
1506 return((char *) NULL);
1507 }
1508 status=ResourceToBlob(resource,path);
1509 path=DestroyString(path);
1510 if (status == MagickFalse)
1511 return((char *) NULL);
1512 return((char *) resource->blob);
1513}
1514
1515/*
1516%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1517% %
1518% %
1519% %
1520% G e t M a g i c k C a c h e R e s o u r c e S i z e %
1521% %
1522% %
1523% %
1524%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1525%
1526% GetMagickCacheResourceSize() returns the size of the image associated with
1527% the resource in the cache repository.
1528%
1529% The format of the GetMagickCacheResourceSize method is:
1530%
1531% void GetMagickCacheResourceSize(
1532% const MagickCacheResource *resource,size_t *columns,size_t *rows)
1533%
1534% A description of each parameter follows:
1535%
1536% o resource: the resource.
1537%
1538*/
1539MagickExport void GetMagickCacheResourceSize(
1540 const MagickCacheResource *resource,size_t *columns,size_t *rows)
1541{
1542 assert(resource != (MagickCacheResource *) NULL);
1543 assert(resource->signature == MagickCacheSignature);
1544 *columns=resource->columns;
1545 *rows=resource->rows;
1546}
1547
1548/*
1549%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1550% %
1551% %
1552% %
1553% G e t M a g i c k C a c h e R e s o u r c e T i m e s t a m p %
1554% %
1555% %
1556% %
1557%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1558%
1559% GetMagickCacheResourceTimestamp() returns the timestamp associated with a
1560% resource in the cache repository.
1561%
1562% The format of the GetMagickCacheResourceTimestamp method is:
1563%
1564% time_t GetMagickCacheResourceTimestamp(
1565% const MagickCacheResource *resource)
1566%
1567% A description of each parameter follows:
1568%
1569% o resource: the resource.
1570%
1571*/
1572MagickExport time_t GetMagickCacheResourceTimestamp(
1573 const MagickCacheResource *resource)
1574{
1575 assert(resource != (MagickCacheResource *) NULL);
1576 assert(resource->signature == MagickCacheSignature);
1577 return(resource->timestamp);
1578}
1579
1580/*
1581%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1582% %
1583% %
1584% %
1585% G e t M a g i c k C a c h e R e s o u r c e T T L %
1586% %
1587% %
1588% %
1589%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1590%
1591% GetMagickCacheResourceTTL() returns the time-to-live associated with a
1592% resource in the cache repository.
1593%
1594% The format of the GetMagickCacheResourceTTL method is:
1595%
1596% time_t GetMagickCacheResourceTTL(const MagickCacheResource *resource)
1597%
1598% A description of each parameter follows:
1599%
1600% o resource: the resource.
1601%
1602*/
1603MagickExport time_t GetMagickCacheResourceTTL(
1604 const MagickCacheResource *resource)
1605{
1606 assert(resource != (MagickCacheResource *) NULL);
1607 assert(resource->signature == MagickCacheSignature);
1608 return(resource->ttl);
1609}
1610
1611/*
1612%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1613% %
1614% %
1615% %
1616% G e t M a g i c k C a c h e R e s o u r c e T y p e %
1617% %
1618% %
1619% %
1620%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1621%
1622% GetMagickCacheResourceType() returns the type associated with a resource in
1623% the cache respository.
1624%
1625% The format of the GetMagickCacheResourceType method is:
1626%
1627% MagickCacheResourceType GetMagickCacheResourceType(
1628% const MagickCacheResource *resource)
1629%
1630% A description of each parameter follows:
1631%
1632% o resource: the resource.
1633%
1634*/
1635MagickExport MagickCacheResourceType GetMagickCacheResourceType(
1636 const MagickCacheResource *resource)
1637{
1638 assert(resource != (MagickCacheResource *) NULL);
1639 assert(resource->signature == MagickCacheSignature);
1640 return(resource->resource_type);
1641}
1642
1643/*
1644%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1645% %
1646% %
1647% %
1648% G e t M a g i c k C a c h e R e s o u r c e V e r s i o n %
1649% %
1650% %
1651% %
1652%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1653%
1654% GetMagickCacheResourceVersion() returns the version associated with a
1655% resource in the cache repository.
1656%
1657% The format of the GetMagickCacheResourceVersion method is:
1658%
1659% size_t GetMagickCacheResourceVersion(
1660% const MagickCacheResource *resource)
1661%
1662% A description of each parameter follows:
1663%
1664% o resource: the resource.
1665%
1666*/
1667MagickExport size_t GetMagickCacheResourceVersion(
1668 const MagickCacheResource *resource)
1669{
1670 assert(resource != (MagickCacheResource *) NULL);
1671 assert(resource->signature == MagickCacheSignature);
1672 return(resource->version);
1673}
1674
1675/*
1676%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677% %
1678% %
1679% %
1680% G e t M a g i c k C a c h e T i m e s t a m p %
1681% %
1682% %
1683% %
1684%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1685%
1686% GetMagickCacheTimestamp() returns the timestamp associated with the cache
1687% repository.
1688%
1689% The format of the GetMagickCacheResource method is:
1690%
1691% time_t GetMagickCacheResourceTimestamp(const MagickCache *cache)
1692%
1693% A description of each parameter follows:
1694%
1695% o resource: the resource.
1696%
1697*/
1698MagickExport time_t GetMagickCacheTimestamp(const MagickCache *cache)
1699{
1700 assert(cache != (MagickCache *) NULL);
1701 assert(cache->signature == MagickCacheSignature);
1702 return(cache->timestamp);
1703}
1704
1705/*
1706%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1707% %
1708% %
1709% %
1710% I d e n t i f y M a g i c k C a c h e R e s o u r c e %
1711% %
1712% %
1713% %
1714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715%
1716% IdentifyMagickCacheResource() identifies a resource within the cache
1717% repository.
1718%
1719% The format of the IdentifyMagickCacheResource method is:
1720%
1721% MagickBooleanType IdentifyMagickCacheResource(MagickCache *cache,
1722% MagickCacheResource *resource,FILE *file)
1723%
1724% A description of each parameter follows:
1725%
1726% o cache: the cache repository.
1727%
1728% o iri: the IRI.
1729%
1730% o file: the file.
1731%
1732*/
1733MagickExport MagickBooleanType IdentifyMagickCacheResource(MagickCache *cache,
1734 MagickCacheResource *resource,FILE *file)
1735{
1736 char
1737 extent[MagickPathExtent],
1738 iso8601[sizeof("9999-99-99T99:99:99Z")],
1739 *path,
1740 size[MagickPathExtent];
1741
1742 int
1743 expired;
1744
1745 MagickBooleanType
1746 status;
1747
1748 struct tm
1749 timestamp;
1750
1751 /*
1752 If the resource ID exists, identify it.
1753 */
1754 assert(cache != (MagickCache *) NULL);
1755 assert(cache->signature == MagickCacheSignature);
1756 path=AcquireString(cache->path);
1757 (void) ConcatenateString(&path,"/");
1758 (void) ConcatenateString(&path,resource->iri);
1759 (void) ConcatenateString(&path,"/");
1760 (void) ConcatenateString(&path,resource->id);
1761 status=GetMagickCacheResource(cache,resource);
1762 *size='\0';
1763 if (resource->resource_type == ImageResourceType)
1764 (void) snprintf(size,MagickPathExtent,"[%gx%g]",(double) resource->columns,
1765 (double) resource->rows);
1766 (void) FormatMagickSize(GetMagickCacheResourceExtent(resource),MagickTrue,
1767 "B",MagickPathExtent,extent);
1768 (void) GetMagickUTCTime(&resource->timestamp,&timestamp);
1769 (void) strftime(iso8601,sizeof(iso8601),"%FT%TZ",&timestamp);
1770 expired=' ';
1771 if ((resource->ttl != 0) && ((resource->timestamp+resource->ttl) < time(0)))
1772 expired='*';
1773 (void) fprintf(file,"%s%s %s %g:%g:%g:%g%c %s\n",GetMagickCacheResourceIRI(
1774 resource),size,extent,(double) (resource->ttl/(3600*24)),(double)
1775 ((resource->ttl % (24*3600))/3600),(double) ((resource->ttl % 3600)/60),
1776 (double) ((resource->ttl % 3600) % 60),expired,iso8601);
1777 path=DestroyString(path);
1778 return(status);
1779}
1780
1781/*
1782%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1783% %
1784% %
1785% %
1786% I s M a g i c k C a c h e R e s o u r c e E x p i r e d %
1787% %
1788% %
1789% %
1790%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1791%
1792% IsMagickCacheResourceExpired() returns MagickTrue if the resource creation
1793% date plus the time to live is greater than or equal to the current time.
1794% Note, a resource with a time to live of zero, never expires.
1795%
1796% The format of the IsMagickCacheResourceExpired method is:
1797%
1798% MagickBooleanType IsMagickCacheResourceExpired(MagickCache *cache,
1799% MagickCacheResource *resource)
1800%
1801% A description of each parameter follows:
1802%
1803% o cache: the cache repository.
1804%
1805% o iri: the IRI.
1806%
1807*/
1808MagickExport MagickBooleanType IsMagickCacheResourceExpired(MagickCache *cache,
1809 MagickCacheResource *resource)
1810{
1811 MagickBooleanType
1812 status;
1813
1814 assert(cache != (MagickCache *) NULL);
1815 assert(cache->signature == MagickCacheSignature);
1816 status=GetMagickCacheResource(cache,resource);
1817 if (status == MagickFalse)
1818 return(status);
1819 if ((resource->ttl != 0) && ((resource->timestamp+resource->ttl) < time(0)))
1820 {
1821#if defined(ESTALE)
1822 errno=ESTALE;
1823#endif
1824 return(MagickTrue);
1825 }
1826 return(MagickFalse);
1827}
1828
1829/*
1830%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1831% %
1832% %
1833% %
1834% I t e r a t e M a g i c k C a c h e R e s o u r c e s %
1835% %
1836% %
1837% %
1838%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1839%
1840% IterateMagickCacheResources() iterates over all the resources in the
1841% MagickCache and calls the callback() method once for each resource
1842% discovered with three arguments: the MagickCache, the current resource, and
1843% a user context. Use the resource `get` methods to retrieve any associated
1844% metadata such as the IRI or time-to-live. To terminate the iteration, have
1845% callback() return MagickFalse.
1846%
1847% The format of the IterateMagickCacheResources method is:
1848%
1849% MagickBooleanType IterateMagickCacheResources(MagickCache *cache,
1850% const char *iri,MagickBooleanType (*callback)(MagickCache *cache,
1851% MagickCacheResource *resource,const void *context))
1852%
1853% A description of each parameter follows:
1854%
1855% o cache: the cache repository.
1856%
1857% o iri: the IRI.
1858%
1859*/
1860MagickExport MagickBooleanType IterateMagickCacheResources(MagickCache *cache,
1861 const char *iri,const void *context,MagickBooleanType (*callback)(
1862 MagickCache *cache,MagickCacheResource *resource,const void *context))
1863{
1864 char
1865 *path;
1866
1867 DIR
1868 *directory;
1869
1870 MagickBooleanType
1871 status;
1872
1873 struct dirent
1874 *entry;
1875
1876 struct ResourceNode
1877 *head,
1878 *node,
1879 *p,
1880 *q;
1881
1882 struct stat
1883 attributes;
1884
1885 /*
1886 Check that resource id exists in MagickCache.
1887 */
1888 assert(cache != (MagickCache *) NULL);
1889 assert(cache->signature == MagickCacheSignature);
1890 status=MagickTrue;
1891 head=(struct ResourceNode *) AcquireCriticalMemory(sizeof(*node));
1892 (void) memset(head,0,sizeof(*head));
1893 head->path=AcquireString(cache->path);
1894 (void) ConcatenateString(&head->path,"/");
1895 (void) ConcatenateString(&head->path,iri);
1896 head->next=(struct ResourceNode *) NULL;
1897 head->previous=(struct ResourceNode *) NULL;
1898 q=head;
1899 for (p=head; p != (struct ResourceNode *) NULL; p=p->next)
1900 {
1901 directory=opendir(p->path);
1902 if (directory == (DIR *) NULL)
1903 {
1904 status=MagickFalse;
1905 break;
1906 }
1907 while ((entry=readdir(directory)) != (struct dirent *) NULL)
1908 {
1909 path=AcquireString(p->path);
1910 (void) ConcatenateString(&path,"/");
1911 (void) ConcatenateString(&path,entry->d_name);
1912 if (GetPathAttributes(path,&attributes) <= 0)
1913 {
1914 path=DestroyString(path);
1915 break;
1916 }
1917 if ((strcmp(entry->d_name, ".") == 0) ||
1918 (strcmp(entry->d_name, "..") == 0))
1919 {
1920 path=DestroyString(path);
1921 continue;
1922 }
1923 if (S_ISDIR(attributes.st_mode) != 0)
1924 {
1925 node=(struct ResourceNode *) AcquireCriticalMemory(sizeof(*node));
1926 (void) memset(node,0,sizeof(*node));
1927 node->path=path;
1928 node->next=(struct ResourceNode *) NULL;
1929 node->previous=q;
1930 q->next=node;
1931 q=q->next;
1932 }
1933 else
1934 if (S_ISREG(attributes.st_mode) != 0)
1935 {
1936 char *sentinel = ConstantString(path);
1937 GetPathComponent(path,TailPath,sentinel);
1938 if (strcmp(sentinel,MagickCacheResourceSentinel) == 0)
1939 {
1941 *resource;
1942
1943 GetPathComponent(path,HeadPath,path);
1944 resource=AcquireMagickCacheResource(cache,path+
1945 strlen(cache->path)+1);
1946 status=GetMagickCacheResource(cache,resource);
1947 if (status != MagickFalse)
1948 {
1949 status=callback(cache,resource,context);
1950 if (status == MagickFalse)
1951 {
1952 path=DestroyString(path);
1953 resource=DestroyMagickCacheResource(resource);
1954 sentinel=DestroyString(sentinel);
1955 break;
1956 }
1957 }
1958 resource=DestroyMagickCacheResource(resource);
1959 }
1960 path=DestroyString(path);
1961 sentinel=DestroyString(sentinel);
1962 }
1963 }
1964 (void) closedir(directory);
1965 }
1966 /*
1967 Free resources.
1968 */
1969 for ( ; q != (struct ResourceNode *) NULL; )
1970 {
1971 node=q;
1972 q=q->previous;
1973 node->path=DestroyString(node->path);
1974 node=(struct ResourceNode *) RelinquishMagickMemory(node);
1975 }
1976 return(status);
1977}
1978
1979/*
1980%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1981% %
1982% %
1983% %
1984% P u t M a g i c k C a c h e R e s o u r c e %
1985% %
1986% %
1987% %
1988%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1989%
1990% PutMagickCacheResource() puts an image, image sequence, video, or metadata
1991% resource in the MagickCache identified by its IRI. If the IRI already
1992% exists, an exception is returned.
1993%
1994% The format of the PutMagickCacheResource method is:
1995%
1996% MagickBooleanType PutMagickCacheResource(MagickCache *cache,
1997% const MagickCacheResource *resource)
1998%
1999% A description of each parameter follows:
2000%
2001% o cache: the cache repository.
2002%
2003% o resource: the resource.
2004%
2005% o blob: the blob.
2006%
2007*/
2008
2009static StringInfo *SetMagickCacheResourceSentinel(
2010 const MagickCacheResource *resource)
2011{
2012 StringInfo
2013 *meta;
2014
2015 unsigned char
2016 *p;
2017
2018 unsigned int
2019 signature;
2020
2021 /*
2022 Set the MagickCache resource sentinel.
2023 */
2024 meta=AcquireStringInfo(MagickPathExtent);
2025 p=GetStringInfoDatum(meta);
2026 signature=GetMagickCacheSignature(resource->nonce);
2027 (void) memcpy(p,&signature,sizeof(signature));
2028 p+=sizeof(signature);
2029 (void) memcpy(p,GetStringInfoDatum(resource->nonce),
2030 GetStringInfoLength(resource->nonce));
2031 p+=GetStringInfoLength(resource->nonce);
2032 (void) memcpy(p,&resource->ttl,sizeof(resource->ttl));
2033 p+=sizeof(resource->ttl);
2034 (void) memcpy(p,&resource->columns,sizeof(resource->columns));
2035 p+=sizeof(resource->columns);
2036 (void) memcpy(p,&resource->rows,sizeof(resource->rows));
2037 p+=sizeof(resource->rows);
2038 (void) memcpy(p,resource->id,MagickCacheDigestExtent);
2039 p+=MagickCacheDigestExtent;
2040 SetStringInfoLength(meta,(size_t) (p-GetStringInfoDatum(meta)));
2041 return(meta);
2042}
2043
2044MagickExport MagickBooleanType PutMagickCacheResource(MagickCache *cache,
2045 MagickCacheResource *resource)
2046{
2047 char
2048 *path;
2049
2050 MagickBooleanType
2051 status;
2052
2053 StringInfo
2054 *meta;
2055
2056 /*
2057 Create the resource path as defined by the IRI.
2058 */
2059 assert(cache != (MagickCache *) NULL);
2060 assert(cache->signature == MagickCacheSignature);
2061 assert(resource != (MagickCacheResource *) NULL);
2062 assert(resource->signature == MagickCacheSignature);
2063 status=GetMagickCacheResource(cache,resource);
2064 if (status != MagickFalse)
2065 {
2066 (void) ThrowMagickException(resource->exception,GetMagickModule(),
2067 CacheError,"cannot overwrite resource","`%s'",resource->iri);
2068 return(MagickFalse);
2069 }
2070 path=AcquireString(cache->path);
2071 (void) ConcatenateString(&path,"/");
2072 (void) ConcatenateString(&path,resource->iri);
2073 if (MagickCreatePath(path) == MagickFalse)
2074 {
2075 path=DestroyString(path);
2076 (void) ThrowMagickException(resource->exception,GetMagickModule(),
2077 CacheError,"cannot put resource","`%s'",path);
2078 return(MagickFalse);
2079 }
2080 /*
2081 Export the MagickCache resource metadata.
2082 */
2083 (void) ConcatenateString(&path,"/");
2084 (void) ConcatenateString(&path,MagickCacheResourceSentinel);
2085 if (IsPathAccessible(path) != MagickFalse)
2086 {
2087 path=DestroyString(path);
2088 errno=EEXIST;
2089 return(MagickFalse);
2090 }
2091 SetMagickCacheResourceID(cache,resource);
2092 meta=SetMagickCacheResourceSentinel(resource);
2093 status=BlobToFile(path,GetStringInfoDatum(meta),GetStringInfoLength(meta),
2094 resource->exception);
2095 meta=DestroyStringInfo(meta);
2096 path=DestroyString(path);
2097 return(status);
2098}
2099
2100/*
2101%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2102% %
2103% %
2104% %
2105% P u t M a g i c k C a c h e R e s o u r c e B l o b %
2106% %
2107% %
2108% %
2109%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2110%
2111% PutMagickCacheResource() puts a blob resource in the MagickCache identified
2112% by its IRI. If the IRI already exists, an exception is returned.
2113%
2114% The format of the PutMagickCacheResource method is:
2115%
2116% MagickBooleanType PutMagickCacheResourceBlob(MagickCache *cache,
2117% const MagickCacheResource *resource,const size_t extent,
2118% const void blob)
2119%
2120% A description of each parameter follows:
2121%
2122% o cache: the cache repository.
2123%
2124% o resource: the resource.
2125%
2126% o blob: the blob.
2127%
2128*/
2129MagickExport MagickBooleanType PutMagickCacheResourceBlob(MagickCache *cache,
2130 MagickCacheResource *resource,const size_t extent,const void *blob)
2131{
2132 char
2133 *path;
2134
2135 MagickBooleanType
2136 status;
2137
2138 /*
2139 Puts a blob resource in the MagickCache identified by its IRI.
2140 */
2141 status=PutMagickCacheResource(cache,resource);
2142 if (status == MagickFalse)
2143 return(MagickFalse);
2144 path=AcquireString(cache->path);
2145 (void) ConcatenateString(&path,"/");
2146 (void) ConcatenateString(&path,resource->iri);
2147 (void) ConcatenateString(&path,"/");
2148 (void) ConcatenateString(&path,resource->id);
2149 status=BlobToFile(path,blob,extent,cache->exception);
2150 path=DestroyString(path);
2151 return(status);
2152}
2153
2154/*
2155%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2156% %
2157% %
2158% %
2159% P u t M a g i c k C a c h e R e s o u r c e I m a g e %
2160% %
2161% %
2162% %
2163%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2164%
2165% PutMagickCacheResourceImage() puts an image resource in the MagickCache
2166% identified by its IRI. If the IRI already exists, an exception is returned.
2167%
2168% The format of the PutMagickCacheResourceImage method is:
2169%
2170% MagickBooleanType PutMagickCacheResourceImage(MagickCache *cache,
2171% const MagickCacheResource *resource,const Image *image)
2172%
2173% A description of each parameter follows:
2174%
2175% o cache: the cache repository.
2176%
2177% o resource: the resource.
2178%
2179% o image: the image.
2180%
2181*/
2182MagickExport MagickBooleanType PutMagickCacheResourceImage(MagickCache *cache,
2183 MagickCacheResource *resource,const Image *image)
2184{
2185 char
2186 *path;
2187
2188 Image
2189 *images;
2190
2191 ImageInfo
2192 *image_info;
2193
2194 MagickBooleanType
2195 status;
2196
2197 /*
2198 Puts an image resource in the MagickCache identified by its IRI.
2199 */
2200 resource->columns=image->columns;
2201 resource->rows=image->rows;
2202 status=PutMagickCacheResource(cache,resource);
2203 if (status == MagickFalse)
2204 return(status);
2205 path=AcquireString(cache->path);
2206 (void) ConcatenateString(&path,"/");
2207 (void) ConcatenateString(&path,resource->iri);
2208 if (MagickCreatePath(path) == MagickFalse)
2209 return(MagickFalse);
2210 image_info=AcquireImageInfo();
2211 images=CloneImageList(image,resource->exception);
2212 (void) ConcatenateString(&path,"/");
2213 (void) ConcatenateString(&path,resource->id);
2214 (void) FormatLocaleString(images->filename,MagickPathExtent,"mpc:%s",path);
2215 path=DestroyString(path);
2216 status=WriteImages(image_info,images,images->filename,resource->exception);
2217 images=DestroyImageList(images);
2218 image_info=DestroyImageInfo(image_info);
2219 return(status);
2220}
2221
2222/*
2223%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2224% %
2225% %
2226% %
2227% P u t M a g i c k C a c h e R e s o u r c e M e t a %
2228% %
2229% %
2230% %
2231%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2232%
2233% PutMagickCacheResourceMeta() puts metadata in the MagickCache identified by
2234% its IRI. If the IRI already exists, an exception is returned.
2235%
2236% The format of the PutMagickCacheResourceMeta method is:
2237%
2238% MagickBooleanType PutMagickCacheResourceMeta(MagickCache *cache,
2239% const MagickCacheResource *resource,const char *properties)
2240%
2241% A description of each parameter follows:
2242%
2243% o cache: the cache repository.
2244%
2245% o resource: the resource.
2246%
2247% o properties: the properties.
2248%
2249*/
2250MagickExport MagickBooleanType PutMagickCacheResourceMeta(MagickCache *cache,
2251 MagickCacheResource *resource,const char *properties)
2252{
2253 char
2254 *path;
2255
2256 MagickBooleanType
2257 status;
2258
2259 /*
2260 Puts resource meta in the MagickCache identified by its IRI.
2261 */
2262 status=PutMagickCacheResource(cache,resource);
2263 if (status == MagickFalse)
2264 return(MagickFalse);
2265 path=AcquireString(cache->path);
2266 (void) ConcatenateString(&path,"/");
2267 (void) ConcatenateString(&path,resource->iri);
2268 (void) ConcatenateString(&path,"/");
2269 (void) ConcatenateString(&path,resource->id);
2270 status=BlobToFile(path,properties,strlen(properties)+1,cache->exception);
2271 path=DestroyString(path);
2272 return(status);
2273}
2274
2275/*
2276%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2277% %
2278% %
2279% %
2280% S e t M a g i c k C a c h e R e s o u r c e I R I %
2281% %
2282% %
2283% %
2284%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2285%
2286% SetMagickCacheResourceIRI() associates an IRI with a resource.
2287%
2288% The format of the SetMagickCacheResourceIRI method is:
2289%
2290% MagickBooleanType SetMagickCacheResourceIRI(MagickCache *cache,
2291% MagickCacheResource *resource,const char *iri)
2292%
2293% A description of each parameter follows:
2294%
2295% o resource: the resource.
2296%
2297% o iri: the IRI.
2298%
2299*/
2300MagickExport MagickBooleanType SetMagickCacheResourceIRI(MagickCache *cache,
2301 MagickCacheResource *resource,const char *iri)
2302{
2303 char
2304 *path,
2305 *p;
2306
2307 /*
2308 Parse the IRI into its components: project / type / resource-path.
2309 */
2310 assert(resource != (MagickCacheResource *) NULL);
2311 assert(resource->signature == MagickCoreSignature);
2312 if (resource->iri != (char *) NULL)
2313 resource->iri=DestroyString(resource->iri);
2314 resource->iri=ConstantString(iri);
2315 path=ConstantString(iri);
2316 p=strtok(path,"/");
2317 if (p == (char *) NULL)
2318 return(MagickFalse);
2319 if (resource->project != (char *) NULL)
2320 resource->project=DestroyString(resource->project);
2321 resource->project=ConstantString(p);
2322 p=strtok(NULL,"/");
2323 if (p == (char *) NULL)
2324 return(MagickFalse);
2325 if (resource->type != (char *) NULL)
2326 resource->type=DestroyString(resource->type);
2327 resource->type=ConstantString(p);
2328 path=DestroyString(path);
2329 if (resource->id != (char *) NULL)
2330 resource->id=DestroyString(resource->id);
2331 resource->id=ConstantString("");
2332 if (LocaleCompare(resource->type,"*") == 0)
2333 resource->resource_type=WildResourceType;
2334 else
2335 if (LocaleCompare(resource->type,"blob") == 0)
2336 resource->resource_type=BlobResourceType;
2337 else
2338 if (LocaleCompare(resource->type,"image") == 0)
2339 resource->resource_type=ImageResourceType;
2340 else
2341 if (LocaleCompare(resource->type,"meta") == 0)
2342 resource->resource_type=MetaResourceType;
2343 else
2344 {
2345 (void) ThrowMagickException(resource->exception,GetMagickModule(),
2346 CacheError,"unknown resource type","`%s'",resource->type);
2347 return(MagickFalse);
2348 }
2349 return(MagickTrue);
2350}
2351
2352/*
2353%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2354% %
2355% %
2356% %
2357% S e t M a g i c k C a c h e R e s o u r c e T T L %
2358% %
2359% %
2360% %
2361%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2362%
2363% SetMagickCacheResourceTTL() associates the time to live with a resource in
2364% the cache respository.
2365%
2366% The format of the SetMagickCacheResourceTTL method is:
2367%
2368% void SetMagickCacheResourceTTL(MagickCacheResource *resource,
2369% const time_t ttl)
2370%
2371% A description of each parameter follows:
2372%
2373% o resource: the resource.
2374%
2375% o ttl: the time to live.
2376%
2377*/
2378MagickExport void SetMagickCacheResourceTTL(MagickCacheResource *resource,
2379 const time_t ttl)
2380{
2381 assert(resource != (MagickCacheResource *) NULL);
2382 assert(resource->signature == MagickCoreSignature);
2383 resource->ttl=ttl;
2384}
2385
2386/*
2387%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2388% %
2389% %
2390% %
2391% S e t M a g i c k C a c h e R e s o u r c e V e r s i o n %
2392% %
2393% %
2394% %
2395%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2396%
2397% SetMagickCacheResourceVersion() associates the API version with a resource.
2398%
2399% The format of the SetMagickCacheResourceVersion method is:
2400%
2401% MagickBooleanType SetMagickCacheResourceVersion(
2402% MagickCacheResource *resource,const size_t version)
2403%
2404% A description of each parameter follows:
2405%
2406% o resource: the resource.
2407%
2408% o version: the version.
2409%
2410*/
2411MagickExport MagickBooleanType SetMagickCacheResourceVersion(
2412 MagickCacheResource *resource,const size_t version)
2413{
2414 assert(resource != (MagickCacheResource *) NULL);
2415 assert(resource->signature == MagickCoreSignature);
2416 resource->version=version;
2417 return(MagickTrue);
2418}