Bug 25151 - Move cleanCacheDirectory() from fc-cache.c into
[platform/upstream/fontconfig.git] / src / fccache.c
1 /*
2  * Copyright © 2000 Keith Packard
3  * Copyright © 2005 Patrick Lam
4  *
5  * Permission to use, copy, modify, distribute, and sell this software and its
6  * documentation for any purpose is hereby granted without fee, provided that
7  * the above copyright notice appear in all copies and that both that
8  * copyright notice and this permission notice appear in supporting
9  * documentation, and that the name of the author(s) not be used in
10  * advertising or publicity pertaining to distribution of the software without
11  * specific, written prior permission.  The authors make no
12  * representations about the suitability of this software for any purpose.  It
13  * is provided "as is" without express or implied warranty.
14  *
15  * THE AUTHOR(S) DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17  * EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "fcint.h"
27 #include "fcarch.h"
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <fcntl.h>
31 #include <dirent.h>
32 #include <string.h>
33 #include <sys/types.h>
34 #include <time.h>
35 #include <assert.h>
36 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
37 #  include <unistd.h>
38 #  include <sys/mman.h>
39 #endif
40
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
44
45
46 struct MD5Context {
47         FcChar32 buf[4];
48         FcChar32 bits[2];
49         unsigned char in[64];
50 };
51
52 static void MD5Init(struct MD5Context *ctx);
53 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len);
54 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx);
55 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
56
57 #define CACHEBASE_LEN (1 + 32 + 1 + sizeof (FC_ARCHITECTURE) + sizeof (FC_CACHE_SUFFIX))
58
59 #ifdef _WIN32
60
61 #include <windows.h>
62
63 #ifdef __GNUC__
64 typedef long long INT64;
65 #define EPOCH_OFFSET 11644473600ll
66 #else
67 #define EPOCH_OFFSET 11644473600i64
68 typedef __int64 INT64;
69 #endif
70
71 /* Workaround for problems in the stat() in the Microsoft C library:
72  *
73  * 1) stat() uses FindFirstFile() to get the file
74  * attributes. Unfortunately this API doesn't return correct values
75  * for modification time of a directory until some time after a file
76  * or subdirectory has been added to the directory. (This causes
77  * run-test.sh to fail, for instance.) GetFileAttributesEx() is
78  * better, it returns the updated timestamp right away.
79  *
80  * 2) stat() does some strange things related to backward
81  * compatibility with the local time timestamps on FAT volumes and
82  * daylight saving time. This causes problems after the switches
83  * to/from daylight saving time. See
84  * http://bugzilla.gnome.org/show_bug.cgi?id=154968 , especially
85  * comment #30, and http://www.codeproject.com/datetime/dstbugs.asp .
86  * We don't need any of that, FAT and Win9x are as good as dead. So
87  * just use the UTC timestamps from NTFS, converted to the Unix epoch.
88  */
89
90 int
91 FcStat (const FcChar8 *file, struct stat *statb)
92 {
93     WIN32_FILE_ATTRIBUTE_DATA wfad;
94     char full_path_name[MAX_PATH];
95     char *basename;
96     DWORD rc;
97
98     if (!GetFileAttributesEx (file, GetFileExInfoStandard, &wfad))
99         return -1;
100
101     statb->st_dev = 0;
102
103     /* Calculate a pseudo inode number as a hash of the full path name.
104      * Call GetLongPathName() to get the spelling of the path name as it
105      * is on disk.
106      */
107     rc = GetFullPathName (file, sizeof (full_path_name), full_path_name, &basename);
108     if (rc == 0 || rc > sizeof (full_path_name))
109         return -1;
110
111     rc = GetLongPathName (full_path_name, full_path_name, sizeof (full_path_name));
112     statb->st_ino = FcStringHash (full_path_name);
113
114     statb->st_mode = _S_IREAD | _S_IWRITE;
115     statb->st_mode |= (statb->st_mode >> 3) | (statb->st_mode >> 6);
116
117     if (wfad.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
118         statb->st_mode |= _S_IFDIR;
119     else
120         statb->st_mode |= _S_IFREG;
121
122     statb->st_nlink = 1;
123     statb->st_uid = statb->st_gid = 0;
124     statb->st_rdev = 0;
125
126     if (wfad.nFileSizeHigh > 0)
127         return -1;
128     statb->st_size = wfad.nFileSizeLow;
129
130     statb->st_atime = (*(INT64 *)&wfad.ftLastAccessTime)/10000000 - EPOCH_OFFSET;
131     statb->st_mtime = (*(INT64 *)&wfad.ftLastWriteTime)/10000000 - EPOCH_OFFSET;
132     statb->st_ctime = statb->st_mtime;
133
134     return 0;
135 }
136
137 #else
138
139 int
140 FcStat (const FcChar8 *file, struct stat *statb)
141 {
142   return stat ((char *) file, statb);
143 }
144
145 #endif
146
147 static const char bin2hex[] = { '0', '1', '2', '3',
148                                 '4', '5', '6', '7',
149                                 '8', '9', 'a', 'b',
150                                 'c', 'd', 'e', 'f' };
151
152 static FcChar8 *
153 FcDirCacheBasename (const FcChar8 * dir, FcChar8 cache_base[CACHEBASE_LEN])
154 {
155     unsigned char       hash[16];
156     FcChar8             *hex_hash;
157     int                 cnt;
158     struct MD5Context   ctx;
159
160     MD5Init (&ctx);
161     MD5Update (&ctx, (const unsigned char *)dir, strlen ((const char *) dir));
162
163     MD5Final (hash, &ctx);
164
165     cache_base[0] = '/';
166     hex_hash = cache_base + 1;
167     for (cnt = 0; cnt < 16; ++cnt)
168     {
169         hex_hash[2*cnt  ] = bin2hex[hash[cnt] >> 4];
170         hex_hash[2*cnt+1] = bin2hex[hash[cnt] & 0xf];
171     }
172     hex_hash[2*cnt] = 0;
173     strcat ((char *) cache_base, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX);
174
175     return cache_base;
176 }
177
178 FcBool
179 FcDirCacheUnlink (const FcChar8 *dir, FcConfig *config)
180 {
181     FcChar8     *cache_hashed = NULL;
182     FcChar8     cache_base[CACHEBASE_LEN];
183     FcStrList   *list;
184     FcChar8     *cache_dir;
185
186     FcDirCacheBasename (dir, cache_base);
187
188     list = FcStrListCreate (config->cacheDirs);
189     if (!list)
190         return FcFalse;
191         
192     while ((cache_dir = FcStrListNext (list)))
193     {
194         cache_hashed = FcStrPlus (cache_dir, cache_base);
195         if (!cache_hashed)
196             break;
197         (void) unlink ((char *) cache_hashed);
198         FcStrFree (cache_hashed);
199     }
200     FcStrListDone (list);
201     /* return FcFalse if something went wrong */
202     if (cache_dir)
203         return FcFalse;
204     return FcTrue;
205 }
206
207 static int
208 FcDirCacheOpenFile (const FcChar8 *cache_file, struct stat *file_stat)
209 {
210     int fd;
211
212 #ifdef _WIN32
213     if (FcStat (cache_file, file_stat) < 0)
214         return -1;
215 #endif
216     fd = open((char *) cache_file, O_RDONLY | O_BINARY);
217     if (fd < 0)
218         return fd;
219 #ifndef _WIN32
220     if (fstat (fd, file_stat) < 0)
221     {
222         close (fd);
223         return -1;
224     }
225 #endif
226     return fd;
227 }
228
229 /*
230  * Look for a cache file for the specified dir. Attempt
231  * to use each one we find, stopping when the callback
232  * indicates success
233  */
234 static FcBool
235 FcDirCacheProcess (FcConfig *config, const FcChar8 *dir,
236                    FcBool (*callback) (int fd, struct stat *fd_stat,
237                                        struct stat *dir_stat, void *closure),
238                    void *closure, FcChar8 **cache_file_ret)
239 {
240     int         fd = -1;
241     FcChar8     cache_base[CACHEBASE_LEN];
242     FcStrList   *list;
243     FcChar8     *cache_dir;
244     struct stat file_stat, dir_stat;
245     FcBool      ret = FcFalse;
246
247     if (FcStat (dir, &dir_stat) < 0)
248         return FcFalse;
249
250     FcDirCacheBasename (dir, cache_base);
251
252     list = FcStrListCreate (config->cacheDirs);
253     if (!list)
254         return FcFalse;
255         
256     while ((cache_dir = FcStrListNext (list)))
257     {
258         FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base);
259         if (!cache_hashed)
260             break;
261         fd = FcDirCacheOpenFile (cache_hashed, &file_stat);
262         if (fd >= 0) {
263             ret = (*callback) (fd, &file_stat, &dir_stat, closure);
264             close (fd);
265             if (ret)
266             {
267                 if (cache_file_ret)
268                     *cache_file_ret = cache_hashed;
269                 else
270                     FcStrFree (cache_hashed);
271                 break;
272             }
273         }
274         FcStrFree (cache_hashed);
275     }
276     FcStrListDone (list);
277
278     return ret;
279 }
280
281 #define FC_CACHE_MIN_MMAP   1024
282
283 /*
284  * Skip list element, make sure the 'next' pointer is the last thing
285  * in the structure, it will be allocated large enough to hold all
286  * of the necessary pointers
287  */
288
289 typedef struct _FcCacheSkip FcCacheSkip;
290
291 struct _FcCacheSkip {
292     FcCache         *cache;
293     int             ref;
294     intptr_t        size;
295     dev_t           cache_dev;
296     ino_t           cache_ino;
297     time_t          cache_mtime;
298     FcCacheSkip     *next[1];
299 };
300
301 /*
302  * The head of the skip list; pointers for every possible level
303  * in the skip list, plus the largest level in the list
304  */
305
306 #define FC_CACHE_MAX_LEVEL  16
307
308 static FcCacheSkip      *fcCacheChains[FC_CACHE_MAX_LEVEL];
309 static int              fcCacheMaxLevel;
310
311
312 static int32_t
313 FcRandom(void)
314 {
315     int32_t result;
316
317 #if HAVE_RANDOM_R
318     static struct random_data fcrandbuf;
319     static char statebuf[256];
320     static FcBool initialized = FcFalse;
321
322     if (initialized != FcTrue)
323     {
324         initstate_r(time(NULL), statebuf, 256, &fcrandbuf);
325         initialized = FcTrue;
326     }
327
328     random_r(&fcrandbuf, &result);
329 #elif HAVE_RANDOM
330     static char statebuf[256];
331     char *state;
332     static FcBool initialized = FcFalse;
333
334     if (initialized != FcTrue)
335     {
336         state = initstate(time(NULL), statebuf, 256);
337         initialized = FcTrue;
338     }
339     else
340         state = setstate(statebuf);
341
342     result = random();
343
344     setstate(state);
345 #elif HAVE_LRAND48
346     result = lrand48();
347 #elif HAVE_RAND_R
348     static unsigned int seed = time(NULL);
349
350     result = rand_r(&seed);
351 #elif HAVE_RAND
352     static FcBool initialized = FcFalse;
353
354     if (initialized != FcTrue)
355     {
356         srand(time(NULL));
357         initialized = FcTrue;
358     }
359     result = rand();
360 #else
361 # error no random number generator function available.
362 #endif
363
364     return result;
365 }
366
367 /*
368  * Generate a random level number, distributed
369  * so that each level is 1/4 as likely as the one before
370  *
371  * Note that level numbers run 1 <= level <= MAX_LEVEL
372  */
373 static int
374 random_level (void)
375 {
376     /* tricky bit -- each bit is '1' 75% of the time */
377     long int    bits = FcRandom () | FcRandom ();
378     int level = 0;
379
380     while (++level < FC_CACHE_MAX_LEVEL)
381     {
382         if (bits & 1)
383             break;
384         bits >>= 1;
385     }
386     return level;
387 }
388
389 /*
390  * Insert cache into the list
391  */
392 static FcBool
393 FcCacheInsert (FcCache *cache, struct stat *cache_stat)
394 {
395     FcCacheSkip    **update[FC_CACHE_MAX_LEVEL];
396     FcCacheSkip    *s, **next;
397     int             i, level;
398
399     /*
400      * Find links along each chain
401      */
402     next = fcCacheChains;
403     for (i = fcCacheMaxLevel; --i >= 0; )
404     {
405         for (; (s = next[i]); next = s->next)
406             if (s->cache > cache)
407                 break;
408         update[i] = &next[i];
409     }
410
411     /*
412      * Create new list element
413      */
414     level = random_level ();
415     if (level > fcCacheMaxLevel)
416     {
417         level = fcCacheMaxLevel + 1;
418         update[fcCacheMaxLevel] = &fcCacheChains[fcCacheMaxLevel];
419         fcCacheMaxLevel = level;
420     }
421
422     s = malloc (sizeof (FcCacheSkip) + (level - 1) * sizeof (FcCacheSkip *));
423     if (!s)
424         return FcFalse;
425
426     s->cache = cache;
427     s->size = cache->size;
428     s->ref = 1;
429     if (cache_stat)
430     {
431         s->cache_dev = cache_stat->st_dev;
432         s->cache_ino = cache_stat->st_ino;
433         s->cache_mtime = cache_stat->st_mtime;
434     }
435     else
436     {
437         s->cache_dev = 0;
438         s->cache_ino = 0;
439         s->cache_mtime = 0;
440     }
441
442     /*
443      * Insert into all fcCacheChains
444      */
445     for (i = 0; i < level; i++)
446     {
447         s->next[i] = *update[i];
448         *update[i] = s;
449     }
450     return FcTrue;
451 }
452
453 static FcCacheSkip *
454 FcCacheFindByAddr (void *object)
455 {
456     int     i;
457     FcCacheSkip    **next = fcCacheChains;
458     FcCacheSkip    *s;
459
460     /*
461      * Walk chain pointers one level at a time
462      */
463     for (i = fcCacheMaxLevel; --i >= 0;)
464         while (next[i] && (char *) object >= ((char *) next[i]->cache + next[i]->size))
465             next = next[i]->next;
466     /*
467      * Here we are
468      */
469     s = next[0];
470     if (s && (char *) object < ((char *) s->cache + s->size))
471         return s;
472     return NULL;
473 }
474
475 static void
476 FcCacheRemove (FcCache *cache)
477 {
478     FcCacheSkip     **update[FC_CACHE_MAX_LEVEL];
479     FcCacheSkip     *s, **next;
480     int             i;
481
482     /*
483      * Find links along each chain
484      */
485     next = fcCacheChains;
486     for (i = fcCacheMaxLevel; --i >= 0; )
487     {
488         for (; (s = next[i]); next = s->next)
489             if (s->cache >= cache)
490                 break;
491         update[i] = &next[i];
492     }
493     s = next[0];
494     for (i = 0; i < fcCacheMaxLevel && *update[i] == s; i++)
495         *update[i] = s->next[i];
496     while (fcCacheMaxLevel > 0 && fcCacheChains[fcCacheMaxLevel - 1] == NULL)
497         fcCacheMaxLevel--;
498     free (s);
499 }
500
501 static FcCache *
502 FcCacheFindByStat (struct stat *cache_stat)
503 {
504     FcCacheSkip     *s;
505
506     for (s = fcCacheChains[0]; s; s = s->next[0])
507         if (s->cache_dev == cache_stat->st_dev &&
508             s->cache_ino == cache_stat->st_ino &&
509             s->cache_mtime == cache_stat->st_mtime)
510         {
511             s->ref++;
512             return s->cache;
513         }
514     return NULL;
515 }
516
517 static void
518 FcDirCacheDispose (FcCache *cache)
519 {
520     switch (cache->magic) {
521     case FC_CACHE_MAGIC_ALLOC:
522         free (cache);
523         break;
524     case FC_CACHE_MAGIC_MMAP:
525 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
526         munmap (cache, cache->size);
527 #elif defined(_WIN32)
528         UnmapViewOfFile (cache);
529 #endif
530         break;
531     }
532     FcCacheRemove (cache);
533 }
534
535 void
536 FcCacheObjectReference (void *object)
537 {
538     FcCacheSkip *skip = FcCacheFindByAddr (object);
539
540     if (skip)
541         skip->ref++;
542 }
543
544 void
545 FcCacheObjectDereference (void *object)
546 {
547     FcCacheSkip *skip = FcCacheFindByAddr (object);
548
549     if (skip)
550     {
551         skip->ref--;
552         if (skip->ref <= 0)
553             FcDirCacheDispose (skip->cache);
554     }
555 }
556
557 void
558 FcCacheFini (void)
559 {
560     int             i;
561
562     for (i = 0; i < FC_CACHE_MAX_LEVEL; i++)
563         assert (fcCacheChains[i] == NULL);
564     assert (fcCacheMaxLevel == 0);
565 }
566
567 static FcBool
568 FcCacheTimeValid (FcCache *cache, struct stat *dir_stat)
569 {
570     struct stat dir_static;
571
572     if (!dir_stat)
573     {
574         if (FcStat (FcCacheDir (cache), &dir_static) < 0)
575             return FcFalse;
576         dir_stat = &dir_static;
577     }
578     if (FcDebug () & FC_DBG_CACHE)
579         printf ("FcCacheTimeValid dir \"%s\" cache time %d dir time %d\n",
580                 FcCacheDir (cache), cache->mtime, (int) dir_stat->st_mtime);
581     return cache->mtime == (int) dir_stat->st_mtime;
582 }
583
584 /*
585  * Map a cache file into memory
586  */
587 static FcCache *
588 FcDirCacheMapFd (int fd, struct stat *fd_stat, struct stat *dir_stat)
589 {
590     FcCache     *cache;
591     FcBool      allocated = FcFalse;
592
593     if (fd_stat->st_size < sizeof (FcCache))
594         return NULL;
595     cache = FcCacheFindByStat (fd_stat);
596     if (cache)
597     {
598         if (FcCacheTimeValid (cache, dir_stat))
599             return cache;
600         FcDirCacheUnload (cache);
601         cache = NULL;
602     }
603
604     /*
605      * Lage cache files are mmap'ed, smaller cache files are read. This
606      * balances the system cost of mmap against per-process memory usage.
607      */
608     if (fd_stat->st_size >= FC_CACHE_MIN_MMAP)
609     {
610 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
611         cache = mmap (0, fd_stat->st_size, PROT_READ, MAP_SHARED, fd, 0);
612 #ifdef HAVE_POSIX_FADVISE
613         posix_fadvise (fd, 0, fd_stat->st_size, POSIX_FADV_WILLNEED);
614 #endif
615         if (cache == MAP_FAILED)
616             cache = NULL;
617 #elif defined(_WIN32)
618         {
619             HANDLE hFileMap;
620
621             cache = NULL;
622             hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
623                                          PAGE_READONLY, 0, 0, NULL);
624             if (hFileMap != NULL)
625             {
626                 cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0,
627                                        fd_stat->st_size);
628                 CloseHandle (hFileMap);
629             }
630         }
631 #endif
632     }
633     if (!cache)
634     {
635         cache = malloc (fd_stat->st_size);
636         if (!cache)
637             return NULL;
638
639         if (read (fd, cache, fd_stat->st_size) != fd_stat->st_size)
640         {
641             free (cache);
642             return NULL;
643         }
644         allocated = FcTrue;
645     }
646     if (cache->magic != FC_CACHE_MAGIC_MMAP ||
647         cache->version < FC_CACHE_CONTENT_VERSION ||
648         cache->size != fd_stat->st_size ||
649         !FcCacheTimeValid (cache, dir_stat) ||
650         !FcCacheInsert (cache, fd_stat))
651     {
652         if (allocated)
653             free (cache);
654         else
655         {
656 #if defined(HAVE_MMAP) || defined(__CYGWIN__)
657             munmap (cache, fd_stat->st_size);
658 #elif defined(_WIN32)
659             UnmapViewOfFile (cache);
660 #endif
661         }
662         return NULL;
663     }
664
665     /* Mark allocated caches so they're freed rather than unmapped */
666     if (allocated)
667         cache->magic = FC_CACHE_MAGIC_ALLOC;
668         
669     return cache;
670 }
671
672 void
673 FcDirCacheReference (FcCache *cache, int nref)
674 {
675     FcCacheSkip *skip = FcCacheFindByAddr (cache);
676
677     if (skip)
678         skip->ref += nref;
679 }
680
681 void
682 FcDirCacheUnload (FcCache *cache)
683 {
684     FcCacheObjectDereference (cache);
685 }
686
687 static FcBool
688 FcDirCacheMapHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
689 {
690     FcCache *cache = FcDirCacheMapFd (fd, fd_stat, dir_stat);
691
692     if (!cache)
693         return FcFalse;
694     *((FcCache **) closure) = cache;
695     return FcTrue;
696 }
697
698 FcCache *
699 FcDirCacheLoad (const FcChar8 *dir, FcConfig *config, FcChar8 **cache_file)
700 {
701     FcCache *cache = NULL;
702
703     if (!FcDirCacheProcess (config, dir,
704                             FcDirCacheMapHelper,
705                             &cache, cache_file))
706         return NULL;
707     return cache;
708 }
709
710 FcCache *
711 FcDirCacheLoadFile (const FcChar8 *cache_file, struct stat *file_stat)
712 {
713     int fd;
714     FcCache *cache;
715     struct stat my_file_stat;
716
717     if (!file_stat)
718         file_stat = &my_file_stat;
719     fd = FcDirCacheOpenFile (cache_file, file_stat);
720     if (fd < 0)
721         return NULL;
722     cache = FcDirCacheMapFd (fd, file_stat, NULL);
723     close (fd);
724     return cache;
725 }
726
727 /*
728  * Validate a cache file by reading the header and checking
729  * the magic number and the size field
730  */
731 static FcBool
732 FcDirCacheValidateHelper (int fd, struct stat *fd_stat, struct stat *dir_stat, void *closure)
733 {
734     FcBool  ret = FcTrue;
735     FcCache     c;
736
737     if (read (fd, &c, sizeof (FcCache)) != sizeof (FcCache))
738         ret = FcFalse;
739     else if (c.magic != FC_CACHE_MAGIC_MMAP)
740         ret = FcFalse;
741     else if (c.version < FC_CACHE_CONTENT_VERSION)
742         ret = FcFalse;
743     else if (fd_stat->st_size != c.size)
744         ret = FcFalse;
745     else if (c.mtime != (int) dir_stat->st_mtime)
746         ret = FcFalse;
747     return ret;
748 }
749
750 static FcBool
751 FcDirCacheValidConfig (const FcChar8 *dir, FcConfig *config)
752 {
753     return FcDirCacheProcess (config, dir,
754                               FcDirCacheValidateHelper,
755                               NULL, NULL);
756 }
757
758 FcBool
759 FcDirCacheValid (const FcChar8 *dir)
760 {
761     FcConfig    *config;
762
763     config = FcConfigGetCurrent ();
764     if (!config)
765         return FcFalse;
766
767     return FcDirCacheValidConfig (dir, config);
768 }
769
770 /*
771  * Build a cache structure from the given contents
772  */
773 FcCache *
774 FcDirCacheBuild (FcFontSet *set, const FcChar8 *dir, struct stat *dir_stat, FcStrSet *dirs)
775 {
776     FcSerialize *serialize = FcSerializeCreate ();
777     FcCache *cache;
778     int i;
779     FcChar8     *dir_serialize;
780     intptr_t    *dirs_serialize;
781     FcFontSet   *set_serialize;
782
783     if (!serialize)
784         return NULL;
785     /*
786      * Space for cache structure
787      */
788     FcSerializeReserve (serialize, sizeof (FcCache));
789     /*
790      * Directory name
791      */
792     if (!FcStrSerializeAlloc (serialize, dir))
793         goto bail1;
794     /*
795      * Subdirs
796      */
797     FcSerializeAlloc (serialize, dirs, dirs->num * sizeof (FcChar8 *));
798     for (i = 0; i < dirs->num; i++)
799         if (!FcStrSerializeAlloc (serialize, dirs->strs[i]))
800             goto bail1;
801
802     /*
803      * Patterns
804      */
805     if (!FcFontSetSerializeAlloc (serialize, set))
806         goto bail1;
807
808     /* Serialize layout complete. Now allocate space and fill it */
809     cache = malloc (serialize->size);
810     if (!cache)
811         goto bail1;
812     /* shut up valgrind */
813     memset (cache, 0, serialize->size);
814
815     serialize->linear = cache;
816
817     cache->magic = FC_CACHE_MAGIC_ALLOC;
818     cache->version = FC_CACHE_CONTENT_VERSION;
819     cache->size = serialize->size;
820     cache->mtime = (int) dir_stat->st_mtime;
821
822     /*
823      * Serialize directory name
824      */
825     dir_serialize = FcStrSerialize (serialize, dir);
826     if (!dir_serialize)
827         goto bail2;
828     cache->dir = FcPtrToOffset (cache, dir_serialize);
829
830     /*
831      * Serialize sub dirs
832      */
833     dirs_serialize = FcSerializePtr (serialize, dirs);
834     if (!dirs_serialize)
835         goto bail2;
836     cache->dirs = FcPtrToOffset (cache, dirs_serialize);
837     cache->dirs_count = dirs->num;
838     for (i = 0; i < dirs->num; i++)
839     {
840         FcChar8 *d_serialize = FcStrSerialize (serialize, dirs->strs[i]);
841         if (!d_serialize)
842             goto bail2;
843         dirs_serialize[i] = FcPtrToOffset (dirs_serialize, d_serialize);
844     }
845
846     /*
847      * Serialize font set
848      */
849     set_serialize = FcFontSetSerialize (serialize, set);
850     if (!set_serialize)
851         goto bail2;
852     cache->set = FcPtrToOffset (cache, set_serialize);
853
854     FcSerializeDestroy (serialize);
855
856     FcCacheInsert (cache, NULL);
857
858     return cache;
859
860 bail2:
861     free (cache);
862 bail1:
863     FcSerializeDestroy (serialize);
864     return NULL;
865 }
866
867
868 #ifdef _WIN32
869 #define mkdir(path,mode) _mkdir(path)
870 #endif
871
872 static FcBool
873 FcMakeDirectory (const FcChar8 *dir)
874 {
875     FcChar8 *parent;
876     FcBool  ret;
877
878     if (strlen ((char *) dir) == 0)
879         return FcFalse;
880
881     parent = FcStrDirname (dir);
882     if (!parent)
883         return FcFalse;
884     if (access ((char *) parent, F_OK) == 0)
885         ret = mkdir ((char *) dir, 0755) == 0 && chmod ((char *) dir, 0755) == 0;
886     else if (access ((char *) parent, F_OK) == -1)
887         ret = FcMakeDirectory (parent) && (mkdir ((char *) dir, 0755) == 0) && chmod ((char *) dir, 0755) == 0;
888     else
889         ret = FcFalse;
890     FcStrFree (parent);
891     return ret;
892 }
893
894 /* write serialized state to the cache file */
895 FcBool
896 FcDirCacheWrite (FcCache *cache, FcConfig *config)
897 {
898     FcChar8         *dir = FcCacheDir (cache);
899     FcChar8         cache_base[CACHEBASE_LEN];
900     FcChar8         *cache_hashed;
901     int             fd;
902     FcAtomic        *atomic;
903     FcStrList       *list;
904     FcChar8         *cache_dir = NULL;
905     FcChar8         *test_dir;
906     FcCacheSkip     *skip;
907     struct stat     cache_stat;
908     int             magic;
909     int             written;
910
911     /*
912      * Write it to the first directory in the list which is writable
913      */
914
915     list = FcStrListCreate (config->cacheDirs);
916     if (!list)
917         return FcFalse;
918     while ((test_dir = FcStrListNext (list))) {
919         if (access ((char *) test_dir, W_OK|X_OK) == 0)
920         {
921             cache_dir = test_dir;
922             break;
923         }
924         else
925         {
926             /*
927              * If the directory doesn't exist, try to create it
928              */
929             if (access ((char *) test_dir, F_OK) == -1) {
930                 if (FcMakeDirectory (test_dir))
931                 {
932                     cache_dir = test_dir;
933                     break;
934                 }
935             }
936             /*
937              * Otherwise, try making it writable
938              */
939             else if (chmod ((char *) test_dir, 0755) == 0)
940             {
941                 cache_dir = test_dir;
942                 break;
943             }
944         }
945     }
946     FcStrListDone (list);
947     if (!cache_dir)
948         return FcFalse;
949
950     FcDirCacheBasename (dir, cache_base);
951     cache_hashed = FcStrPlus (cache_dir, cache_base);
952     if (!cache_hashed)
953         return FcFalse;
954
955     if (FcDebug () & FC_DBG_CACHE)
956         printf ("FcDirCacheWriteDir dir \"%s\" file \"%s\"\n",
957                 dir, cache_hashed);
958
959     atomic = FcAtomicCreate ((FcChar8 *)cache_hashed);
960     if (!atomic)
961         goto bail1;
962
963     if (!FcAtomicLock (atomic))
964         goto bail3;
965
966     fd = open((char *)FcAtomicNewFile (atomic), O_RDWR | O_CREAT | O_BINARY, 0666);
967     if (fd == -1)
968         goto bail4;
969
970     /* Temporarily switch magic to MMAP while writing to file */
971     magic = cache->magic;
972     if (magic != FC_CACHE_MAGIC_MMAP)
973         cache->magic = FC_CACHE_MAGIC_MMAP;
974
975     /*
976      * Write cache contents to file
977      */
978     written = write (fd, cache, cache->size);
979
980     /* Switch magic back */
981     if (magic != FC_CACHE_MAGIC_MMAP)
982         cache->magic = magic;
983
984     if (written != cache->size)
985     {
986         perror ("write cache");
987         goto bail5;
988     }
989
990     close(fd);
991     if (!FcAtomicReplaceOrig(atomic))
992         goto bail4;
993
994     /* If the file is small, update the cache chain entry such that the
995      * new cache file is not read again.  If it's large, we don't do that
996      * such that we reload it, using mmap, which is shared across processes.
997      */
998     if (cache->size < FC_CACHE_MIN_MMAP &&
999         (skip = FcCacheFindByAddr (cache)) &&
1000         FcStat (cache_hashed, &cache_stat))
1001     {
1002         skip->cache_dev = cache_stat.st_dev;
1003         skip->cache_ino = cache_stat.st_ino;
1004         skip->cache_mtime = cache_stat.st_mtime;
1005     }
1006
1007     FcStrFree (cache_hashed);
1008     FcAtomicUnlock (atomic);
1009     FcAtomicDestroy (atomic);
1010     return FcTrue;
1011
1012  bail5:
1013     close (fd);
1014  bail4:
1015     FcAtomicUnlock (atomic);
1016  bail3:
1017     FcAtomicDestroy (atomic);
1018  bail1:
1019     FcStrFree (cache_hashed);
1020     return FcFalse;
1021 }
1022
1023 FcBool
1024 FcDirCacheClean (const FcChar8 *cache_dir, FcBool verbose)
1025 {
1026     DIR         *d;
1027     struct dirent *ent;
1028     FcChar8     *dir_base;
1029     FcBool      ret = FcTrue;
1030     FcBool      remove;
1031     FcCache     *cache;
1032     struct stat target_stat;
1033
1034     dir_base = FcStrPlus (cache_dir, (FcChar8 *) FC_DIR_SEPARATOR_S);
1035     if (!dir_base)
1036     {
1037         fprintf (stderr, "Fontconfig error: %s: out of memory\n", cache_dir);
1038         return FcFalse;
1039     }
1040     if (access ((char *) cache_dir, W_OK) != 0)
1041     {
1042         if (verbose || FcDebug () & FC_DBG_CACHE)
1043             printf ("%s: not cleaning %s cache directory\n", cache_dir,
1044                     access ((char *) cache_dir, F_OK) == 0 ? "unwritable" : "non-existent");
1045         goto bail0;
1046     }
1047     if (verbose || FcDebug () & FC_DBG_CACHE)
1048         printf ("%s: cleaning cache directory\n", cache_dir);
1049     d = opendir ((char *) cache_dir);
1050     if (!d)
1051     {
1052         perror ((char *) cache_dir);
1053         ret = FcFalse;
1054         goto bail0;
1055     }
1056     while ((ent = readdir (d)))
1057     {
1058         FcChar8 *file_name;
1059         const FcChar8   *target_dir;
1060
1061         if (ent->d_name[0] == '.')
1062             continue;
1063         /* skip cache files for different architectures and */
1064         /* files which are not cache files at all */
1065         if (strlen(ent->d_name) != 32 + strlen ("-" FC_ARCHITECTURE FC_CACHE_SUFFIX) ||
1066             strcmp(ent->d_name + 32, "-" FC_ARCHITECTURE FC_CACHE_SUFFIX))
1067             continue;
1068
1069         file_name = FcStrPlus (dir_base, (FcChar8 *) ent->d_name);
1070         if (!file_name)
1071         {
1072             fprintf (stderr, "Fontconfig error: %s: allocation failure\n", cache_dir);
1073             ret = FcFalse;
1074             break;
1075         }
1076         remove = FcFalse;
1077         cache = FcDirCacheLoadFile (file_name, NULL);
1078         if (!cache)
1079         {
1080             if (verbose || FcDebug () & FC_DBG_CACHE)
1081                 printf ("%s: invalid cache file: %s\n", cache_dir, ent->d_name);
1082             remove = FcTrue;
1083         }
1084         else
1085         {
1086             target_dir = FcCacheDir (cache);
1087             if (stat ((char *) target_dir, &target_stat) < 0)
1088             {
1089                 if (verbose || FcDebug () & FC_DBG_CACHE)
1090                     printf ("%s: %s: missing directory: %s \n",
1091                             cache_dir, ent->d_name, target_dir);
1092                 remove = FcTrue;
1093             }
1094         }
1095         if (remove)
1096         {
1097             if (unlink ((char *) file_name) < 0)
1098             {
1099                 perror ((char *) file_name);
1100                 ret = FcFalse;
1101             }
1102         }
1103         FcDirCacheUnload (cache);
1104         FcStrFree (file_name);
1105     }
1106
1107     closedir (d);
1108   bail0:
1109     FcStrFree (dir_base);
1110
1111     return ret;
1112 }
1113
1114 /*
1115  * Hokey little macro trick to permit the definitions of C functions
1116  * with the same name as CPP macros
1117  */
1118 #define args1(x)            (x)
1119 #define args2(x,y)          (x,y)
1120
1121 const FcChar8 *
1122 FcCacheDir args1(const FcCache *c)
1123 {
1124     return FcCacheDir (c);
1125 }
1126
1127 FcFontSet *
1128 FcCacheCopySet args1(const FcCache *c)
1129 {
1130     FcFontSet   *old = FcCacheSet (c);
1131     FcFontSet   *new = FcFontSetCreate ();
1132     int         i;
1133
1134     if (!new)
1135         return NULL;
1136     for (i = 0; i < old->nfont; i++)
1137     {
1138         FcPattern   *font = FcFontSetFont (old, i);
1139         
1140         FcPatternReference (font);
1141         if (!FcFontSetAdd (new, font))
1142         {
1143             FcFontSetDestroy (new);
1144             return NULL;
1145         }
1146     }
1147     return new;
1148 }
1149
1150 const FcChar8 *
1151 FcCacheSubdir args2(const FcCache *c, int i)
1152 {
1153     return FcCacheSubdir (c, i);
1154 }
1155
1156 int
1157 FcCacheNumSubdir args1(const FcCache *c)
1158 {
1159     return c->dirs_count;
1160 }
1161
1162 int
1163 FcCacheNumFont args1(const FcCache *c)
1164 {
1165     return FcCacheSet(c)->nfont;
1166 }
1167
1168 /*
1169  * This code implements the MD5 message-digest algorithm.
1170  * The algorithm is due to Ron Rivest.  This code was
1171  * written by Colin Plumb in 1993, no copyright is claimed.
1172  * This code is in the public domain; do with it what you wish.
1173  *
1174  * Equivalent code is available from RSA Data Security, Inc.
1175  * This code has been tested against that, and is equivalent,
1176  * except that you don't need to include two pages of legalese
1177  * with every copy.
1178  *
1179  * To compute the message digest of a chunk of bytes, declare an
1180  * MD5Context structure, pass it to MD5Init, call MD5Update as
1181  * needed on buffers full of bytes, and then call MD5Final, which
1182  * will fill a supplied 16-byte array with the digest.
1183  */
1184
1185 #ifndef HIGHFIRST
1186 #define byteReverse(buf, len)   /* Nothing */
1187 #else
1188 /*
1189  * Note: this code is harmless on little-endian machines.
1190  */
1191 void byteReverse(unsigned char *buf, unsigned longs)
1192 {
1193     FcChar32 t;
1194     do {
1195         t = (FcChar32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
1196             ((unsigned) buf[1] << 8 | buf[0]);
1197         *(FcChar32 *) buf = t;
1198         buf += 4;
1199     } while (--longs);
1200 }
1201 #endif
1202
1203 /*
1204  * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
1205  * initialization constants.
1206  */
1207 static void MD5Init(struct MD5Context *ctx)
1208 {
1209     ctx->buf[0] = 0x67452301;
1210     ctx->buf[1] = 0xefcdab89;
1211     ctx->buf[2] = 0x98badcfe;
1212     ctx->buf[3] = 0x10325476;
1213
1214     ctx->bits[0] = 0;
1215     ctx->bits[1] = 0;
1216 }
1217
1218 /*
1219  * Update context to reflect the concatenation of another buffer full
1220  * of bytes.
1221  */
1222 static void MD5Update(struct MD5Context *ctx, const unsigned char *buf, unsigned len)
1223 {
1224     FcChar32 t;
1225
1226     /* Update bitcount */
1227
1228     t = ctx->bits[0];
1229     if ((ctx->bits[0] = t + ((FcChar32) len << 3)) < t)
1230         ctx->bits[1]++;         /* Carry from low to high */
1231     ctx->bits[1] += len >> 29;
1232
1233     t = (t >> 3) & 0x3f;        /* Bytes already in shsInfo->data */
1234
1235     /* Handle any leading odd-sized chunks */
1236
1237     if (t) {
1238         unsigned char *p = (unsigned char *) ctx->in + t;
1239
1240         t = 64 - t;
1241         if (len < t) {
1242             memcpy(p, buf, len);
1243             return;
1244         }
1245         memcpy(p, buf, t);
1246         byteReverse(ctx->in, 16);
1247         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1248         buf += t;
1249         len -= t;
1250     }
1251     /* Process data in 64-byte chunks */
1252
1253     while (len >= 64) {
1254         memcpy(ctx->in, buf, 64);
1255         byteReverse(ctx->in, 16);
1256         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1257         buf += 64;
1258         len -= 64;
1259     }
1260
1261     /* Handle any remaining bytes of data. */
1262
1263     memcpy(ctx->in, buf, len);
1264 }
1265
1266 /*
1267  * Final wrapup - pad to 64-byte boundary with the bit pattern
1268  * 1 0* (64-bit count of bits processed, MSB-first)
1269  */
1270 static void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
1271 {
1272     unsigned count;
1273     unsigned char *p;
1274
1275     /* Compute number of bytes mod 64 */
1276     count = (ctx->bits[0] >> 3) & 0x3F;
1277
1278     /* Set the first char of padding to 0x80.  This is safe since there is
1279        always at least one byte free */
1280     p = ctx->in + count;
1281     *p++ = 0x80;
1282
1283     /* Bytes of padding needed to make 64 bytes */
1284     count = 64 - 1 - count;
1285
1286     /* Pad out to 56 mod 64 */
1287     if (count < 8) {
1288         /* Two lots of padding:  Pad the first block to 64 bytes */
1289         memset(p, 0, count);
1290         byteReverse(ctx->in, 16);
1291         MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1292
1293         /* Now fill the next block with 56 bytes */
1294         memset(ctx->in, 0, 56);
1295     } else {
1296         /* Pad block to 56 bytes */
1297         memset(p, 0, count - 8);
1298     }
1299     byteReverse(ctx->in, 14);
1300
1301     /* Append length in bits and transform */
1302     ((FcChar32 *) ctx->in)[14] = ctx->bits[0];
1303     ((FcChar32 *) ctx->in)[15] = ctx->bits[1];
1304
1305     MD5Transform(ctx->buf, (FcChar32 *) ctx->in);
1306     byteReverse((unsigned char *) ctx->buf, 4);
1307     memcpy(digest, ctx->buf, 16);
1308     memset(ctx, 0, sizeof(*ctx));        /* In case it's sensitive */
1309 }
1310
1311
1312 /* The four core functions - F1 is optimized somewhat */
1313
1314 /* #define F1(x, y, z) (x & y | ~x & z) */
1315 #define F1(x, y, z) (z ^ (x & (y ^ z)))
1316 #define F2(x, y, z) F1(z, x, y)
1317 #define F3(x, y, z) (x ^ y ^ z)
1318 #define F4(x, y, z) (y ^ (x | ~z))
1319
1320 /* This is the central step in the MD5 algorithm. */
1321 #define MD5STEP(f, w, x, y, z, data, s) \
1322         ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
1323
1324 /*
1325  * The core of the MD5 algorithm, this alters an existing MD5 hash to
1326  * reflect the addition of 16 longwords of new data.  MD5Update blocks
1327  * the data and converts bytes into longwords for this routine.
1328  */
1329 static void MD5Transform(FcChar32 buf[4], FcChar32 in[16])
1330 {
1331     register FcChar32 a, b, c, d;
1332
1333     a = buf[0];
1334     b = buf[1];
1335     c = buf[2];
1336     d = buf[3];
1337
1338     MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
1339     MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
1340     MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
1341     MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
1342     MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
1343     MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
1344     MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
1345     MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
1346     MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
1347     MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
1348     MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
1349     MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
1350     MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
1351     MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
1352     MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
1353     MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
1354
1355     MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
1356     MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
1357     MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
1358     MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
1359     MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
1360     MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
1361     MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
1362     MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
1363     MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
1364     MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
1365     MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
1366     MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
1367     MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
1368     MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
1369     MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
1370     MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
1371
1372     MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
1373     MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
1374     MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
1375     MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
1376     MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
1377     MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
1378     MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
1379     MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
1380     MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
1381     MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
1382     MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
1383     MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
1384     MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
1385     MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
1386     MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
1387     MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
1388
1389     MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
1390     MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
1391     MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
1392     MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
1393     MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
1394     MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
1395     MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
1396     MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
1397     MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
1398     MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
1399     MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
1400     MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
1401     MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
1402     MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
1403     MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
1404     MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
1405
1406     buf[0] += a;
1407     buf[1] += b;
1408     buf[2] += c;
1409     buf[3] += d;
1410 }
1411 #define __fccache__
1412 #include "fcaliastail.h"
1413 #undef __fccache__