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
244 MagickCache
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{
338 MagickCacheResource
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 sentinel.
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:%02g:%02g:%02g%c %s\n",
1774 GetMagickCacheResourceIRI(resource),size,extent,
1775 ceil((double) (resource->ttl/(3600*24))),
1776 ceil((double) ((resource->ttl % (24*3600))/3600)),
1777 ceil((double) ((resource->ttl % 3600)/60)),
1778 ceil((double) ((resource->ttl % 3600) % 60)),expired,iso8601);
1779 path=DestroyString(path);
1780 return(status);
1781}
1782
1783/*
1784%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1785% %
1786% %
1787% %
1788% 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 %
1789% %
1790% %
1791% %
1792%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1793%
1794% IsMagickCacheResourceExpired() returns MagickTrue if the resource creation
1795% date plus the time to live is greater than or equal to the current time.
1796% Note, a resource with a time to live of zero, never expires.
1797%
1798% The format of the IsMagickCacheResourceExpired method is:
1799%
1800% MagickBooleanType IsMagickCacheResourceExpired(MagickCache *cache,
1801% MagickCacheResource *resource)
1802%
1803% A description of each parameter follows:
1804%
1805% o cache: the cache repository.
1806%
1807% o iri: the IRI.
1808%
1809*/
1810MagickExport MagickBooleanType IsMagickCacheResourceExpired(MagickCache *cache,
1811 MagickCacheResource *resource)
1812{
1813 MagickBooleanType
1814 status;
1815
1816 assert(cache != (MagickCache *) NULL);
1817 assert(cache->signature == MagickCacheSignature);
1818 status=GetMagickCacheResource(cache,resource);
1819 if (status == MagickFalse)
1820 return(status);
1821 if ((resource->ttl != 0) && ((resource->timestamp+resource->ttl) < time(0)))
1822 {
1823#if defined(ESTALE)
1824 errno=ESTALE;
1825#endif
1826 return(MagickTrue);
1827 }
1828 return(MagickFalse);
1829}
1830
1831/*
1832%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1833% %
1834% %
1835% %
1836% 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 %
1837% %
1838% %
1839% %
1840%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1841%
1842% IterateMagickCacheResources() iterates over all the resources in the
1843% MagickCache and calls the callback() method once for each resource
1844% discovered with three arguments: the MagickCache, the current resource, and
1845% a user context. Use the resource `get` methods to retrieve any associated
1846% metadata such as the IRI or time-to-live. To terminate the iteration, have
1847% callback() return MagickFalse.
1848%
1849% The format of the IterateMagickCacheResources method is:
1850%
1851% MagickBooleanType IterateMagickCacheResources(MagickCache *cache,
1852% const char *iri,MagickBooleanType (*callback)(MagickCache *cache,
1853% MagickCacheResource *resource,const void *context))
1854%
1855% A description of each parameter follows:
1856%
1857% o cache: the cache repository.
1858%
1859% o iri: the IRI.
1860%
1861*/
1862MagickExport MagickBooleanType IterateMagickCacheResources(MagickCache *cache,
1863 const char *iri,const void *context,MagickBooleanType (*callback)(
1864 MagickCache *cache,MagickCacheResource *resource,const void *context))
1865{
1866 char
1867 *path;
1868
1869 DIR
1870 *directory;
1871
1872 MagickBooleanType
1873 status;
1874
1875 struct dirent
1876 *entry;
1877
1878 struct ResourceNode
1879 *head,
1880 *node,
1881 *p,
1882 *q;
1883
1884 struct stat
1885 attributes;
1886
1887 /*
1888 Check that resource id exists in MagickCache.
1889 */
1890 assert(cache != (MagickCache *) NULL);
1891 assert(cache->signature == MagickCacheSignature);
1892 status=MagickTrue;
1893 head=(struct ResourceNode *) AcquireCriticalMemory(sizeof(*node));
1894 (void) memset(head,0,sizeof(*head));
1895 head->path=AcquireString(cache->path);
1896 (void) ConcatenateString(&head->path,"/");
1897 (void) ConcatenateString(&head->path,iri);
1898 head->next=(struct ResourceNode *) NULL;
1899 head->previous=(struct ResourceNode *) NULL;
1900 q=head;
1901 for (p=head; p != (struct ResourceNode *) NULL; p=p->next)
1902 {
1903 directory=opendir(p->path);
1904 if (directory == (DIR *) NULL)
1905 {
1906 status=MagickFalse;
1907 break;
1908 }
1909 while ((entry=readdir(directory)) != (struct dirent *) NULL)
1910 {
1911 path=AcquireString(p->path);
1912 (void) ConcatenateString(&path,"/");
1913 (void) ConcatenateString(&path,entry->d_name);
1914 if (GetPathAttributes(path,&attributes) <= 0)
1915 {
1916 path=DestroyString(path);
1917 break;
1918 }
1919 if ((strcmp(entry->d_name, ".") == 0) ||
1920 (strcmp(entry->d_name, "..") == 0))
1921 {
1922 path=DestroyString(path);
1923 continue;
1924 }
1925 if (S_ISDIR(attributes.st_mode) != 0)
1926 {
1927 node=(struct ResourceNode *) AcquireCriticalMemory(sizeof(*node));
1928 (void) memset(node,0,sizeof(*node));
1929 node->path=path;
1930 node->next=(struct ResourceNode *) NULL;
1931 node->previous=q;
1932 q->next=node;
1933 q=q->next;
1934 }
1935 else
1936 if (S_ISREG(attributes.st_mode) != 0)
1937 {
1938 char *sentinel = ConstantString(path);
1939 GetPathComponent(path,TailPath,sentinel);
1940 if (strcmp(sentinel,MagickCacheResourceSentinel) == 0)
1941 {
1942 MagickCacheResource
1943 *resource;
1944
1945 GetPathComponent(path,HeadPath,path);
1946 resource=AcquireMagickCacheResource(cache,path+
1947 strlen(cache->path)+1);
1948 status=GetMagickCacheResource(cache,resource);
1949 if (status != MagickFalse)
1950 {
1951 status=callback(cache,resource,context);
1952 if (status == MagickFalse)
1953 {
1954 path=DestroyString(path);
1955 resource=DestroyMagickCacheResource(resource);
1956 sentinel=DestroyString(sentinel);
1957 break;
1958 }
1959 }
1960 resource=DestroyMagickCacheResource(resource);
1961 }
1962 path=DestroyString(path);
1963 sentinel=DestroyString(sentinel);
1964 }
1965 }
1966 (void) closedir(directory);
1967 }
1968 /*
1969 Free resources.
1970 */
1971 for ( ; q != (struct ResourceNode *) NULL; )
1972 {
1973 node=q;
1974 q=q->previous;
1975 node->path=DestroyString(node->path);
1976 node=(struct ResourceNode *) RelinquishMagickMemory(node);
1977 }
1978 return(status);
1979}
1980
1981/*
1982%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1983% %
1984% %
1985% %
1986% P u t M a g i c k C a c h e R e s o u r c e %
1987% %
1988% %
1989% %
1990%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1991%
1992% PutMagickCacheResource() puts an image, image sequence, video, or metadata
1993% resource in the MagickCache identified by its IRI. If the IRI already
1994% exists, an exception is returned.
1995%
1996% The format of the PutMagickCacheResource method is:
1997%
1998% MagickBooleanType PutMagickCacheResource(MagickCache *cache,
1999% const MagickCacheResource *resource)
2000%
2001% A description of each parameter follows:
2002%
2003% o cache: the cache repository.
2004%
2005% o resource: the resource.
2006%
2007% o blob: the blob.
2008%
2009*/
2010
2011static StringInfo *SetMagickCacheResourceSentinel(
2012 const MagickCacheResource *resource)
2013{
2014 StringInfo
2015 *meta;
2016
2017 unsigned char
2018 *p;
2019
2020 unsigned int
2021 signature;
2022
2023 /*
2024 Set the MagickCache resource sentinel.
2025 */
2026 meta=AcquireStringInfo(MagickPathExtent);
2027 p=GetStringInfoDatum(meta);
2028 signature=GetMagickCacheSignature(resource->nonce);
2029 (void) memcpy(p,&signature,sizeof(signature));
2030 p+=sizeof(signature);
2031 (void) memcpy(p,GetStringInfoDatum(resource->nonce),
2032 GetStringInfoLength(resource->nonce));
2033 p+=GetStringInfoLength(resource->nonce);
2034 (void) memcpy(p,&resource->ttl,sizeof(resource->ttl));
2035 p+=sizeof(resource->ttl);
2036 (void) memcpy(p,&resource->columns,sizeof(resource->columns));
2037 p+=sizeof(resource->columns);
2038 (void) memcpy(p,&resource->rows,sizeof(resource->rows));
2039 p+=sizeof(resource->rows);
2040 (void) memcpy(p,resource->id,MagickCacheDigestExtent);
2041 p+=MagickCacheDigestExtent;
2042 SetStringInfoLength(meta,(size_t) (p-GetStringInfoDatum(meta)));
2043 return(meta);
2044}
2045
2046MagickExport MagickBooleanType PutMagickCacheResource(MagickCache *cache,
2047 MagickCacheResource *resource)
2048{
2049 char
2050 *path;
2051
2052 MagickBooleanType
2053 status;
2054
2055 StringInfo
2056 *meta;
2057
2058 /*
2059 Create the resource path as defined by the IRI.
2060 */
2061 assert(cache != (MagickCache *) NULL);
2062 assert(cache->signature == MagickCacheSignature);
2063 assert(resource != (MagickCacheResource *) NULL);
2064 assert(resource->signature == MagickCacheSignature);
2065 status=GetMagickCacheResource(cache,resource);
2066 if (status != MagickFalse)
2067 {
2068 (void) ThrowMagickException(resource->exception,GetMagickModule(),
2069 CacheError,"cannot overwrite resource","`%s'",resource->iri);
2070 return(MagickFalse);
2071 }
2072 path=AcquireString(cache->path);
2073 (void) ConcatenateString(&path,"/");
2074 (void) ConcatenateString(&path,resource->iri);
2075 if (MagickCreatePath(path) == MagickFalse)
2076 {
2077 path=DestroyString(path);
2078 (void) ThrowMagickException(resource->exception,GetMagickModule(),
2079 CacheError,"cannot put resource","`%s'",path);
2080 return(MagickFalse);
2081 }
2082 /*
2083 Export the MagickCache resource metadata.
2084 */
2085 (void) ConcatenateString(&path,"/");
2086 (void) ConcatenateString(&path,MagickCacheResourceSentinel);
2087 if (IsPathAccessible(path) != MagickFalse)
2088 {
2089 path=DestroyString(path);
2090 errno=EEXIST;
2091 return(MagickFalse);
2092 }
2093 SetMagickCacheResourceID(cache,resource);
2094 meta=SetMagickCacheResourceSentinel(resource);
2095 status=BlobToFile(path,GetStringInfoDatum(meta),GetStringInfoLength(meta),
2096 resource->exception);
2097 meta=DestroyStringInfo(meta);
2098 path=DestroyString(path);
2099 return(status);
2100}
2101
2102/*
2103%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2104% %
2105% %
2106% %
2107% 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 %
2108% %
2109% %
2110% %
2111%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2112%
2113% PutMagickCacheResource() puts a blob resource in the MagickCache identified
2114% by its IRI. If the IRI already exists, an exception is returned.
2115%
2116% The format of the PutMagickCacheResource method is:
2117%
2118% MagickBooleanType PutMagickCacheResourceBlob(MagickCache *cache,
2119% const MagickCacheResource *resource,const size_t extent,
2120% const void blob)
2121%
2122% A description of each parameter follows:
2123%
2124% o cache: the cache repository.
2125%
2126% o resource: the resource.
2127%
2128% o blob: the blob.
2129%
2130*/
2131MagickExport MagickBooleanType PutMagickCacheResourceBlob(MagickCache *cache,
2132 MagickCacheResource *resource,const size_t extent,const void *blob)
2133{
2134 char
2135 *path;
2136
2137 MagickBooleanType
2138 status;
2139
2140 /*
2141 Puts a blob resource in the MagickCache identified by its IRI.
2142 */
2143 status=PutMagickCacheResource(cache,resource);
2144 if (status == MagickFalse)
2145 return(MagickFalse);
2146 path=AcquireString(cache->path);
2147 (void) ConcatenateString(&path,"/");
2148 (void) ConcatenateString(&path,resource->iri);
2149 (void) ConcatenateString(&path,"/");
2150 (void) ConcatenateString(&path,resource->id);
2151 status=BlobToFile(path,blob,extent,cache->exception);
2152 path=DestroyString(path);
2153 return(status);
2154}
2155
2156/*
2157%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2158% %
2159% %
2160% %
2161% 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 %
2162% %
2163% %
2164% %
2165%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2166%
2167% PutMagickCacheResourceImage() puts an image resource in the MagickCache
2168% identified by its IRI. If the IRI already exists, an exception is returned.
2169%
2170% The format of the PutMagickCacheResourceImage method is:
2171%
2172% MagickBooleanType PutMagickCacheResourceImage(MagickCache *cache,
2173% const MagickCacheResource *resource,const Image *image)
2174%
2175% A description of each parameter follows:
2176%
2177% o cache: the cache repository.
2178%
2179% o resource: the resource.
2180%
2181% o image: the image.
2182%
2183*/
2184MagickExport MagickBooleanType PutMagickCacheResourceImage(MagickCache *cache,
2185 MagickCacheResource *resource,const Image *image)
2186{
2187 char
2188 *path;
2189
2190 Image
2191 *images;
2192
2193 ImageInfo
2194 *image_info;
2195
2196 MagickBooleanType
2197 status;
2198
2199 /*
2200 Puts an image resource in the MagickCache identified by its IRI.
2201 */
2202 resource->columns=image->columns;
2203 resource->rows=image->rows;
2204 status=PutMagickCacheResource(cache,resource);
2205 if (status == MagickFalse)
2206 return(status);
2207 path=AcquireString(cache->path);
2208 (void) ConcatenateString(&path,"/");
2209 (void) ConcatenateString(&path,resource->iri);
2210 if (MagickCreatePath(path) == MagickFalse)
2211 return(MagickFalse);
2212 image_info=AcquireImageInfo();
2213 images=CloneImageList(image,resource->exception);
2214 (void) ConcatenateString(&path,"/");
2215 (void) ConcatenateString(&path,resource->id);
2216 (void) FormatLocaleString(images->filename,MagickPathExtent,"mpc:%s",path);
2217 path=DestroyString(path);
2218 status=WriteImages(image_info,images,images->filename,resource->exception);
2219 images=DestroyImageList(images);
2220 image_info=DestroyImageInfo(image_info);
2221 return(status);
2222}
2223
2224/*
2225%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2226% %
2227% %
2228% %
2229% 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 %
2230% %
2231% %
2232% %
2233%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2234%
2235% PutMagickCacheResourceMeta() puts metadata in the MagickCache identified by
2236% its IRI. If the IRI already exists, an exception is returned.
2237%
2238% The format of the PutMagickCacheResourceMeta method is:
2239%
2240% MagickBooleanType PutMagickCacheResourceMeta(MagickCache *cache,
2241% const MagickCacheResource *resource,const char *properties)
2242%
2243% A description of each parameter follows:
2244%
2245% o cache: the cache repository.
2246%
2247% o resource: the resource.
2248%
2249% o properties: the properties.
2250%
2251*/
2252MagickExport MagickBooleanType PutMagickCacheResourceMeta(MagickCache *cache,
2253 MagickCacheResource *resource,const char *properties)
2254{
2255 char
2256 *path;
2257
2258 MagickBooleanType
2259 status;
2260
2261 /*
2262 Puts resource meta in the MagickCache identified by its IRI.
2263 */
2264 status=PutMagickCacheResource(cache,resource);
2265 if (status == MagickFalse)
2266 return(MagickFalse);
2267 path=AcquireString(cache->path);
2268 (void) ConcatenateString(&path,"/");
2269 (void) ConcatenateString(&path,resource->iri);
2270 (void) ConcatenateString(&path,"/");
2271 (void) ConcatenateString(&path,resource->id);
2272 status=BlobToFile(path,properties,strlen(properties)+1,cache->exception);
2273 path=DestroyString(path);
2274 return(status);
2275}
2276
2277/*
2278%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2279% %
2280% %
2281% %
2282% 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 %
2283% %
2284% %
2285% %
2286%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2287%
2288% SetMagickCacheResourceIRI() associates an IRI with a resource.
2289%
2290% The format of the SetMagickCacheResourceIRI method is:
2291%
2292% MagickBooleanType SetMagickCacheResourceIRI(MagickCache *cache,
2293% MagickCacheResource *resource,const char *iri)
2294%
2295% A description of each parameter follows:
2296%
2297% o resource: the resource.
2298%
2299% o iri: the IRI.
2300%
2301*/
2302MagickExport MagickBooleanType SetMagickCacheResourceIRI(MagickCache *cache,
2303 MagickCacheResource *resource,const char *iri)
2304{
2305 char
2306 *path,
2307 *p;
2308
2309 /*
2310 Parse the IRI into its components: project / type / resource-path.
2311 */
2312 assert(resource != (MagickCacheResource *) NULL);
2313 assert(resource->signature == MagickCoreSignature);
2314 if (resource->iri != (char *) NULL)
2315 resource->iri=DestroyString(resource->iri);
2316 resource->iri=ConstantString(iri);
2317 path=ConstantString(iri);
2318 p=strtok(path,"/");
2319 if (p == (char *) NULL)
2320 return(MagickFalse);
2321 if (resource->project != (char *) NULL)
2322 resource->project=DestroyString(resource->project);
2323 resource->project=ConstantString(p);
2324 p=strtok(NULL,"/");
2325 if (p == (char *) NULL)
2326 return(MagickFalse);
2327 if (resource->type != (char *) NULL)
2328 resource->type=DestroyString(resource->type);
2329 resource->type=ConstantString(p);
2330 path=DestroyString(path);
2331 if (resource->id != (char *) NULL)
2332 resource->id=DestroyString(resource->id);
2333 resource->id=ConstantString("");
2334 if (LocaleCompare(resource->type,"*") == 0)
2335 resource->resource_type=WildResourceType;
2336 else
2337 if (LocaleCompare(resource->type,"blob") == 0)
2338 resource->resource_type=BlobResourceType;
2339 else
2340 if (LocaleCompare(resource->type,"image") == 0)
2341 resource->resource_type=ImageResourceType;
2342 else
2343 if (LocaleCompare(resource->type,"meta") == 0)
2344 resource->resource_type=MetaResourceType;
2345 else
2346 {
2347 (void) ThrowMagickException(resource->exception,GetMagickModule(),
2348 CacheError,"unknown resource type","`%s'",resource->type);
2349 return(MagickFalse);
2350 }
2351 return(MagickTrue);
2352}
2353
2354/*
2355%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2356% %
2357% %
2358% %
2359% 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 %
2360% %
2361% %
2362% %
2363%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2364%
2365% SetMagickCacheResourceTTL() associates the time to live with a resource in
2366% the cache respository.
2367%
2368% The format of the SetMagickCacheResourceTTL method is:
2369%
2370% void SetMagickCacheResourceTTL(MagickCacheResource *resource,
2371% const time_t ttl)
2372%
2373% A description of each parameter follows:
2374%
2375% o resource: the resource.
2376%
2377% o ttl: the time to live.
2378%
2379*/
2380MagickExport void SetMagickCacheResourceTTL(MagickCacheResource *resource,
2381 const time_t ttl)
2382{
2383 assert(resource != (MagickCacheResource *) NULL);
2384 assert(resource->signature == MagickCoreSignature);
2385 resource->ttl=ttl;
2386}
2387
2388/*
2389%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2390% %
2391% %
2392% %
2393% 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 %
2394% %
2395% %
2396% %
2397%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2398%
2399% SetMagickCacheResourceVersion() associates the API version with a resource.
2400%
2401% The format of the SetMagickCacheResourceVersion method is:
2402%
2403% MagickBooleanType SetMagickCacheResourceVersion(
2404% MagickCacheResource *resource,const size_t version)
2405%
2406% A description of each parameter follows:
2407%
2408% o resource: the resource.
2409%
2410% o version: the version.
2411%
2412*/
2413MagickExport MagickBooleanType SetMagickCacheResourceVersion(
2414 MagickCacheResource *resource,const size_t version)
2415{
2416 assert(resource != (MagickCacheResource *) NULL);
2417 assert(resource->signature == MagickCoreSignature);
2418 resource->version=version;
2419 return(MagickTrue);
2420}