Commit 7ce19673 authored by Keith Packard's avatar Keith Packard
Browse files

Rework cache files to use offsets for all data structures.

Replace all of the bank/id pairs with simple offsets, recode several
data structures to always use offsets inside the library to avoid
conditional paths. Exposed data structures use pointers to hold offsets,
setting the low bit to distinguish between offset and pointer.

Use offset-based data structures for lang charset encodings; eliminates
separate data structure format for that file.

Much testing will be needed; offsets are likely not detected everywhere in
the library yet.
parent 2a9179d8
......@@ -31,4 +31,5 @@
@@@ name endian char char* int Pattern EltPtr Elt * Elt ObjPtr VLPtr Value Binding VL * CharSet Leaf** Char16 * Char16 Leaf Char32 Cache PageSize
x86 78563412_00000001_00000004_00000004_00000018_00000008_00000004_0000000c_00000004_00000008_0000000c_00000004_00000004_00000014_00000004_00000004_00000002_00000020_00000004_00000038_00001000
x86-64 78563412_00000001_00000008_00000004_00000020_00000010_00000008_00000018_00000004_00000010_00000010_00000004_00000008_00000020_00000008_00000008_00000002_00000020_00000004_00000040_00001000
ppc 12345678_00000001_00000004_00000004_00000018_00000008_00000004_0000000c_00000004_00000008_00000010_00000004_00000004_00000014_00000004_00000004_00000002_00000020_00000004_00000038_00001000
ppc-4k 12345678_00000001_00000004_00000004_00000018_00000008_00000004_0000000c_00000004_00000008_00000010_00000004_00000004_00000014_00000004_00000004_00000002_00000020_00000004_00000038_00001000
ppc-64k 12345678_00000001_00000004_00000004_00000018_00000008_00000004_0000000c_00000004_00000008_00000010_00000004_00000004_00000014_00000004_00000004_00000002_00000020_00000004_00000038_00010000
......@@ -37,10 +37,6 @@
* functions are also needed in slightly modified form
*/
const FcChar16 langBankNumbers[1]; /* place holders so that externs resolve */
const FcCharLeaf langBankLeaves[1];
const int langBankLeafIdx[1];
void
FcMemAlloc (int kind, int size)
{
......@@ -51,18 +47,6 @@ FcMemFree (int kind, int size)
{
}
int* _fcBankId = 0;
int* _fcBankIdx = 0;
FcValueList ** _fcValueLists = 0;
FcPatternElt ** _fcPatternElts = 0;
int FcDebugVal = 0;
int
FcCacheBankToIndexMTF (int bank)
{
return -1;
}
FcChar8 *
FcConfigHome (void)
{
......@@ -239,19 +223,18 @@ main (int argc, char **argv)
static char *files[MAX_LANG];
static FcCharSet *sets[MAX_LANG];
static int duplicate[MAX_LANG];
static int offsets[MAX_LANG];
static int country[MAX_LANG];
static char *names[MAX_LANG];
static char *langs[MAX_LANG];
static int off[MAX_LANG];
FILE *f;
int offset = 0;
int ncountry = 0;
int i = 0;
int nsets = 0;
int argi;
FcCharLeaf **leaves;
int total_leaves = 0;
int offset_count = 0;
int l, sl, tl;
int l, sl, tl, tn;
static char line[1024];
static FcChar32 map[MAX_LANG_SET_MAP];
int num_lang_set_map;
......@@ -290,6 +273,7 @@ main (int argc, char **argv)
i++;
fclose (f);
}
nsets = i;
sets[i] = 0;
leaves = malloc (total_leaves * sizeof (FcCharLeaf *));
tl = 0;
......@@ -301,10 +285,10 @@ main (int argc, char **argv)
for (sl = 0; sl < sets[i]->num; sl++)
{
for (l = 0; l < tl; l++)
if (leaves[l] == FcCharSetGetLeaf(sets[i], sl))
if (leaves[l] == FcCharSetLeaf(sets[i], sl))
break;
if (l == tl)
leaves[tl++] = FcCharSetGetLeaf(sets[i], sl);
leaves[tl++] = FcCharSetLeaf(sets[i], sl);
}
}
......@@ -321,22 +305,6 @@ main (int argc, char **argv)
printf ("/* total size: %d unique leaves: %d */\n\n",
total_leaves, tl);
/*
* Dump leaves
*/
printf ("const FcCharLeaf langBankLeaves[%d] = {\n", tl);
for (l = 0; l < tl; l++)
{
printf (" { { /* %d */", l);
for (i = 0; i < 256/32; i++)
{
if (i % 4 == 0)
printf ("\n ");
printf (" 0x%08x,", leaves[l]->map[i]);
}
printf ("\n } },\n");
}
printf ("};\n\n");
/*
* Find duplicate charsets
......@@ -355,111 +323,121 @@ main (int argc, char **argv)
}
}
tn = 0;
for (i = 0; sets[i]; i++) {
if (duplicate[i] >= 0)
continue;
off[i] = tn;
tn += sets[i]->num;
}
printf ("#define LEAF0 (%d * sizeof (FcLangCharSet))\n", nsets);
printf ("#define OFF0 (LEAF0 + %d * sizeof (FcCharLeaf))\n", tl);
printf ("#define NUM0 (OFF0 + %d * sizeof (intptr_t))\n", tn);
printf ("#define SET(n) (n * sizeof (FcLangCharSet) + offsetof (FcLangCharSet, charset))\n");
printf ("#define OFF(s,o) (OFF0 + o * sizeof (intptr_t) - SET(s))\n");
printf ("#define NUM(s,n) (NUM0 + n * sizeof (FcChar16) - SET(s))\n");
printf ("#define LEAF(o,l) (LEAF0 + l * sizeof (FcCharLeaf) - (OFF0 + o * sizeof (intptr_t)))\n");
printf ("#define fcLangCharSets (fcLangData.langCharSets)\n");
printf ("\n");
printf ("static const struct {\n"
" FcLangCharSet langCharSets[%d];\n"
" FcCharLeaf leaves[%d];\n"
" intptr_t leaf_offsets[%d];\n"
" FcChar16 numbers[%d];\n"
"} fcLangData = {\n",
nsets, tl, tn, tn);
/*
* Find ranges for each letter for faster searching
* Dump sets
*/
setRangeChar = 'a';
printf ("{\n");
for (i = 0; sets[i]; i++)
{
char c = names[i][0];
while (setRangeChar <= c && c <= 'z')
setRangeStart[setRangeChar++ - 'a'] = i;
int j = duplicate[i];
if (j < 0)
j = i;
printf (" { (FcChar8 *) \"%s\", "
" { FC_REF_CONSTANT, %d, OFF(%d,%d), NUM(%d,%d) } }, /* %d */\n",
langs[i],
sets[j]->num, i, off[j], i, off[j], i);
}
for (setRangeChar = 'a'; setRangeChar < 'z'; setRangeChar++)
setRangeEnd[setRangeChar - 'a'] = setRangeStart[setRangeChar+1-'a'] - 1;
setRangeEnd[setRangeChar - 'a'] = i - 1;
printf ("},\n");
/*
* Dump arrays
* Dump leaves
*/
for (i = 0; sets[i]; i++)
printf ("{\n");
for (l = 0; l < tl; l++)
{
int n;
if (duplicate[i] >= 0)
continue;
for (n = 0; n < sets[i]->num; n++)
printf (" { { /* %d */", l);
for (i = 0; i < 256/32; i++)
{
for (l = 0; l < tl; l++)
if (leaves[l] == FcCharSetGetLeaf(sets[i], n))
break;
if (l == tl)
fatal (names[i], 0, "can't find leaf");
offset_count++;
if (i % 4 == 0)
printf ("\n ");
printf (" 0x%08x,", leaves[l]->map[i]);
}
offsets[i] = offset;
offset += sets[i]->num;
printf ("\n } },\n");
}
printf ("},\n");
printf ("const int langBankLeafIdx[%d] = {\n",
offset_count);
/*
* Dump leaves
*/
printf ("{\n");
for (i = 0; sets[i]; i++)
{
int n;
if (duplicate[i] >= 0)
continue;
printf (" /* %s */\n", names[i]);
for (n = 0; n < sets[i]->num; n++)
{
if (n % 8 == 0)
if (n % 4 == 0)
printf (" ");
for (l = 0; l < tl; l++)
if (leaves[l] == FcCharSetGetLeaf(sets[i], n))
if (leaves[l] == FcCharSetLeaf(sets[i], n))
break;
if (l == tl)
fatal (names[i], 0, "can't find leaf");
printf (" %3d,", l);
if (n % 8 == 7)
printf (" LEAF(%3d,%3d),", off[i], l);
if (n % 4 == 3)
printf ("\n");
}
if (n % 8 != 0)
if (n % 4 != 0)
printf ("\n");
}
printf ("};\n\n");
printf ("const FcChar16 langBankNumbers[%d] = {\n",
offset_count);
printf ("},\n");
printf ("{\n");
for (i = 0; sets[i]; i++)
{
int n;
if (duplicate[i] >= 0)
continue;
printf (" /* %s */\n", names[i]);
for (n = 0; n < sets[i]->num; n++)
{
if (n % 8 == 0)
printf (" ");
printf (" 0x%04x,", FcCharSetGetNumbers(sets[i])[n]);
printf (" 0x%04x,", FcCharSetNumbers (sets[i])[n]);
if (n % 8 == 7)
printf ("\n");
}
if (n % 8 != 0)
printf ("\n");
}
printf ("};\n\n");
printf ("}\n");
/*
* Dump sets
*/
printf ("const FcLangCharSet fcLangCharSets[] = {\n");
for (i = 0; sets[i]; i++)
{
int j = duplicate[i];
if (j < 0)
j = i;
printf (" { (FcChar8 *) \"%s\",\n"
" { FC_REF_CONSTANT, %d, FC_BANK_LANGS, "
"{ { %d, %d } } } }, /* %d */\n",
langs[i],
sets[j]->num, offsets[j], offsets[j], j);
}
printf ("};\n\n");
printf ("#define NUM_LANG_CHAR_SET %d\n", i);
num_lang_set_map = (i + 31) / 32;
printf ("#define NUM_LANG_SET_MAP %d\n", num_lang_set_map);
......@@ -506,6 +484,23 @@ main (int argc, char **argv)
}
/*
* Find ranges for each letter for faster searching
*/
setRangeChar = 'a';
memset(setRangeStart, '\0', sizeof (setRangeStart));
memset(setRangeEnd, '\0', sizeof (setRangeEnd));
for (i = 0; sets[i]; i++)
{
char c = names[i][0];
while (setRangeChar <= c && c <= 'z')
setRangeStart[setRangeChar++ - 'a'] = i;
}
for (setRangeChar = 'a'; setRangeChar < 'z'; setRangeChar++)
setRangeEnd[setRangeChar - 'a'] = setRangeStart[setRangeChar+1-'a'] - 1;
setRangeEnd[setRangeChar - 'a'] = i - 1;
/*
* Dump sets start/finish for the fastpath
*/
......
......@@ -212,17 +212,14 @@ typedef struct _FcValue {
FcType type;
union {
const FcChar8 *s;
int s_off;
int i;
FcBool b;
double d;
const FcMatrix *m;
const FcCharSet *c;
int c_off;
void *f;
const FcPattern *p;
const FcLangSet *l;
int l_off; /* this is a difference of char *s */
} u;
} FcValue;
......
......@@ -95,6 +95,7 @@ libfontconfig_la_SOURCES = \
fcmatrix.c \
fcname.c \
fcpat.c \
fcserialize.c \
fcstr.c \
fcxml.c \
ftglue.h \
......
/*
* $RCSId: xc/lib/fontconfig/src/fccache.c,v 1.12 2002/08/22 07:36:44 keithp Exp $
*
* Copyright © 2000 Keith Packard
* Copyright © 2005 Patrick Lam
*
......@@ -37,29 +35,12 @@
# include <windows.h>
#endif
#define ENDIAN_TEST 0x12345678
#define MACHINE_SIGNATURE_SIZE (9 + 5*20 + 1)
/* for when we don't have sysconf: */
#define FC_HARDCODED_PAGESIZE 8192
#ifndef O_BINARY
#define O_BINARY 0
#endif
static FILE *
FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, FcChar8 **cache_path);
static void *
FcDirCacheProduce (FcFontSet *set, FcCache * metadata);
static off_t
FcCacheNextOffset(off_t w);
static FcBool
FcCacheHaveBank (int bank);
static void
FcCacheAddBankDir (int bank, const char * dir);
static int
FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, off_t *size);
struct MD5Context {
FcChar32 buf[4];
......@@ -74,67 +55,17 @@ static void MD5Transform(FcChar32 buf[4], FcChar32 in[16]);
#define FC_DBG_CACHE_REF 1024
static char *
FcCacheReadString (FILE *file, char *dest, int len)
{
int c;
char *d = dest;
if (len == 0)
return 0;
while ((c = getc (file)) != EOF && len > 0) {
*d++ = c;
if (c == '\0')
return dest;
len--;
}
return 0;
}
static FcBool
FcCacheWriteString (int fd, const char *chars)
{
if (write (fd, chars, strlen(chars)+1) != strlen(chars)+1)
return FcFalse;
return FcTrue;
}
/*
* Find the next presumably-mmapable offset after the supplied file
* position.
*/
static off_t
FcCacheNextOffset(off_t w)
{
static long pagesize = -1;
if (w == -1)
return w;
if (pagesize == -1)
#if defined (HAVE_SYSCONF)
pagesize = sysconf(_SC_PAGESIZE);
#else
pagesize = FC_HARDCODED_PAGESIZE;
#endif
if (w % pagesize == 0)
return w;
else
return ((w / pagesize)+1)*pagesize;
}
/* Does not check that the cache has the appropriate arch section. */
FcBool
FcDirCacheValid (const FcChar8 *dir, FcConfig *config)
{
FILE *file;
int fd;
file = FcDirCacheOpen (config, dir, NULL);
fd = FcDirCacheOpen (config, dir, NULL);
if (file == NULL)
if (fd < 0)
return FcFalse;
fclose (file);
close (fd);
return FcTrue;
}
......@@ -282,218 +213,281 @@ FcCacheRead (FcConfig *config)
* This searches the list of cache dirs for the relevant cache file,
* returning the first one found.
*/
static FILE *
FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, FcChar8 **cache_path)
static int
FcDirCacheOpen (FcConfig *config, const FcChar8 *dir, off_t *size)
{
FILE *file = NULL;
FcChar8 *cache_hashed = NULL;
int fd = -1;
FcChar8 cache_base[CACHEBASE_LEN];
FcStrList *list;
FcChar8 *cache_dir;
struct stat file_stat, dir_stat;
if (stat ((char *) dir, &dir_stat) < 0)
return NULL;
return -1;
FcDirCacheBasename (dir, cache_base);
list = FcStrListCreate (config->cacheDirs);
if (!list)
return NULL;
return -1;
while ((cache_dir = FcStrListNext (list)))
{
cache_hashed = FcStrPlus (cache_dir, cache_base);
FcChar8 *cache_hashed = FcStrPlus (cache_dir, cache_base);
if (!cache_hashed)
break;
file = fopen((char *) cache_hashed, "rb");
if (file != NULL) {
if (fstat (fileno (file), &file_stat) >= 0 &&
fd = open((char *) cache_hashed, O_RDONLY | O_BINARY);
FcStrFree (cache_hashed);
if (fd >= 0) {
if (fstat (fd, &file_stat) >= 0 &&
dir_stat.st_mtime <= file_stat.st_mtime)
{
if (size)
*size = file_stat.st_size;
break;
}
fclose (file);
file = NULL;
close (fd);
fd = -1;
}
FcStrFree (cache_hashed);
cache_hashed = NULL;
}
FcStrListDone (list);
if (file == NULL)
return NULL;
if (cache_path)
*cache_path = cache_hashed;
else
FcStrFree (cache_hashed);
return fd;
}
return file;
#if 0
static void
FcDirCacheUnmap (FcCache *cache)
{
if (cache->magic == FC_CACHE_MAGIC_COPY)
{
free (cache);
return;
}
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
munmap (cache, cache->size);
#elif defined(_WIN32)
UnmapViewOfFile (cache);
#endif
}
#endif
/* read serialized state from the cache file */
FcBool
FcDirCacheConsume (FILE *file, FcFontSet *set, FcStrSet *dirs,
const FcChar8 *dir, char *dirname)
static FcCache *
FcDirCacheMap (int fd, off_t size)
{
FcCache metadata;
void *current_dir_block;
char subdir_name[FC_MAX_FILE_LEN + 1 + 12 + 1];
int i;
if (fread(&metadata, sizeof(FcCache), 1, file) != 1)
goto bail;
if (metadata.magic != FC_CACHE_MAGIC)
goto bail;
/* skip directory name; it's just for fc-cat */
if (!FcCacheReadString (file, subdir_name, sizeof (subdir_name)))
goto bail;
if (dirname)
strcpy (dirname, subdir_name);
FcCache *cache;
FcBool allocated = FcFalse;
for (i = 0; i < metadata.subdirs; i++) {
if (!FcCacheReadString (file, subdir_name, sizeof (subdir_name)))
goto bail;
FcStrSetAdd (dirs, (FcChar8 *)subdir_name);
}
if (metadata.count)
{
int fd = fileno (file);
if (size < sizeof (FcCache))
return NULL;
#if defined(HAVE_MMAP) || defined(__CYGWIN__)
current_dir_block = mmap (0, metadata.count,
PROT_READ, MAP_SHARED, fd, metadata.pos);
if (current_dir_block == MAP_FAILED)
goto bail;
cache = mmap (0, size, PROT_READ, MAP_SHARED, fd, 0);
#elif defined(_WIN32)
{
HANDLE hFileMap;
hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL, PAGE_READONLY, 0, 0, NULL);
if (hFileMap == NULL)
goto bail;
{
HANDLE hFileMap;
current_dir_block = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, metadata.pos, metadata.count);
if (current_dir_block == NULL)
{
CloseHandle (hFileMap);
goto bail;
}
cache = NULL;
hFileMap = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
PAGE_READONLY, 0, 0, NULL);
if (hFileMap != NULL)
{
cache = MapViewOfFile (hFileMap, FILE_MAP_READ, 0, 0, size);
CloseHandle (hFileMap);
}
#else
if (lseek (fd, metatdata.pos, SEEK_SET) == -1)
goto bail;
current_dir_block = malloc (metadata.count);
if (!current_dir_block)
goto bail;
}
#endif
if (!cache)
{
cache = malloc (size);
if (!cache)
return NULL;
/* could also use CreateMappedViewOfFile under MinGW... */
if (read (fd, current_dir_block, metadata.count) != metadata.count)
if (read (fd, cache, size) != size)
{
free (current_dir_block);
goto bail;
free (cache);
return NULL;
}
allocated = FcTrue;
}
if (cache->magic != FC_CACHE_MAGIC ||
cache->size != size)