From: Patrick Lam Date: Mon, 25 Jul 2005 04:10:09 +0000 (+0000) Subject: #ifdef out old cache stuff, replace with first version of new mmapping X-Git-Tag: fc-2_3_90~25 X-Git-Url: https://git.wh0rd.org/?p=fontconfig.git;a=commitdiff_plain;h=212c9f437e959fbdc5fe344c67b8c1cf8ca63edb #ifdef out old cache stuff, replace with first version of new mmapping cache. Add *Read and *Write procedures which mmap in and write out the fontconfig data structures to disk. Currently, create cache in /tmp, with different sections for each architecture (as returned by uname's .machine field. Run the fc-cache binary to create a new cache file; fontconfig then uses this cache file on subsequent runs, saving lots of memory. Also fixes a few bugs and leaks. --- diff --git a/fc-cache/fc-cache.c b/fc-cache/fc-cache.c index 1e8fdf2..7d01ccf 100644 --- a/fc-cache/fc-cache.c +++ b/fc-cache/fc-cache.c @@ -93,6 +93,7 @@ usage (char *program) exit (1); } +#if 0 static int nsubdirs (FcStrSet *set) { @@ -222,6 +223,7 @@ scanDirs (FcStrList *list, FcConfig *config, char *program, FcBool force, FcBool FcStrListDone (list); return ret; } +#endif int main (int argc, char **argv) @@ -268,12 +270,20 @@ main (int argc, char **argv) if (systemOnly) FcConfigEnableHome (FcFalse); - config = FcInitLoadConfig (); + FcCacheForce (FcTrue); + /* need to use FcInitLoadConfig when we use dirs */ + FcInit (); + config = FcConfigGetCurrent (); if (!config) { fprintf (stderr, "%s: Can't init font config library\n", argv[0]); return 1; } + + /* We don't yet have per-directory caches. */ + ret = (FcCacheWrite (config) == FcFalse); + +#if 0 if (argv[i]) { dirs = FcStrSetCreate (); @@ -298,6 +308,7 @@ main (int argc, char **argv) else list = FcConfigGetConfigDirs (config); ret = scanDirs (list, config, argv[0], force, verbose); +#endif /* * Now we need to sleep a second (or two, to be extra sure), to make * sure that timestamps for changes after this run of fc-cache are later diff --git a/fc-lang/fc-lang.c b/fc-lang/fc-lang.c index a2699a3..e302c4a 100644 --- a/fc-lang/fc-lang.c +++ b/fc-lang/fc-lang.c @@ -47,6 +47,12 @@ FcMemFree (int kind, int size) { } +int +FcCacheNextOffset (int fd) +{ + return -1; +} + FcChar8 * FcConfigHome (void) { diff --git a/src/fccache.c b/src/fccache.c index a9d8701..9b92173 100644 --- a/src/fccache.c +++ b/src/fccache.c @@ -22,47 +22,30 @@ * PERFORMANCE OF THIS SOFTWARE. */ +#include +#include +#include #include "fcint.h" -/* - * POSIX has broken stdio so that getc must do thread-safe locking, - * this is a serious performance problem for applications doing large - * amounts of IO with getc (as is done here). If available, use - * the getc_unlocked varient instead. - */ - -#if defined(getc_unlocked) || defined(_IO_getc_unlocked) -#define GETC(f) getc_unlocked(f) -#define PUTC(c,f) putc_unlocked(c,f) -#else -#define GETC(f) getc(f) -#define PUTC(c,f) putc(c,f) -#endif +#define PAGESIZE 8192 -#define FC_DBG_CACHE_REF 1024 +static FcBool force; static FcChar8 * -FcCacheReadString (FILE *f, FcChar8 *dest, int len) +FcCacheReadString (int fd, FcChar8 *dest, int len) { - int c; + FcChar8 c; FcBool escape; - FcChar8 *d; int size; int i; - while ((c = GETC (f)) != EOF) - if (c == '"') - break; - if (c == EOF) - return FcFalse; if (len == 0) return FcFalse; size = len; i = 0; - d = dest; escape = FcFalse; - while ((c = GETC (f)) != EOF) + while (read (fd, &c, 1) == 1) { if (!escape) { @@ -77,260 +60,26 @@ FcCacheReadString (FILE *f, FcChar8 *dest, int len) } if (i == size) { - FcChar8 *new = malloc (size * 2); /* freed in caller */ - if (!new) - break; - memcpy (new, d, size); - size *= 2; - if (d != dest) - free (d); - d = new; + dest[i++] = 0; + return dest; } - d[i++] = c; + dest[i++] = c; if (c == '\0') - return d; + return dest; escape = FcFalse; } - if (d != dest) - free (d); return 0; } static FcBool -FcCacheReadUlong (FILE *f, unsigned long *dest) -{ - unsigned long t; - int c; - - while ((c = GETC (f)) != EOF) - { - if (!isspace (c)) - break; - } - if (c == EOF) - return FcFalse; - t = 0; - for (;;) - { - if (c == EOF || isspace (c)) - break; - if (!isdigit (c)) - return FcFalse; - t = t * 10 + (c - '0'); - c = GETC (f); - } - *dest = t; - return FcTrue; -} - -static FcBool -FcCacheReadInt (FILE *f, int *dest) -{ - unsigned long t; - FcBool ret; - - ret = FcCacheReadUlong (f, &t); - if (ret) - *dest = (int) t; - return ret; -} - -static FcBool -FcCacheReadTime (FILE *f, time_t *dest) -{ - unsigned long t; - FcBool ret; - - ret = FcCacheReadUlong (f, &t); - if (ret) - *dest = (time_t) t; - return ret; -} - -static FcBool -FcCacheWriteChars (FILE *f, const FcChar8 *chars) -{ - FcChar8 c; - while ((c = *chars++)) - { - switch (c) { - case '"': - case '\\': - if (PUTC ('\\', f) == EOF) - return FcFalse; - /* fall through */ - default: - if (PUTC (c, f) == EOF) - return FcFalse; - } - } - return FcTrue; -} - -static FcBool -FcCacheWriteString (FILE *f, const FcChar8 *string) -{ - - if (PUTC ('"', f) == EOF) - return FcFalse; - if (!FcCacheWriteChars (f, string)) - return FcFalse; - if (PUTC ('"', f) == EOF) - return FcFalse; - return FcTrue; -} - -static FcBool -FcCacheWritePath (FILE *f, const FcChar8 *dir, const FcChar8 *file) +FcCacheWriteString (int fd, const FcChar8 *chars) { - if (PUTC ('"', f) == EOF) - return FcFalse; - if (dir) - if (!FcCacheWriteChars (f, dir)) - return FcFalse; -#ifdef _WIN32 - if (dir && - dir[strlen((const char *) dir) - 1] != '/' && - dir[strlen((const char *) dir) - 1] != '\\') - { - if (!FcCacheWriteChars (f, "\\")) - return FcFalse; - } -#else - if (dir && dir[strlen((const char *) dir) - 1] != '/') - if (PUTC ('/', f) == EOF) - return FcFalse; -#endif - if (!FcCacheWriteChars (f, file)) + if (write (fd, chars, strlen(chars)+1) != strlen(chars)+1) return FcFalse; - if (PUTC ('"', f) == EOF) - return FcFalse; - return FcTrue; -} - -static FcBool -FcCacheWriteUlong (FILE *f, unsigned long t) -{ - int pow; - unsigned long temp, digit; - - temp = t; - pow = 1; - while (temp >= 10) - { - temp /= 10; - pow *= 10; - } - temp = t; - while (pow) - { - digit = temp / pow; - if (PUTC ((char) digit + '0', f) == EOF) - return FcFalse; - temp = temp - pow * digit; - pow = pow / 10; - } return FcTrue; } -static FcBool -FcCacheWriteInt (FILE *f, int i) -{ - return FcCacheWriteUlong (f, (unsigned long) i); -} - -static FcBool -FcCacheWriteTime (FILE *f, time_t t) -{ - return FcCacheWriteUlong (f, (unsigned long) t); -} - -static FcBool -FcCacheFontSetAdd (FcFontSet *set, - FcStrSet *dirs, - const FcChar8 *dir, - int dir_len, - const FcChar8 *file, - const FcChar8 *name, - FcConfig *config) -{ - FcChar8 path_buf[8192], *path; - int len; - FcBool ret = FcFalse; - FcPattern *font; - FcPattern *frozen; - - path = path_buf; - len = (dir_len + 1 + strlen ((const char *) file) + 1); - if (len > sizeof (path_buf)) - { - path = malloc (len); /* freed down below */ - if (!path) - return FcFalse; - } - strncpy ((char *) path, (const char *) dir, dir_len); -#ifdef _WIN32 - if (dir[dir_len - 1] != '/' && dir[dir_len - 1] != '\\' ) - path[dir_len++] = '\\'; -#else - if (dir[dir_len - 1] != '/') - path[dir_len++] = '/'; -#endif - strcpy ((char *) path + dir_len, (const char *) file); - if (config && !FcConfigAcceptFilename (config, path)) - ret = FcTrue; - else if (!FcStrCmp (name, FC_FONT_FILE_DIR)) - { - if (FcDebug () & FC_DBG_CACHEV) - printf (" dir cache dir \"%s\"\n", path); - ret = FcStrSetAdd (dirs, path); - } - else if (!FcStrCmp (name, FC_FONT_FILE_INVALID)) - { - ret = FcTrue; - } - else - { - font = FcNameParse (name); - if (font) - { - FcChar8 *family; - - if (FcDebug () & FC_DBG_CACHEV) - printf (" dir cache file \"%s\"\n", file); - ret = FcPatternAddString (font, FC_FILE, path); - /* - * Make sure the pattern has the file name as well as - * already containing at least one family name. - */ - if (ret && - FcPatternGetString (font, FC_FAMILY, 0, &family) == FcResultMatch && - (!config || FcConfigAcceptFont (config, font))) - { - frozen = FcPatternFreeze (font); - ret = (frozen != 0); - if (ret) - ret = FcFontSetAdd (set, frozen); - } - FcPatternDestroy (font); - } - } - if (path != path_buf) free (path); - return ret; - -} - -static unsigned int -FcCacheHash (const FcChar8 *string, int len) -{ - unsigned int h = 0; - FcChar8 c; - - while (len-- && (c = *string++)) - h = (h << 1) ^ c; - return h; -} - +#if 0 /* * Verify the saved timestamp for a file */ @@ -406,328 +155,6 @@ FcFilePathInfoGet (const FcChar8 *path) return i; } -FcGlobalCacheDir * -FcGlobalCacheDirGet (FcGlobalCache *cache, - const FcChar8 *dir, - int len, - FcBool create_missing) -{ - unsigned int hash = FcCacheHash (dir, len); - FcGlobalCacheDir *d, **prev; - - for (prev = &cache->ents[hash % FC_GLOBAL_CACHE_DIR_HASH_SIZE]; - (d = *prev); - prev = &(*prev)->next) - { - if (d->info.hash == hash && d->len == len && - !strncmp ((const char *) d->info.file, - (const char *) dir, len)) - break; - } - if (!(d = *prev)) - { - int i; - if (!create_missing) - return 0; - d = malloc (sizeof (FcGlobalCacheDir) + len + 1); - if (!d) - return 0; - FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + len + 1); - d->next = *prev; - *prev = d; - d->info.hash = hash; - d->info.file = (FcChar8 *) (d + 1); - strncpy ((char *) d->info.file, (const char *) dir, len); - d->info.file[len] = '\0'; - d->info.time = 0; - d->info.referenced = FcFalse; - d->len = len; - for (i = 0; i < FC_GLOBAL_CACHE_FILE_HASH_SIZE; i++) - d->ents[i] = 0; - d->subdirs = 0; - } - return d; -} - -static FcGlobalCacheInfo * -FcGlobalCacheDirAdd (FcGlobalCache *cache, - const FcChar8 *dir, - time_t time, - FcBool replace, - FcBool create_missing) -{ - FcGlobalCacheDir *d; - FcFilePathInfo i; - FcGlobalCacheSubdir *subdir; - FcGlobalCacheDir *parent; - - i = FcFilePathInfoGet (dir); - parent = FcGlobalCacheDirGet (cache, i.dir, i.dir_len, create_missing); - /* - * Tricky here -- directories containing fonts.cache-1 files - * need entries only when the parent doesn't have a cache file. - * That is, when the parent already exists in the cache, is - * referenced and has a "real" timestamp. The time of 0 is - * special and marks directories which got stuck in the - * global cache for this very reason. Yes, it could - * use a separate boolean field, and probably should. - */ - if (!parent || (!create_missing && - (!parent->info.referenced || - (parent->info.time == 0)))) - return 0; - /* - * Add this directory to the cache - */ - d = FcGlobalCacheDirGet (cache, dir, strlen ((const char *) dir), FcTrue); - if (!d) - return 0; - d->info.time = time; - /* - * Add this directory to the subdirectory list of the parent - */ - subdir = malloc (sizeof (FcGlobalCacheSubdir)); - if (!subdir) - return 0; - FcMemAlloc (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir)); - subdir->ent = d; - subdir->next = parent->subdirs; - parent->subdirs = subdir; - return &d->info; -} - -static void -FcGlobalCacheDirDestroy (FcGlobalCacheDir *d) -{ - FcGlobalCacheFile *f, *next; - int h; - FcGlobalCacheSubdir *s, *nexts; - - for (h = 0; h < FC_GLOBAL_CACHE_FILE_HASH_SIZE; h++) - for (f = d->ents[h]; f; f = next) - { - next = f->next; - FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheFile) + - strlen ((char *) f->info.file) + 1 + - strlen ((char *) f->name) + 1); - free (f); - } - for (s = d->subdirs; s; s = nexts) - { - nexts = s->next; - FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheSubdir)); - free (s); - } - FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheDir) + d->len + 1); - free (d); -} - -/* - * If the parent is in the global cache and referenced, add - * an entry for 'dir' to the global cache. This is used - * for directories with fonts.cache files - */ - -void -FcGlobalCacheReferenceSubdir (FcGlobalCache *cache, - const FcChar8 *dir) -{ - FcGlobalCacheInfo *info; - info = FcGlobalCacheDirAdd (cache, dir, 0, FcFalse, FcFalse); - if (info && !info->referenced) - { - info->referenced = FcTrue; - cache->referenced++; - } -} - -/* - * Check to see if the global cache contains valid data for 'dir'. - * If so, scan the global cache for files and directories in 'dir'. - * else, return False. - */ -FcBool -FcGlobalCacheScanDir (FcFontSet *set, - FcStrSet *dirs, - FcGlobalCache *cache, - const FcChar8 *dir, - FcConfig *config) -{ - FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, dir, - strlen ((const char *) dir), - FcFalse); - FcGlobalCacheFile *f; - int h; - int dir_len; - FcGlobalCacheSubdir *subdir; - FcBool any_in_cache = FcFalse; - - if (FcDebug() & FC_DBG_CACHE) - printf ("FcGlobalCacheScanDir %s\n", dir); - - if (!d) - { - if (FcDebug () & FC_DBG_CACHE) - printf ("\tNo dir cache entry\n"); - return FcFalse; - } - - /* - * See if the timestamp recorded in the global cache - * matches the directory time, if not, return False - */ - if (!FcGlobalCacheCheckTime (d->info.file, &d->info)) - { - if (FcDebug () & FC_DBG_CACHE) - printf ("\tdir cache entry time mismatch\n"); - return FcFalse; - } - - /* - * Add files from 'dir' to the fontset - */ - dir_len = strlen ((const char *) dir); - for (h = 0; h < FC_GLOBAL_CACHE_FILE_HASH_SIZE; h++) - for (f = d->ents[h]; f; f = f->next) - { - if (FcDebug() & FC_DBG_CACHEV) - printf ("FcGlobalCacheScanDir add file %s\n", f->info.file); - any_in_cache = FcTrue; - if (!FcCacheFontSetAdd (set, dirs, dir, dir_len, - f->info.file, f->name, config)) - { - cache->broken = FcTrue; - return FcFalse; - } - FcGlobalCacheReferenced (cache, &f->info); - } - /* - * Add directories in 'dir' to 'dirs' - */ - for (subdir = d->subdirs; subdir; subdir = subdir->next) - { - FcFilePathInfo info = FcFilePathInfoGet (subdir->ent->info.file); - - any_in_cache = FcTrue; - if (!FcCacheFontSetAdd (set, dirs, dir, dir_len, - info.base, FC_FONT_FILE_DIR, config)) - { - cache->broken = FcTrue; - return FcFalse; - } - FcGlobalCacheReferenced (cache, &subdir->ent->info); - } - - FcGlobalCacheReferenced (cache, &d->info); - - /* - * To recover from a bug in previous versions of fontconfig, - * return FcFalse if no entries in the cache were found - * for this directory. This will cause any empty directories - * to get rescanned every time fontconfig is initialized. This - * might get removed at some point when the older cache files are - * presumably fixed. - */ - return any_in_cache; -} - -/* - * Locate the cache entry for a particular file - */ -FcGlobalCacheFile * -FcGlobalCacheFileGet (FcGlobalCache *cache, - const FcChar8 *file, - int id, - int *count) -{ - FcFilePathInfo i = FcFilePathInfoGet (file); - FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, i.dir, - i.dir_len, FcFalse); - FcGlobalCacheFile *f, *match = 0; - int max = -1; - - if (!d) - return 0; - for (f = d->ents[i.base_hash % FC_GLOBAL_CACHE_FILE_HASH_SIZE]; f; f = f->next) - { - if (f->info.hash == i.base_hash && - !strcmp ((const char *) f->info.file, (const char *) i.base)) - { - if (f->id == id) - match = f; - if (f->id > max) - max = f->id; - } - } - if (count) - *count = max + 1; - return match; -} - -/* - * Add a file entry to the cache - */ -static FcGlobalCacheInfo * -FcGlobalCacheFileAdd (FcGlobalCache *cache, - const FcChar8 *path, - int id, - time_t time, - const FcChar8 *name, - FcBool replace) -{ - FcFilePathInfo i = FcFilePathInfoGet (path); - FcGlobalCacheDir *d = FcGlobalCacheDirGet (cache, i.dir, - i.dir_len, FcTrue); - FcGlobalCacheFile *f, **prev; - int size; - - if (!d) - return 0; - for (prev = &d->ents[i.base_hash % FC_GLOBAL_CACHE_FILE_HASH_SIZE]; - (f = *prev); - prev = &(*prev)->next) - { - if (f->info.hash == i.base_hash && - f->id == id && - !strcmp ((const char *) f->info.file, (const char *) i.base)) - { - break; - } - } - if (*prev) - { - if (!replace) - return 0; - - f = *prev; - if (f->info.referenced) - cache->referenced--; - *prev = f->next; - FcMemFree (FC_MEM_CACHE, sizeof (FcGlobalCacheFile) + - strlen ((char *) f->info.file) + 1 + - strlen ((char *) f->name) + 1); - free (f); - } - size = (sizeof (FcGlobalCacheFile) + - strlen ((char *) i.base) + 1 + - strlen ((char *) name) + 1); - f = malloc (size); - if (!f) - return 0; - FcMemAlloc (FC_MEM_CACHE, size); - f->next = *prev; - *prev = f; - f->info.hash = i.base_hash; - f->info.file = (FcChar8 *) (f + 1); - f->info.time = time; - f->info.referenced = FcFalse; - f->id = id; - f->name = f->info.file + strlen ((char *) i.base) + 1; - strcpy ((char *) f->info.file, (const char *) i.base); - strcpy ((char *) f->name, (const char *) name); - return &f->info; -} - FcGlobalCache * FcGlobalCacheCreate (void) { @@ -955,218 +382,59 @@ bail1: bail0: return FcFalse; } +#endif -FcBool -FcDirCacheValid (const FcChar8 *dir) +/* + * Find the next presumably-mmapable offset after the current file + * pointer. + */ +int +FcCacheNextOffset(int fd) { - FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE); - struct stat file_stat, dir_stat; + off_t w; + w = lseek(fd, 0, SEEK_END); - if (stat ((char *) dir, &dir_stat) < 0) - { - FcStrFree (cache_file); - return FcFalse; - } - if (stat ((char *) cache_file, &file_stat) < 0) - { - FcStrFree (cache_file); - return FcFalse; - } - FcStrFree (cache_file); - /* - * If the directory has been modified more recently than - * the cache file, the cache is not valid - */ - if (dir_stat.st_mtime - file_stat.st_mtime > 0) - return FcFalse; - return FcTrue; + if (w % PAGESIZE == 0) + return w; + else + return ((w / PAGESIZE)+1)*PAGESIZE; } -FcBool -FcDirCacheReadDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir, FcConfig *config) +/* will go away once we use config->cache */ +#define CACHE_DEFAULT_TMPDIR "/tmp" +#define CACHE_DEFAULT_NAME "/fontconfig-mmap" +static char * +FcCacheFilename(void) { - FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE); - FILE *f; - FcChar8 *base; - int id; - int dir_len; - FcChar8 file_buf[8192], *file; - FcChar8 name_buf[8192], *name; - FcBool ret = FcFalse; + struct utsname b; + static char * name = 0; - if (!cache_file) - goto bail0; - - if (FcDebug () & FC_DBG_CACHE) - printf ("FcDirCacheReadDir cache_file \"%s\"\n", cache_file); - - f = fopen ((char *) cache_file, "r"); - if (!f) - { - if (FcDebug () & FC_DBG_CACHE) - printf (" no cache file\n"); - goto bail1; - } + if (name) + return name; - if (!FcDirCacheValid (dir)) - { - if (FcDebug () & FC_DBG_CACHE) - printf (" cache file older than directory\n"); - goto bail2; - } - - base = (FcChar8 *) strrchr ((char *) cache_file, '/'); - if (!base) - goto bail2; - base++; - dir_len = base - cache_file; - - file = 0; - name = 0; - while ((file = FcCacheReadString (f, file_buf, sizeof (file_buf))) && - FcCacheReadInt (f, &id) && - (name = FcCacheReadString (f, name_buf, sizeof (name_buf)))) + if (uname(&b) == -1) + name = CACHE_DEFAULT_NAME; + else { - if (!FcCacheFontSetAdd (set, dirs, cache_file, dir_len, - file, name, config)) - goto bail3; - if (file != file_buf) - free (file); - if (name != name_buf) - free (name); - file = name = 0; - } - if (FcDebug () & FC_DBG_CACHE) - printf (" cache loaded\n"); - - ret = FcTrue; -bail3: - if (file && file != file_buf) - free (file); - if (name && name != name_buf) - free (name); -bail2: - fclose (f); -bail1: - FcStrFree (cache_file); -bail0: - return ret; -} + char * tmpname = getenv("TMPDIR"); + char * logname = getenv("LOGNAME"); + if (!tmpname) + tmpname = CACHE_DEFAULT_TMPDIR; -/* - * return the path from the directory containing 'cache' to 'file' - */ - -static const FcChar8 * -FcFileBaseName (const FcChar8 *cache, const FcChar8 *file) -{ - const FcChar8 *cache_slash; - - cache_slash = FcStrLastSlash (cache); - if (cache_slash && !strncmp ((const char *) cache, (const char *) file, - (cache_slash + 1) - cache)) - return file + ((cache_slash + 1) - cache); - return file; -} - -FcBool -FcDirCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir) -{ - FcChar8 *cache_file = FcStrPlus (dir, (FcChar8 *) "/" FC_DIR_CACHE_FILE); - FcPattern *font; - FILE *f; - FcChar8 *name; - const FcChar8 *file, *base; - int n; - int id; - FcBool ret; - FcStrList *list; - - if (!cache_file) - goto bail0; - if (FcDebug () & FC_DBG_CACHE) - printf ("FcDirCacheWriteDir cache_file \"%s\"\n", cache_file); - - f = fopen ((char *) cache_file, "w"); - if (!f) - { - if (FcDebug () & FC_DBG_CACHE) - printf (" can't create \"%s\"\n", cache_file); - goto bail1; - } - - list = FcStrListCreate (dirs); - if (!list) - goto bail2; - - while ((dir = FcStrListNext (list))) - { - base = FcFileBaseName (cache_file, dir); - if (!FcCacheWriteString (f, base)) - goto bail3; - if (PUTC (' ', f) == EOF) - goto bail3; - if (!FcCacheWriteInt (f, 0)) - goto bail3; - if (PUTC (' ', f) == EOF) - goto bail3; - if (!FcCacheWriteString (f, FC_FONT_FILE_DIR)) - goto bail3; - if (PUTC ('\n', f) == EOF) - goto bail3; + name = malloc(strlen(CACHE_DEFAULT_NAME) + + strlen(tmpname) + + (logname ? strlen(logname) : 0) + 5); + strcpy(name, tmpname); + strcat(name, CACHE_DEFAULT_NAME); + strcat(name, "-"); + strcat(name, logname ? logname : ""); } - - for (n = 0; n < set->nfont; n++) - { - font = set->fonts[n]; - if (FcPatternGetString (font, FC_FILE, 0, (FcChar8 **) &file) != FcResultMatch) - goto bail3; - base = FcFileBaseName (cache_file, file); - if (FcPatternGetInteger (font, FC_INDEX, 0, &id) != FcResultMatch) - goto bail3; - if (FcDebug () & FC_DBG_CACHEV) - printf (" write file \"%s\"\n", base); - if (!FcCacheWriteString (f, base)) - goto bail3; - if (PUTC (' ', f) == EOF) - goto bail3; - if (!FcCacheWriteInt (f, id)) - goto bail3; - if (PUTC (' ', f) == EOF) - goto bail3; - name = FcNameUnparse (font); - if (!name) - goto bail3; - ret = FcCacheWriteString (f, name); - FcStrFree (name); - if (!ret) - goto bail3; - if (PUTC ('\n', f) == EOF) - goto bail3; - } - - FcStrListDone (list); - - if (fclose (f) == EOF) - goto bail1; - - FcStrFree (cache_file); - - if (FcDebug () & FC_DBG_CACHE) - printf (" cache written\n"); - return FcTrue; - -bail3: - FcStrListDone (list); -bail2: - fclose (f); -bail1: - unlink ((char *) cache_file); - FcStrFree (cache_file); -bail0: - return FcFalse; + return name; } +/* + * Wipe out static state. + */ void FcCacheClearStatic() { @@ -1179,6 +447,9 @@ FcCacheClearStatic() FcLangSetClearStatic(); } +/* + * Trigger the counting phase: this tells us how much to allocate. + */ FcBool FcCachePrepareSerialize (FcConfig * config) { @@ -1189,6 +460,7 @@ FcCachePrepareSerialize (FcConfig * config) return FcTrue; } +/* allocate and populate static structures */ FcBool FcCacheSerialize (FcConfig * config) { @@ -1198,3 +470,238 @@ FcCacheSerialize (FcConfig * config) return FcFalse; return FcTrue; } + +/* get the current arch name */ +/* caller is responsible for freeing returned pointer */ +static char * +FcCacheGetCurrentArch (void) +{ + struct utsname b; + char * current_arch_machine_name; + + if (uname(&b) == -1) + return FcFalse; + current_arch_machine_name = strdup(b.machine); + /* if (getenv ("FAKE_ARCH")) // testing purposes + current_arch_machine_name = strdup(getenv("FAKE_ARCH")); */ + return current_arch_machine_name; +} + +/* return the address of the segment for the provided arch, + * or -1 if arch not found */ +static off_t +FcCacheSkipToArch (int fd, const char * arch) +{ + char candidate_arch_machine_name[64], bytes_to_skip[7]; + off_t current_arch_start = 0; + + /* skip arches that are not the current arch */ + while (1) + { + long bs; + + lseek (fd, current_arch_start, SEEK_SET); + if (FcCacheReadString (fd, candidate_arch_machine_name, + sizeof (candidate_arch_machine_name)) == 0) + break; + if (FcCacheReadString (fd, bytes_to_skip, 7) == 0) + break; + bs = a64l(bytes_to_skip); + if (bs == 0) + break; + + if (strcmp (candidate_arch_machine_name, arch)==0) + break; + current_arch_start += bs; + } + + if (strcmp (candidate_arch_machine_name, arch)!=0) + return -1; + + return current_arch_start; +} + +/* Cuts out the segment at the file pointer (moves everything else + * down to cover it), and leaves the file pointer at the end of the + * file. */ +#define BUF_SIZE 8192 + +static FcBool +FcCacheMoveDown (int fd, off_t start) +{ + char * buf = malloc (BUF_SIZE); + char candidate_arch_machine_name[64], bytes_to_skip[7]; + long bs; off_t pos; + int c, bytes_skipped; + + if (!buf) + return FcFalse; + + lseek (fd, start, SEEK_SET); + if (FcCacheReadString (fd, candidate_arch_machine_name, + sizeof (candidate_arch_machine_name)) == 0) + goto done; + if (FcCacheReadString (fd, bytes_to_skip, 7) == 0) + goto done; + + bs = a64l(bytes_to_skip); + if (bs == 0) + goto done; + + bytes_skipped = 0; + do + { + lseek (fd, start+bs+bytes_skipped, SEEK_SET); + if ((c = read (fd, buf, BUF_SIZE)) <= 0) + break; + lseek (fd, start+bytes_skipped, SEEK_SET); + if (write (fd, buf, c) < 0) + goto bail; + bytes_skipped += c; + } + while (c > 0); + lseek (fd, start+bytes_skipped, SEEK_SET); + + done: + free (buf); + return FcTrue; + + bail: + free (buf); + return FcFalse; +} + +/* read serialized state from the cache file */ +FcBool +FcCacheRead (FcConfig *config) +{ + int fd, i; + FcCache metadata; + char * current_arch_machine_name; + char candidate_arch_machine_name[64], bytes_in_block[7]; + off_t current_arch_start = 0; + + if (force) + return FcFalse; + + fd = open(FcCacheFilename(), O_RDONLY); + if (fd == -1) + return FcFalse; + + current_arch_machine_name = FcCacheGetCurrentArch(); + current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name); + if (current_arch_start < 0) + goto bail; + + lseek (fd, current_arch_start, SEEK_SET); + if (FcCacheReadString (fd, candidate_arch_machine_name, + sizeof (candidate_arch_machine_name)) == 0) + goto bail; + if (FcCacheReadString (fd, bytes_in_block, 7) == 0) + goto bail; + + // sanity check for endianness issues + read(fd, &metadata, sizeof(FcCache)); + if (metadata.magic != FC_CACHE_MAGIC) + goto bail; + + if (!FcObjectRead(fd, metadata)) goto bail1; + if (!FcStrSetRead(fd, metadata)) goto bail1; + if (!FcCharSetRead(fd, metadata)) goto bail1; + if (!FcMatrixRead(fd, metadata)) goto bail1; + if (!FcLangSetRead(fd, metadata)) goto bail1; + if (!FcValueListRead(fd, metadata)) goto bail1; + if (!FcPatternEltRead(fd, metadata)) goto bail1; + if (!FcPatternRead(fd, metadata)) goto bail1; + if (!FcFontSetRead(fd, config, metadata)) goto bail1; + close(fd); + free (current_arch_machine_name); + return FcTrue; + + bail1: + for (i = FcSetSystem; i <= FcSetApplication; i++) + config->fonts[i] = 0; + close(fd); + bail: + free (current_arch_machine_name); + return FcFalse; +} + +/* write serialized state to the cache file */ +FcBool +FcCacheWrite (FcConfig * config) +{ + int fd; + FcCache metadata; + off_t current_arch_start = 0, truncate_to; + char * current_arch_machine_name, bytes_written[7] = "dedbef"; + + if (!FcCachePrepareSerialize (config)) + return FcFalse; + + if (!FcCacheSerialize (config)) + return FcFalse; + + fd = open(FcCacheFilename(), O_RDWR | O_CREAT, 0666); + if (fd == -1) + return FcFalse; + + current_arch_machine_name = FcCacheGetCurrentArch(); + current_arch_start = FcCacheSkipToArch(fd, current_arch_machine_name); + if (current_arch_start < 0) + current_arch_start = FcCacheNextOffset (fd); + + if (!FcCacheMoveDown(fd, current_arch_start)) + goto bail; + + current_arch_start = lseek(fd, 0, SEEK_CUR); + if (ftruncate (fd, current_arch_start) == -1) + goto bail; + + /* reserve space for arch, count & metadata */ + if (!FcCacheWriteString (fd, current_arch_machine_name)) + goto bail; + if (!FcCacheWriteString (fd, bytes_written)) + goto bail; + memset (&metadata, 0, sizeof(FcCache)); + metadata.magic = FC_CACHE_MAGIC; + write(fd, &metadata, sizeof(FcCache)); + + if (!FcFontSetWrite(fd, config, &metadata)) goto bail; + if (!FcPatternWrite(fd, &metadata)) goto bail; + if (!FcPatternEltWrite(fd, &metadata)) goto bail; + if (!FcValueListWrite(fd, &metadata)) goto bail; + if (!FcLangSetWrite(fd, &metadata)) goto bail; + if (!FcCharSetWrite(fd, &metadata)) goto bail; + if (!FcMatrixWrite(fd, &metadata)) goto bail; + if (!FcStrSetWrite(fd, &metadata)) goto bail; + if (!FcObjectWrite(fd, &metadata)) goto bail; + + /* now write the address of the next offset */ + truncate_to = FcCacheNextOffset(fd) - current_arch_start; + lseek(fd, current_arch_start + strlen(current_arch_machine_name)+1, + SEEK_SET); + strcpy (bytes_written, l64a(truncate_to)); + if (!FcCacheWriteString (fd, bytes_written)) + goto bail; + + /* now rewrite metadata & truncate file */ + if (write(fd, &metadata, sizeof(FcCache)) != sizeof (FcCache)) + goto bail; + if (ftruncate (fd, current_arch_start + truncate_to) == -1) + goto bail; + + close(fd); + return FcTrue; + + bail: + free (current_arch_machine_name); + return FcFalse; +} + +/* if true, ignore the cache file */ +void +FcCacheForce (FcBool f) +{ + force = f; +} diff --git a/src/fccfg.c b/src/fccfg.c index 7be4cdd..a5de075 100644 --- a/src/fccfg.c +++ b/src/fccfg.c @@ -252,16 +252,22 @@ FcConfigBuildFonts (FcConfig *config) FcStrList *list; FcChar8 *dir; +#if 0 + if (config->cache) + FcGlobalCacheLoad (cache, config->cache); +#endif + if (config->fonts[FcSetSystem]) + return FcTrue; + fonts = FcFontSetCreate (); if (!fonts) goto bail0; - + +#if 0 cache = FcGlobalCacheCreate (); if (!cache) goto bail1; - - if (config->cache) - FcGlobalCacheLoad (cache, config->cache); +#endif list = FcConfigGetFontDirs (config); if (!list) @@ -280,9 +286,11 @@ FcConfigBuildFonts (FcConfig *config) if (FcDebug () & FC_DBG_FONTSET) FcFontSetPrint (fonts); +#if 0 if (config->cache) FcGlobalCacheSave (cache, config->cache); FcGlobalCacheDestroy (cache); +#endif FcConfigSetFonts (config, fonts, FcSetSystem); diff --git a/src/fccharset.c b/src/fccharset.c index 6c6f0f5..00b2010 100644 --- a/src/fccharset.c +++ b/src/fccharset.c @@ -23,6 +23,7 @@ */ #include +#include #include "fcint.h" /* #define CHECK */ @@ -383,6 +384,14 @@ FcCharSetCopy (FcCharSet *src) return src; } +FcCharSetPtr +FcCharSetCopyPtr (FcCharSetPtr src) +{ + if (FcCharSetPtrU(src)->ref != FC_REF_CONSTANT) + FcCharSetPtrU(src)->ref++; + return src; +} + FcBool FcCharSetEqual (const FcCharSet *a, const FcCharSet *b) { @@ -1369,10 +1378,11 @@ FcCharSetSerialize(FcCharSet *c) if (!leaf_idx) goto bail3; } - new.ref = c->ref; + new.ref = FC_REF_CONSTANT; new.storage = FcStorageStatic; - new.u.stat.leafidx_offset = charset_leaf_ptr; + new.u.stat.leafidx_offset = charset_leaf_idx_ptr; new.u.stat.numbers_offset = charset_numbers_ptr; + new.num = c->num; newp.storage = FcStorageStatic; newp.u.stat = charset_ptr; @@ -1398,6 +1408,95 @@ FcCharSetSerialize(FcCharSet *c) return FcCharSetPtrCreateDynamic(0); } +FcBool +FcCharSetRead (int fd, FcCache metadata) +{ + charsets = mmap(NULL, + metadata.charsets_length * sizeof (FcCharSet), + PROT_READ, + MAP_SHARED, fd, metadata.charsets_offset); + if (charsets == MAP_FAILED) + goto bail; + charset_count = charset_ptr = metadata.charsets_length; + + leaves = mmap(NULL, + metadata.charset_num_sum * sizeof (FcCharLeaf), + PROT_READ, + MAP_SHARED, fd, metadata.charset_leaf_offset); + if (leaves == MAP_FAILED) + goto bail1; + charset_leaf_count = charset_leaf_ptr = metadata.charset_num_sum; + + leaf_idx = mmap(NULL, + metadata.charsets_length * sizeof (FcCharLeaf*), + PROT_READ, + MAP_SHARED, fd, metadata.charset_leafidx_offset); + if (leaf_idx == MAP_FAILED) + goto bail2; + charset_leaf_idx_count = charset_leaf_idx_ptr = metadata.charsets_length; + + numbers = mmap(NULL, + metadata.charset_num_sum * sizeof (FcChar16), + PROT_READ, + MAP_SHARED, fd, metadata.charset_numbers_offset); + if (numbers == MAP_FAILED) + goto bail3; + charset_numbers_count = charset_numbers_ptr = metadata.charset_num_sum; + + return FcTrue; + + bail3: + munmap (leaf_idx, metadata.charsets_length * sizeof (FcCharLeaf*)); + bail2: + munmap (leaves, metadata.charset_num_sum * sizeof (FcCharLeaf)); + bail1: + munmap (charsets, metadata.charsets_length * sizeof (FcCharSet)); + bail: + return FcFalse; +} + +FcBool +FcCharSetWrite (int fd, FcCache *metadata) +{ + metadata->charsets_length = charset_ptr; + metadata->charsets_offset = FcCacheNextOffset(fd); + + if (charset_ptr > 0) + { + lseek (fd, metadata->charsets_offset, SEEK_SET); + if (write (fd, charsets, charset_ptr * sizeof(FcCharSet)) == -1) + return FcFalse; + } + + metadata->charset_leaf_offset = FcCacheNextOffset(fd); + metadata->charset_num_sum = charset_leaf_ptr; + if (charset_leaf_ptr > 0) + { + lseek (fd, metadata->charset_leaf_offset, SEEK_SET); + if (write (fd, leaves, charset_leaf_ptr * sizeof(FcCharLeaf)) == -1) + return FcFalse; + } + + metadata->charset_leafidx_offset = FcCacheNextOffset(fd); + if (charset_leaf_idx_ptr > 0) + { + lseek (fd, metadata->charset_leafidx_offset, SEEK_SET); + if (write (fd, leaf_idx, charset_leaf_idx_ptr * sizeof(FcCharLeaf*)) == -1) + return FcFalse; + } + + + metadata->charset_numbers_offset = FcCacheNextOffset(fd); + if (charset_leaf_ptr > 0) + { + lseek (fd, metadata->charset_numbers_offset, SEEK_SET); + if (write (fd, numbers, charset_leaf_ptr * sizeof(FcChar16)) == -1) + return FcFalse; + } + + return FcTrue; +} + FcCharLeaf * FcCharSetGetLeaf(const FcCharSet *c, int i) { diff --git a/src/fcdir.c b/src/fcdir.c index 974886d..595e22a 100644 --- a/src/fcdir.c +++ b/src/fcdir.c @@ -45,13 +45,15 @@ FcFileScanConfig (FcFontSet *set, FcConfig *config) { int id; +#if 0 FcChar8 *name; + FcGlobalCacheFile *cache_file; + FcGlobalCacheDir *cache_dir; +#endif FcPattern *font; FcBool ret = FcTrue; FcBool isDir; int count = 0; - FcGlobalCacheFile *cache_file; - FcGlobalCacheDir *cache_dir; FcBool need_scan; if (config && !FcConfigAcceptFilename (config, file)) @@ -64,6 +66,7 @@ FcFileScanConfig (FcFontSet *set, { need_scan = FcTrue; font = 0; +#if 0 /* * Check the cache */ @@ -104,6 +107,7 @@ FcFileScanConfig (FcFontSet *set, } } } +#endif /* * Nothing in the cache, scan the file */ @@ -123,6 +127,7 @@ FcFileScanConfig (FcFontSet *set, isDir = FcTrue; ret = FcStrSetAdd (dirs, file); } +#if 0 /* * Update the cache */ @@ -137,6 +142,7 @@ FcFileScanConfig (FcFontSet *set, FcStrFree (unparse); } } +#endif } /* * Add the font @@ -193,6 +199,7 @@ FcDirScanConfig (FcFontSet *set, if (!force) { +#if 0 /* * Check fonts.cache- file */ @@ -208,6 +215,7 @@ FcDirScanConfig (FcFontSet *set, */ if (cache && FcGlobalCacheScanDir (set, dirs, cache, dir, config)) return FcTrue; +#endif } /* freed below */ @@ -246,8 +254,10 @@ FcDirScanConfig (FcFontSet *set, * Now that the directory has been scanned, * add the cache entry */ +#if 0 if (ret && cache) FcGlobalCacheUpdate (cache, dir, 0, 0); +#endif return ret; } @@ -266,5 +276,8 @@ FcDirScan (FcFontSet *set, FcBool FcDirSave (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir) { +#if 0 return FcDirCacheWriteDir (set, dirs, dir); +#endif + return FcTrue; } diff --git a/src/fcfs.c b/src/fcfs.c index c202040..f362e2b 100644 --- a/src/fcfs.c +++ b/src/fcfs.c @@ -116,3 +116,98 @@ FcFontSetClearStatic (void) { FcPatternClearStatic(); } + +FcBool +FcFontSetRead(int fd, FcConfig * config, FcCache metadata) +{ + int i, mz, j; + FcPattern * buf; + + lseek(fd, metadata.fontsets_offset, SEEK_SET); + for (i = FcSetSystem; i <= FcSetApplication; i++) + { + if (config->fonts[i]) + { + if (config->fonts[i]->nfont > 0 && config->fonts[i]->fonts) + free (config->fonts[i]->fonts); + free (config->fonts[i]); + } + } + + for (i = FcSetSystem; i <= FcSetApplication; i++) + { + read(fd, &mz, sizeof(int)); + if (mz != FC_CACHE_MAGIC) + continue; + + config->fonts[i] = malloc(sizeof(FcFontSet)); + if (!config->fonts[i]) + return FcFalse; + FcMemAlloc(FC_MEM_FONTSET, sizeof(FcFontSet)); + + if (read(fd, config->fonts[i], sizeof(FcFontSet)) == -1) + goto bail; + if (config->fonts[i]->sfont > 0) + { + config->fonts[i]->fonts = malloc + (config->fonts[i]->sfont*sizeof(FcPattern *)); + buf = malloc (config->fonts[i]->sfont * sizeof(FcPattern)); + if (!config->fonts[i]->fonts || !buf) + goto bail; + for (j = 0; j < config->fonts[i]->nfont; j++) + { + config->fonts[i]->fonts[j] = buf+j; + if (read(fd, buf+j, sizeof(FcPattern)) == -1) + goto bail; + } + } + } + + return FcTrue; + bail: + for (i = FcSetSystem; i <= FcSetApplication; i++) + { + if (config->fonts[i]) + { + if (config->fonts[i]->fonts) + free (config->fonts[i]->fonts); + free(config->fonts[i]); + } + config->fonts[i] = 0; + } + return FcFalse; +} + +FcBool +FcFontSetWrite(int fd, FcConfig * config, FcCache * metadata) +{ + int c, t, i, j; + int m = FC_CACHE_MAGIC, z = 0; + + metadata->fontsets_offset = FcCacheNextOffset(fd); + lseek(fd, metadata->fontsets_offset, SEEK_SET); + for (i = FcSetSystem; i <= FcSetApplication; i++) + { + if (!config->fonts[i]) + { + write(fd, &z, sizeof(int)); + continue; + } + else + write(fd, &m, sizeof(int)); + + if ((c = write(fd, config->fonts[i], sizeof(FcFontSet))) == -1) + return FcFalse; + t = c; + if (config->fonts[i]->nfont > 0) + { + for (j = 0; j < config->fonts[i]->nfont; j++) + { + if ((c = write(fd, config->fonts[i]->fonts[j], + sizeof(FcPattern))) == -1) + return FcFalse; + } + } + } + return FcTrue; +} diff --git a/src/fcinit.c b/src/fcinit.c index 8a9bdbd..9c51c28 100644 --- a/src/fcinit.c +++ b/src/fcinit.c @@ -61,6 +61,9 @@ FcInitLoadConfig (void) if (!config) return FcFalse; + if (!FcCacheRead(config)) + FcCacheForce(FcTrue); + if (!FcConfigParseAndLoad (config, 0, FcTrue)) { FcConfigDestroy (config); diff --git a/src/fcint.h b/src/fcint.h index f29b459..992c09f 100644 --- a/src/fcint.h +++ b/src/fcint.h @@ -259,6 +259,25 @@ typedef struct _FcStrBuf { int size; } FcStrBuf; +typedef struct _FcCache { + int magic; + off_t fontsets_offset; + off_t pattern_offset; int pattern_length; + off_t patternelt_offset; int patternelt_length; + off_t valuelist_offset; int valuelist_length; + off_t object_offset; int object_length; + off_t objectcontent_offset; int objectcontent_length; + off_t langsets_offset; int langsets_length; + off_t charsets_offset; int charsets_length; + off_t charset_leaf_offset; int charset_num_sum; + off_t charset_leafidx_offset; + off_t charset_numbers_offset; + off_t matrices_offset; int matrices_length; + off_t strsets_offset; int strsets_length; + off_t strsets_idx_offset; int strsets_idx_length; + off_t strset_buf_offset; int strset_buf_length; +} FcCache; + /* * To map adobe glyph names to unicode values, a precomputed hash * table is used @@ -312,6 +331,7 @@ typedef struct _FcCaseFold { * cache which is then rewritten to the users home directory */ +#define FC_CACHE_MAGIC 0x12345678 #define FC_GLOBAL_CACHE_DIR_HASH_SIZE 37 #define FC_GLOBAL_CACHE_FILE_HASH_SIZE 67 @@ -429,66 +449,27 @@ typedef struct _FcCharMap FcCharMap; /* fccache.c */ -FcGlobalCache * -FcGlobalCacheCreate (void); - -void -FcGlobalCacheDestroy (FcGlobalCache *cache); - -FcBool -FcGlobalCacheCheckTime (const FcChar8*file, FcGlobalCacheInfo *info); +int +FcCacheNextOffset(int fd); void -FcGlobalCacheReferenced (FcGlobalCache *cache, - FcGlobalCacheInfo *info); +FcCacheForce(FcBool force); void -FcGlobalCacheReferenceSubdir (FcGlobalCache *cache, - const FcChar8 *dir); - -FcGlobalCacheDir * -FcGlobalCacheDirGet (FcGlobalCache *cache, - const FcChar8 *dir, - int len, - FcBool create_missing); - -FcBool -FcGlobalCacheScanDir (FcFontSet *set, - FcStrSet *dirs, - FcGlobalCache *cache, - const FcChar8 *dir, - FcConfig *config); - -FcGlobalCacheFile * -FcGlobalCacheFileGet (FcGlobalCache *cache, - const FcChar8 *file, - int id, - int *count); - - -void -FcGlobalCacheLoad (FcGlobalCache *cache, - const FcChar8 *cache_file); +FcCacheClearStatic(void); FcBool -FcGlobalCacheUpdate (FcGlobalCache *cache, - const FcChar8 *file, - int id, - const FcChar8 *name); +FcCachePrepareSerialize(FcConfig * config); FcBool -FcGlobalCacheSave (FcGlobalCache *cache, - const FcChar8 *cache_file); +FcCacheSerialize (FcConfig * config); FcBool -FcDirCacheReadDir (FcFontSet *set, - FcStrSet *dirs, - const FcChar8 *dir, - FcConfig *config); +FcCacheRead (FcConfig *config); FcBool -FcDirCacheWriteDir (FcFontSet *set, FcStrSet *dirs, const FcChar8 *dir); - +FcCacheWrite (FcConfig * config); + /* fccfg.c */ FcBool @@ -553,6 +534,9 @@ FcConfigAcceptFont (FcConfig *config, FcCharSet * FcCharSetFreeze (FcCharSet *cs); +FcCharSetPtr +FcCharSetCopyPtr (FcCharSetPtr src); + void FcCharSetThawAll (void); @@ -586,6 +570,12 @@ FcCharSetGetLeaf(const FcCharSet *c, int i); FcChar16 * FcCharSetGetNumbers(const FcCharSet *c); +FcBool +FcCharSetRead (int fd, FcCache metadata); + +FcBool +FcCharSetWrite (int fd, FcCache *metadata); + /* fcdbg.c */ void FcValueListPrint (const FcValueListPtr l); @@ -668,6 +658,12 @@ FcFontSetPrepareSerialize (FcFontSet * s); FcBool FcFontSetSerialize (FcFontSet * s); +FcBool +FcFontSetRead(int fd, FcConfig * config, FcCache metadata); + +FcBool +FcFontSetWrite(int fd, FcConfig * config, FcCache * metadata); + /* fcgram.y */ int FcConfigparse (void); @@ -766,6 +762,12 @@ FcLangSetPtrCreateDynamic (FcLangSet *l); void FcLangSetPtrDestroy (FcLangSetPtr li); +FcBool +FcLangSetRead (int fd, FcCache metadata); + +FcBool +FcLangSetWrite (int fd, FcCache *metadata); + /* fclist.c */ FcBool @@ -774,18 +776,6 @@ FcListPatternMatchAny (const FcPattern *p, /* fcmatch.c */ -/* fcmmap.c */ - -void -FcCacheClearStatic(void); - -FcBool -FcCachePrepareSerialize(FcConfig * config); - -FcBool -FcCacheSerialize (FcConfig * config); - - /* fcname.c */ FcBool @@ -824,7 +814,10 @@ FcObjectPtr FcObjectStaticName (const char *name); FcBool -FcObjectPrepareSerialize (FcObjectPtr si); +FcObjectRead (int fd, FcCache metadata); + +FcBool +FcObjectWrite (int fd, FcCache * metadata); const char * FcObjectPtrU (FcObjectPtr p); @@ -832,9 +825,6 @@ FcObjectPtrU (FcObjectPtr p); int FcObjectPtrCompare (FcObjectPtr a, FcObjectPtr b); -FcObjectPtr -FcObjectPtrCreateDynamic (const char * s); - void FcObjectPtrDestroy (FcObjectPtr p); @@ -865,6 +855,24 @@ FcValueListSerialize(FcValueList *pi); FcPattern * FcPatternSerialize (FcPattern * p); +FcBool +FcPatternRead (int fd, FcCache metadata); + +FcBool +FcPatternWrite (int fd, FcCache *metadata); + +FcBool +FcPatternEltRead (int fd, FcCache metadata); + +FcBool +FcPatternEltWrite (int fd, FcCache *metadata); + +FcBool +FcValueListRead (int fd, FcCache metadata); + +FcBool +FcValueListWrite (int fd, FcCache *metadata); + /* fcrender.c */ /* fcmatrix.c */ @@ -892,6 +900,12 @@ FcMatrixPtrCreateDynamic (FcMatrix *m); void FcMatrixClearStatic (void); +FcBool +FcMatrixWrite (int fd, FcCache *metadata); + +FcBool +FcMatrixRead (int fd, FcCache metadata); + /* fcstr.c */ FcStrSet * FcStrSetPtrU (const FcStrSetPtr set); @@ -938,6 +952,12 @@ FcStrBufData (FcStrBuf *buf, const FcChar8 *s, int len); FcStrSetPtr FcStrSetSerialize (FcStrSet *set); +FcBool +FcStrSetRead (int fd, FcCache metadata); + +FcBool +FcStrSetWrite (int fd, FcCache *metadata); + int FcStrCmpIgnoreBlanksAndCase (const FcChar8 *s1, const FcChar8 *s2); diff --git a/src/fclang.c b/src/fclang.c index 28b2d9b..515e3cf 100644 --- a/src/fclang.c +++ b/src/fclang.c @@ -774,3 +774,31 @@ FcLangSetSerialize(FcLangSet *l) new.u.stat = p; return new; } + +FcBool +FcLangSetWrite (int fd, FcCache *metadata) +{ + metadata->langsets_length = langset_ptr; + metadata->langsets_offset = FcCacheNextOffset(fd); + + if (langset_ptr > 0) + { + lseek (fd, metadata->langsets_offset, SEEK_SET); + return write(fd, langsets, + metadata->langsets_length * sizeof(FcLangSet)) != -1; + } + return FcTrue; +} + +FcBool +FcLangSetRead (int fd, FcCache metadata) +{ + langsets = mmap(NULL, + metadata.langsets_length * sizeof (FcLangSet), + PROT_READ, + MAP_SHARED, fd, metadata.langsets_offset); + if (langsets == MAP_FAILED) + return FcFalse; + langset_count = langset_ptr = metadata.langsets_length; + return FcTrue; +} diff --git a/src/fcmatrix.c b/src/fcmatrix.c index 6a5aa5d..9b69bc9 100644 --- a/src/fcmatrix.c +++ b/src/fcmatrix.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "fcint.h" FcMatrix _id = { 1, 0, 0, 1 }; @@ -182,3 +183,31 @@ FcMatrixSerialize(FcMatrix *m) return new; } +FcBool +FcMatrixRead (int fd, FcCache metadata) +{ + matrices = mmap(NULL, + metadata.matrices_length * sizeof (FcMatrix), + PROT_READ, + MAP_SHARED, fd, metadata.matrices_offset); + if (matrices == MAP_FAILED) + return FcFalse; + + matrix_count = matrix_ptr = metadata.matrices_length; + return FcTrue; +} + +FcBool +FcMatrixWrite (int fd, FcCache *metadata) +{ + metadata->matrices_length = matrix_ptr; + metadata->matrices_offset = FcCacheNextOffset(fd); + + if (matrix_ptr > 0) + { + lseek(fd, metadata->matrices_offset, SEEK_SET); + return write(fd, matrices, + metadata->matrices_length * sizeof(FcMatrix)) != -1; + } + return FcTrue; +} diff --git a/src/fcpat.c b/src/fcpat.c index 0633c5a..956ed66 100644 --- a/src/fcpat.c +++ b/src/fcpat.c @@ -94,8 +94,7 @@ FcValueSave (FcValue v) v.type = FcTypeVoid; break; case FcTypeCharSet: - v.u.ci = FcCharSetPtrCreateDynamic - (FcCharSetCopy (FcCharSetPtrU(v.u.ci))); + v.u.ci = FcCharSetCopyPtr (v.u.ci); if (!FcCharSetPtrU(v.u.ci)) v.type = FcTypeVoid; break; @@ -1270,7 +1269,6 @@ FcPatternEltU (FcPatternEltPtr pei) switch (pei.storage) { case FcStorageStatic: - if (pei.u.stat == 0) return 0; return &fcpatternelts[pei.u.stat]; case FcStorageDynamic: return pei.u.dyn; @@ -1324,6 +1322,8 @@ FcValueListClearStatic (void) fcvaluelist_count = 0; } +static FcBool +FcObjectPrepareSerialize (FcObjectPtr si); static FcObjectPtr FcObjectSerialize (FcObjectPtr si); @@ -1408,13 +1408,14 @@ FcPatternSerialize (FcPattern *old) fcpatternelt_ptr = 0; } - p = FcPatternCreate(); + p = &fcpatterns[fcpattern_ptr++]; elts = fcpatternelt_ptr; nep = &fcpatternelts[elts]; if (!nep) return FcFalse; + fcpatternelt_ptr += old->num; - + for (e = FcPatternEltU(old->elts), i=0; i < old->num; i++, e++) { v = e->values; @@ -1438,12 +1439,13 @@ FcPatternSerialize (FcPattern *old) } nep[i].values = nv_head; - nep[i].object = FcObjectSerialize - (FcObjectStaticName(FcObjectPtrU(e->object))); + nep[i].object = FcObjectSerialize (e->object); } - + + p->elts = old->elts; p->elts = FcPatternEltPtrCreateStatic(elts); p->size = old->num; + p->num = old->num; p->ref = FC_REF_CONSTANT; return p; @@ -1453,7 +1455,69 @@ FcPatternSerialize (FcPattern *old) free (fcpatterns); bail: return 0; - } +} + +FcBool +FcPatternRead (int fd, FcCache metadata) +{ + fcpatterns = mmap(NULL, + metadata.pattern_length * sizeof (FcPattern), + PROT_READ, + MAP_SHARED, fd, metadata.pattern_offset); + if (fcpatterns == MAP_FAILED) + return FcFalse; + fcpattern_count = fcpattern_ptr = metadata.pattern_length; + + return FcTrue; +} + +FcBool +FcPatternWrite (int fd, FcCache *metadata) +{ + int c = fcpattern_ptr; + off_t w = FcCacheNextOffset(fd); + + metadata->pattern_offset = w; + metadata->pattern_length = c; + + if (c > 0) + { + lseek(fd, w, SEEK_SET); + return write(fd, fcpatterns, c*sizeof(FcPattern)) != -1; + } + return FcTrue; +} + +FcBool +FcPatternEltRead (int fd, FcCache metadata) +{ + fcpatternelts = mmap(NULL, + metadata.patternelt_length * sizeof (FcPatternElt), + PROT_READ, + MAP_SHARED, fd, metadata.patternelt_offset); + if (fcpatternelts == MAP_FAILED) + return FcFalse; + fcpatternelt_count = fcpatternelt_ptr = metadata.patternelt_length; + + return FcTrue; +} + +FcBool +FcPatternEltWrite (int fd, FcCache *metadata) +{ + int c = fcpatternelt_ptr; + off_t w = FcCacheNextOffset(fd); + + metadata->patternelt_offset = w; + metadata->patternelt_length = c; + + if (c > 0) + { + lseek(fd, w, SEEK_SET); + return write(fd, fcpatternelts, c*sizeof(FcPatternElt)) != -1; + } + return FcTrue; +} FcValueListPtr FcValueListSerialize(FcValueList *pi) @@ -1480,13 +1544,18 @@ FcValueListSerialize(FcValueList *pi) switch (v->type) { case FcTypeString: - if (FcObjectPtrU(v->u.si)) + /* this departs from the usual convention of dereferencing + * foo before serialization; FcObjectSerialize does the + * translation itself. */ + /* also, v->u.si is 0 iff the string is null. */ + /* also, have to update the old pi */ + if (v->u.si) { - FcObjectPtr si = - FcObjectSerialize(FcObjectStaticName(FcObjectPtrU(v->u.si))); - if (!FcObjectPtrU(v->u.si)) + FcObjectPtr si = FcObjectSerialize(v->u.si); + if (!FcObjectPtrU(si)) return FcValueListPtrCreateDynamic(pi); v->u.si = si; + pi->value.u.si = si; } break; case FcTypeMatrix: @@ -1503,7 +1572,7 @@ FcValueListSerialize(FcValueList *pi) if (FcCharSetPtrU(v->u.ci)) { FcCharSetPtr ci = FcCharSetSerialize(FcCharSetPtrU(v->u.ci)); - if (!FcCharSetPtrU(v->u.ci)) + if (!FcCharSetPtrU(ci)) return FcValueListPtrCreateDynamic(pi); v->u.ci = ci; } @@ -1512,7 +1581,7 @@ FcValueListSerialize(FcValueList *pi) if (FcLangSetPtrU(v->u.li)) { FcLangSetPtr li = FcLangSetSerialize(FcLangSetPtrU(v->u.li)); - if (!FcLangSetPtrU(v->u.li)) + if (!FcLangSetPtrU(li)) return FcValueListPtrCreateDynamic(pi); v->u.li = li; } @@ -1523,13 +1592,41 @@ FcValueListSerialize(FcValueList *pi) return new; } +FcBool +FcValueListRead (int fd, FcCache metadata) +{ + fcvaluelists = mmap(NULL, + metadata.valuelist_length * sizeof (FcValueList), + PROT_READ, + MAP_SHARED, fd, metadata.valuelist_offset); + if (fcvaluelists == MAP_FAILED) + return FcFalse; + fcvaluelist_count = fcvaluelist_ptr = metadata.valuelist_length; + + return FcTrue; +} + +FcBool +FcValueListWrite (int fd, FcCache *metadata) +{ + metadata->valuelist_offset = FcCacheNextOffset(fd); + metadata->valuelist_length = fcvaluelist_ptr; + + if (fcvaluelist_ptr > 0) + { + lseek(fd, metadata->valuelist_offset, SEEK_SET); + return write(fd, fcvaluelists, + fcvaluelist_ptr * sizeof(FcValueList)) != -1; + } + return FcTrue; +} + FcValueList * FcValueListPtrU (FcValueListPtr pi) { switch (pi.storage) { case FcStorageStatic: - if (pi.u.stat == 0) return 0; return &fcvaluelists[pi.u.stat]; case FcStorageDynamic: return pi.u.dyn; @@ -1642,7 +1739,7 @@ FcObjectStaticName (const char *name) objectptr_alloc = s; } - size = sizeof (struct objectBucket) + strlen (name) + 1; + size = sizeof (struct objectBucket) + sizeof (char *); b = malloc (size); if (!b) return 0; @@ -1687,6 +1784,9 @@ FcObjectPtrDestroy (FcObjectPtr p) const char * FcObjectPtrU (FcObjectPtr si) { + if (si == 0) + return 0; + if (objectptr_indices[si] > 0) return &objectcontent_static_buf[objectptr_indices[si]]; else @@ -1750,7 +1850,7 @@ FcObjectRebuildStaticNameHashtable (void) /* Hmm. This will have a terrible effect on the memory size, * because the mmapped strings now get reallocated on the heap. * Is it all worth it? (Of course, the Serialization codepath is - * not problematic.) */ + * not problematic, because the program quits just afterwards.) */ static FcBool FcObjectPtrConvertToStatic(FcBool renumber) { @@ -1784,6 +1884,8 @@ FcObjectPtrConvertToStatic(FcBool renumber) new_indices = malloc (active_count * sizeof(int)); if (!new_indices) goto bail2; + new_indices[0] = 0; + new_static_buf[0] = 0; FcMemAlloc (FC_MEM_STATICSTR, new_static_bytes); FcMemFree (FC_MEM_STATICSTR, objectptr_count * sizeof (int)); @@ -1817,8 +1919,8 @@ FcObjectPtrConvertToStatic(FcBool renumber) int n = FcObjectStaticName(fixed_length_buf+i*(longest_string+1)); if (renumber) { - object_old_id_to_new[n] = i; - new_indices[i] = p-new_static_buf; + object_old_id_to_new[n] = i+1; + new_indices[i+1] = p-new_static_buf; } else new_indices[n] = p-new_static_buf; @@ -1907,21 +2009,11 @@ FcObjectClearStatic(void) object_old_id_to_new = 0; } -static FcObjectPtr -FcObjectSerialize (FcObjectPtr si) -{ - if (objectptr_first_serialization) - if (!FcObjectPtrConvertToStatic(FcTrue)) - return 0; - - return object_old_id_to_new[si]; -} - /* In the pre-serialization phase, mark the used strings with * -1 in the mapping array. */ /* The first call to the serialization phase assigns actual * static indices to the strings (sweep). */ -FcBool +static FcBool FcObjectPrepareSerialize (FcObjectPtr si) { if (object_old_id_to_new == 0) @@ -1942,6 +2034,93 @@ FcObjectPrepareSerialize (FcObjectPtr si) return FcFalse; } +static FcObjectPtr +FcObjectSerialize (FcObjectPtr si) +{ + if (objectptr_first_serialization) + if (!FcObjectPtrConvertToStatic(FcTrue)) + return 0; + + return object_old_id_to_new[si]; +} + +FcBool +FcObjectRead (int fd, FcCache metadata) +{ + /* do we have to merge strings? + * it's possible to merge dynamic strings, as long as we only store + * static strings to disk and as long as all static strings have lower + * ids than any dynamic strings. */ + + objectcontent_dynamic_count = 1; + objectcontent_dynamic_alloc = 0; + objectcontent_dynamic = 0; + objectcontent_dynamic_refcount = 0; + + /* well, we do need to allocate dynamic strings all the time, + * so this would just have to be converted. It takes 1.4k on + * my system. - PL */ +/* objectptr_indices = mmap(NULL, */ +/* metadata.object_length * sizeof (int), */ +/* PROT_READ, */ +/* MAP_SHARED, fd, metadata.object_offset); */ +/* if (objectptr_indices == MAP_FAILED) */ +/* goto bail; */ + + objectptr_count = metadata.object_length; + objectptr_alloc = metadata.object_length; + objectptr_indices = malloc (metadata.object_length * sizeof (int)); + if (!objectptr_indices) + goto bail; + FcMemAlloc (FC_MEM_STATICSTR, metadata.object_length * sizeof (int)); + lseek (fd, metadata.object_offset, SEEK_SET); + read (fd, objectptr_indices, metadata.object_length * sizeof (int)); + + objectcontent_static_buf = + mmap(NULL, + metadata.objectcontent_length * sizeof (char), + PROT_READ, + MAP_SHARED, fd, metadata.objectcontent_offset); + if (objectptr_indices == MAP_FAILED) + goto bail1; + objectcontent_static_bytes = metadata.objectcontent_length; + + FcObjectRebuildStaticNameHashtable (); + + return FcTrue; + + bail1: + /*munmap(objectptr_indices, metadata.object_length * sizeof(int));*/ + free (objectptr_indices); + bail: + return FcFalse; +} + +FcBool +FcObjectWrite (int fd, FcCache * metadata) +{ + /* there should be no dynamic strings: + * serialize ought to have zapped 'em. */ + if (objectcontent_dynamic_alloc) + return FcFalse; + + metadata->object_length = objectptr_count; + metadata->object_offset = FcCacheNextOffset(fd); + lseek(fd, metadata->object_offset, SEEK_SET); + if (write (fd, objectptr_indices, + metadata->object_length * sizeof (int)) == -1) + return FcFalse; + + metadata->objectcontent_length = objectcontent_static_bytes; + metadata->objectcontent_offset = FcCacheNextOffset(fd); + lseek(fd, metadata->objectcontent_offset, SEEK_SET); + if (write (fd, objectcontent_static_buf, + metadata->objectcontent_length * sizeof (char)) == -1) + return FcFalse; + + return FcTrue; +} + static void FcObjectStaticNameFini (void) { diff --git a/src/fcstr.c b/src/fcstr.c index 1391b65..dfa7697 100644 --- a/src/fcstr.c +++ b/src/fcstr.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "fcint.h" FcChar8 * @@ -1129,8 +1130,8 @@ FcStrSetSerialize (FcStrSet *set) if (strset_ptr > strset_count || strset_idx_ptr > strset_idx_count) return FcStrSetPtrCreateDynamic(0); - // problem with multiple ptrs to the same LangSet. - // should hash LangSets or something. + // problem with multiple ptrs to the same StrSet. + // should hash StrSets or something. // FcStrSetDestroy (set); return newp; @@ -1143,6 +1144,77 @@ FcStrSetSerialize (FcStrSet *set) return FcStrSetPtrCreateDynamic(0); } +FcBool +FcStrSetRead (int fd, FcCache metadata) +{ + strsets = mmap(NULL, + metadata.strsets_length * sizeof (FcStrSet), + PROT_READ, + MAP_SHARED, fd, metadata.strsets_offset); + if (strsets == MAP_FAILED) + goto bail; + strset_count = strset_ptr = metadata.strsets_length; + + strset_idx = mmap(NULL, + metadata.strsets_idx_length * sizeof (int), + PROT_READ, + MAP_SHARED, fd, metadata.strsets_idx_offset); + if (strset_idx == MAP_FAILED) + goto bail1; + strset_idx_count = strset_idx_ptr = metadata.strsets_length; + + strset_buf = mmap(NULL, + metadata.strset_buf_length * sizeof (char), + PROT_READ, + MAP_SHARED, fd, metadata.strset_buf_offset); + if (strset_buf == MAP_FAILED) + goto bail2; + strset_buf_count = strset_buf_ptr = metadata.strset_buf_length; + + return FcTrue; + + bail2: + munmap (strset_idx, metadata.strsets_idx_length * sizeof (int)); + bail1: + munmap (strsets, metadata.strsets_length * sizeof (FcStrSet)); + bail: + return FcFalse; +} + +FcBool +FcStrSetWrite (int fd, FcCache *metadata) +{ + metadata->strsets_length = strset_ptr; + metadata->strsets_offset = FcCacheNextOffset(fd); + if (strset_ptr > 0) + { + lseek (fd, metadata->strsets_offset, SEEK_SET); + if (write (fd, strsets, strset_ptr * sizeof(FcStrSet)) == -1) + return FcFalse; + } + + metadata->strsets_idx_length = strset_idx_ptr; + metadata->strsets_idx_offset = FcCacheNextOffset(fd); + if (strset_idx_ptr > 0) + { + lseek (fd, metadata->strsets_idx_offset, SEEK_SET); + if (write (fd, strset_idx, strset_idx_ptr * sizeof (int)) == -1) + return FcFalse; + } + + metadata->strset_buf_offset = FcCacheNextOffset(fd); + metadata->strset_buf_length = strset_buf_ptr; + if (strset_buf_ptr > 0) + { + lseek (fd, metadata->strset_buf_offset, SEEK_SET); + if (write (fd, strset_buf, + metadata->strset_buf_length * sizeof (char)) == -1) + return FcFalse; + } + + return FcTrue; +} + FcStrList * FcStrListCreate (FcStrSet *set) {